Architecture
OCMLabs_Faq follows standard Magento 2 patterns throughout. This page is the developer reference for what is inside the module and where each piece lives.
Package metadata
Section titled “Package metadata”- Package:
ocmlabs/module-faq - Module name:
OCMLabs_Faq - Current version: 1.0.5
- Requires: PHP 8.3+, Magento 2.4.6 to 2.4.8 (framework
>=103.0.6 <103.0.9, catalog, backend, ui modules) - Editions: Magento Open Source and Adobe Commerce (Adobe Commerce via the
ocmlabs/module-faq-commercemetapackage) - Accessibility: WCAG 2.1 Level AA conformant storefront accordion
What it does
Section titled “What it does”OCMLabs_Faq adds a product FAQ system to Magento 2. Admins create FAQ entries - a question, an answer, and one or more associated products - and those FAQs appear in an accordion tab on each associated product detail page. Each FAQ also emits a JSON-LD FAQPage schema block, which makes the questions eligible for Google’s rich result FAQ display in search.
A single FAQ can be assigned to multiple products. A product can have multiple FAQs, displayed in a configurable sort order.
Database
Section titled “Database”Two tables manage FAQ data:
ocmlabs_faq - stores FAQ records: question, answer, sort order, active flag, and timestamps.
ocmlabs_faq_product - a junction table linking FAQs to products (faq_id, product_id). Enforces a unique constraint on the pair and carries cascade deletes on both sides. This is what enables the many-to-many relationship.
Data layer
Section titled “Data layer”The module follows Magento’s standard repository pattern:
Api/Data/FaqInterfacedefines the data contract: entity ID, product IDs array, question, answer, sort order, is_active, and timestamps.Model/Faqimplements the interface viaAbstractModel.Model/FaqRepositoryimplementsFaqRepositoryInterfacewith standardgetById,save,delete, andgetList(SearchCriteria) methods.Model/ResourceModel/Faqhandles the product relationship in_afterLoad(reads product IDs from the junction table) and_afterSave(delete-then-insert pattern to sync product links on every save).Model/ResourceModel/Grid/Collectionpowers the admin grid with a LEFT JOIN + GROUP_CONCAT producing a computedproduct_skuscolumn. Supports cross-table SKU filtering.
Admin backend
Section titled “Admin backend”The admin interface lives under Catalog > Product FAQs (sortOrder 50) and provides:
- Grid listing (
ocmlabs_faq_listing) - all FAQ records with columns for question, product SKUs, sort order, and status. Supports search and mass delete. - Create / Edit form (
ocmlabs_faq_form) - fields for question, answer, sort order, active toggle, and an Associated Products section with a searchable product grid. - System configuration (
etc/adminhtml/system.xml) - store-view-scoped settings for the FAQ heading title, tab title, heading visibility, and tab visibility under Stores > Configuration > OCMLabs > Product FAQs. - Save controller - reads product IDs from the
faq_productsJSON payload submitted by the product grid and persists them to the junction table. - DataProvider (
FaqFormDataProvider) - loads FAQ fields for the edit form. Product associations are pre-populated in the product grid viaBlock/Adminhtml/Faq/AssignProducts. - AssignProducts block (
Block/Adminhtml/Faq/AssignProducts.php) +Block/Adminhtml/Faq/Tab/Product.php- renders the searchable product grid in the form, pre-selecting currently assigned products. - ACL - single permission resource
OCMLabs_Faq::manageunderMagento_Backend::content. Controls access to the entire admin section.
Controllers
Section titled “Controllers”| Controller | Route | Purpose |
|---|---|---|
Index | ocmlabs_faq/faq/index | Grid listing |
Edit | ocmlabs_faq/faq/edit | Edit form |
NewAction | ocmlabs_faq/faq/new | New FAQ form |
Save | ocmlabs_faq/faq/save | POST save handler |
Delete | ocmlabs_faq/faq/delete | Single record delete |
MassDelete | ocmlabs_faq/faq/massDelete | Bulk delete from grid |
Frontend
Section titled “Frontend”Block/Product/FaqTab loads active FAQs for the current product, sorted by sort_order ascending. The block renders nothing if no active FAQs exist for the product, or if the FAQ tab is disabled in store configuration, so no empty tab or section appears.
The FAQ tab is injected into the product detail page via catalog_product_view.xml at sort_order="20", placing it early in the tab list. Its visible tab label is resolved from store configuration at render time.
Accordion template (faq-tab.phtml)
Section titled “Accordion template (faq-tab.phtml)”Renders a <section> with an accessible accordion following the WAI-ARIA APG Accordion Pattern. The section heading is store-configurable and can be hidden independently from the tab label. Each FAQ item is a native <button> wrapped in <h3> (so headings-list navigation jumps between FAQs), carrying aria-expanded and aria-controls. The corresponding answer panel has role="region" and aria-labelledby pointing back at the question button id, giving assistive tech a clear question-to-region relationship. The first item is expanded by default. A chevron SVG icon rotates on toggle. Behaviour is driven by a RequireJS component (faqAccordion) following Magento’s standard data-mage-init pattern. All DOM ids in the rendered markup are scoped to the block’s layout name, so multiple accordion instances on a single page cannot collide.
See Accessibility for the WCAG 2.1 Level AA audit details.
Schema template (faq_schema.phtml)
Section titled “Schema template (faq_schema.phtml)”Injects a <script type="application/ld+json"> block with @type: FAQPage structured data. Questions and answers are strip-tagged before output. The block is skipped entirely if no FAQ data is present, or if the FAQ tab is disabled for the current store view.
See SEO (JSON-LD) for the on-page behaviour and Google eligibility rules.
Scope and limitations
Section titled “Scope and limitations”- No REST or GraphQL API. No
webapi.xmlis included. FAQ data is not exposed via Magento’s API layer. - Store-scoped display configuration.
system.xmlprovides store-view overrides for FAQ heading text, tab text, heading visibility, and tab visibility. Clearing the tab title falls back to the layout-default “FAQs” label so the product tab control always has an accessible name. - No plugins or observers. The module adds no extension points and hooks into no external events.
- Admin-only CRUD. FAQ management is entirely through the Magento admin panel.
- WYSIWYG answers. The answer field uses a WYSIWYG editor with a restricted toolbar in the admin. Output is rendered as raw HTML - trusted as admin-authored content gated behind
OCMLabs_Faq::manage. The schema template strips all tags before including answers in JSON-LD output.
Packaging
Section titled “Packaging”The module is distributed as two Composer packages from a single repository:
| Package | Type | Purpose |
|---|---|---|
ocmlabs/module-faq | magento2-module | The module itself. Installs on Magento Open Source and Adobe Commerce. |
ocmlabs/module-faq-commerce | metapackage | Adobe Commerce licensing gate. Requires ocmlabs/module-faq plus magento/product-enterprise-edition. |
The community package gates Magento versions via magento/framework (present in all install methods including GitHub clones) and holds conflict rules against both edition metapackages at >=2.4.9. Both packages are version-locked - ocmlabs/module-faq-commerce requires ocmlabs/module-faq: ^1.0 and ships the matching tag.