EMN FAQ & Accordion Block

Plugin Banner

EMN FAQ & Accordion Block

by engelhardtmedien

Download
Description

Developed by Engelhardt Medien, a digital webdesign and graphics agency based in Nuremberg, Germany.

Why this plugin?

  • Schema.org FAQPage JSON-LD is generated automatically and tied directly to the block’s mode — no separate schema plugin needed. This structured markup helps AI systems and assistants (ChatGPT, Perplexity, Gemini, and others) understand and surface your content, and gives search engines clean, standards-based context about your page — increasingly important as more traffic is driven by AI-powered search and answers. (Note: Google discontinued its visual FAQ rich-result snippet in Google Search in May 2026; the underlying structured data is still valid, standard, and used elsewhere, e.g. by AI assistants.)
  • FAQ and Accordion mode are switchable independently per block instance.
  • Fast and lightweight — no external libraries, and assets only load on pages that actually contain the block.
  • Fully accessible, matching WCAG 2.1 Level AA for this interaction pattern — particularly relevant for websites operating in the European Union, where the European Accessibility Act has required many businesses to meet digital accessibility standards since June 2025.
  • WPML-compatible; translation-ready with translations delivered via translate.wordpress.org.
  • Works with your active theme’s own color palette and gradient presets.
  • Freely customizable — every visual aspect can be adjusted in the block editor sidebar, without touching any code.

EMN FAQ & Accordion Block adds a native Gutenberg block for building expandable question/answer sections. It works in two modes, switchable per block instance (Accordion mode is the default for new blocks):

  • Accordion mode (default) – the same expandable UI without structured data, for general-purpose content (services, features, steps, etc.).
  • FAQ mode – automatically outputs valid Schema.org FAQPage JSON-LD structured data alongside the visible content. This structured data helps AI systems and assistants (such as ChatGPT, Perplexity, and Gemini) understand and surface your content when answering questions related to it, and provides search engines with clean, standards-based context about the page (note: Google discontinued the visual FAQ rich-result snippet in Google Search in May 2026).

By default, opening one item automatically closes any other open item in the same block — this can be turned off per block (under the “Type” panel) to allow multiple items to stay open at once. The first item can also be set to already be expanded when the page loads, again on a per-block basis (also in the “Type” panel).

Want to point someone straight to one specific question instead of making them scroll through the whole list? Give that question a short link name (the “HTML anchor” field, under “Advanced” in its block settings), and the plugin immediately shows you the finished, ready-to-share link right underneath. Anyone who opens that link arrives with exactly that question already expanded and scrolled into view — handy for emails, chat support, or linking from another page straight to the answer.

Design controls

Every visual aspect can be adjusted directly in the block editor sidebar, without touching any code:

  • Solid color or two-stop gradient backgrounds for both the question and the answer, including separate hover colors/gradients.
  • Border color, hover border color, border width, and border radius.
  • Independent top/right/bottom/left padding for both the question and the answer, and independent top/right/bottom/left icon padding — using WordPress’s own native “Dimensions” spacing control (including your theme’s own spacing presets, if defined), with the same unit choices as WordPress itself (px, %, em, rem, vw, vh).
  • One shared border color and width for all four sides. Border radius can be set per corner (using WordPress’s own native corner-radius control) or all at once.
  • All of the above native WordPress controls automatically and invisibly fall back to this plugin’s own equivalent, simpler control if a given native component isn’t available on a specific WordPress version.
  • Padding and border settings each have a compact “⋮” reset-to-default menu.
  • Normal/hover color pairs (question background, question text, icon color, icon background) are grouped into a compact two-way switch instead of being listed one below the other.
  • Choice of icon: plus/minus, chevron, or arrow — freely selectable per block (the chevron and arrow rotate when an item is opened; the plus turns into a minus).
  • Icon color, icon background color (with separate hover colors), icon size, icon background radius, icon padding, and the spacing between the icon and the question text.
  • Icon position: left (default) or right of the question text.
  • Choice of HTML element for the question (div, p, or h2–h6), so it can match your document heading structure — with an optional custom font size override, set independently for desktop, tablet, and mobile (any breakpoint left empty automatically falls back to the next larger breakpoint, and ultimately to your theme’s own default size for that element).
  • Any color or gradient field can also use your active theme’s own color palette (e.g. Astra, or any theme that registers editor-color-palette / editor-gradient-presets), exactly like core WordPress blocks.
  • The answer area accepts any block available in your WordPress installation — not just text: paragraphs, lists, images, headings, quotes, tables, galleries, columns, buttons, embeds, and any block added by other plugins/addons.

Lightweight & fast

Built with no external libraries or frameworks: a small, dependency-free editor script and a compact vanilla-JS frontend script. Nothing is loaded on pages that don’t contain the block, and all output is plain HTML/CSS — no heavy runtime, no bloat, and virtually no impact on page load time. All CSS and JavaScript ships pre-minified and is served minified by default, keeping the amount of data sent to visitors as small as possible (the original, readable source files are also included for transparency and are used automatically instead when SCRIPT_DEBUG is enabled).

Images, iframes (e.g. video embeds), and self-hosted videos placed inside a collapsed answer are automatically served with native lazy-loading attributes (loading="lazy" / preload="none") as a reliable fallback, on top of WordPress core’s own automatic lazy-loading — so media inside FAQ/accordion items that aren’t visible on load don’t block the page. Existing loading/decoding/preload attributes (yours or another plugin’s) are always left untouched. Media inside an item that is set to be open by default is deliberately excluded, so it loads immediately like any other above-the-fold content.

Accessibility

The expand/collapse interaction is built to be fully keyboard-operable and screen-reader-friendly, in line with WCAG 2.1 Level AA for this type of disclosure widget:

  • Each question is reachable via Tab and operable with Enter or Space, in addition to mouse/touch.
  • Correct ARIA semantics are used throughout: role="button" and aria-expanded on the question, aria-controls linking it to its answer, and role="region" with aria-hidden and aria-labelledby (pointing back to its own question) on the answer — all written directly into the server-rendered HTML, not added as an afterthought by JavaScript.
  • Decorative icons (plus/minus, chevron, arrow) are hidden from assistive technology via aria-hidden, since the open/closed state is already announced through aria-expanded.
  • A visible focus indicator is shown for keyboard users.
  • If an item is set to be open by default, it is rendered already expanded (correct aria-expanded/aria-hidden state and focusable content) directly in the initial HTML — no reliance on JavaScript running first.

No plugin can honestly certify a page as “100% accessible” on its own, since real-world accessibility also depends on the content and colors you choose. What this plugin guarantees on its own is the interaction pattern itself: correct roles/states, full keyboard operability, a visible focus indicator, and screen-reader-friendly markup, matching WCAG 2.1 Level AA for this type of disclosure widget. Final color contrast (text against background, icon against its background) depends on the colors you choose in the block settings — pick sufficiently contrasting colors (a ratio of at least 4.5:1 for normal text) to keep the result compliant with WCAG AA.

Security

All styling attributes are re-validated and rebuilt on the server on every page load — via strict allow-lists for colors, gradients, numeric ranges, and HTML tags — regardless of what is stored in the post content. This prevents malicious or malformed attribute values from ever reaching the page’s HTML or CSS.

Multilingual

  • The plugin’s source strings are in German; fully translation-ready, with translations delivered automatically per-locale via translate.wordpress.org once contributed there — no bundled .po/.mo files, in line with how WordPress.org-hosted plugins handle translations.
  • Includes a wpml-config.xml for WPML compatibility, so only the question text itself is offered for translation — all styling attributes are copied as-is across languages.
  1. Upload the emn-faq-accordion-block folder to the /wp-content/plugins/ directory, or install the plugin directly through the “Plugins Add New” screen in WordPress.
  2. Activate the plugin through the “Plugins” screen in WordPress.
  3. Edit any post or page, add the “FAQ / Accordion” block, choose FAQ or Accordion mode, and add one or more accordion items underneath it.
  4. Adjust colors, icon, spacing, and other options in the block settings sidebar on the right.

Updating from the old plugin

If you previously used the earlier “Custom FAQ Block” plugin, note that this is a separate plugin (different folder/slug), so installing and activating this one does not automatically deactivate the old one — both would otherwise run side by side. Please deactivate (and, once you’ve confirmed everything looks right, delete) the old “Custom FAQ Block” plugin after activating this one; having both active at the same time can cause each plugin’s own frontend script to load together, which stops the accordions from expanding. This plugin will show a notice in the WordPress admin for as long as it detects the old plugin is still active. Content you already published continues to display correctly either way.

  1. The FAQ/Accordion block in the editor.

    The FAQ/Accordion block in the editor.

  2. The custom styled plugin in Accordion mode in the frontend.

    The custom styled plugin in Accordion mode in the frontend.

Does this plugin add any FAQ schema markup automatically?

Yes, but only when a block is set to “FAQ” mode. In that mode, the plugin outputs a Schema.org FAQPage JSON-LD block based on the actual questions and answers in that block. Blocks set to “Accordion” mode do not output this schema.

Will my existing accordions break if I update the plugin?

No. Every markup shape produced by earlier versions of this plugin is explicitly supported through WordPress’s block deprecation system, and legacy attributes (such as the old single “padding” value) are automatically mapped to their modern equivalents at render time.

Can I use my theme’s own color palette in the color pickers?

Yes. If your active theme registers a color palette and/or gradient presets (via add_theme_support( 'editor-color-palette' ) / add_theme_support( 'editor-gradient-presets' )), those colors and gradients are automatically offered in every color/gradient field of this block, in addition to a fully custom color/gradient picker.

Is this plugin compatible with WPML?

Yes, a wpml-config.xml is included that marks the question text as translatable while keeping all styling attributes identical across every language.

Which blocks can I use inside the answer?

Any block registered in your WordPress installation. There is no restriction to a fixed list — this includes every core block (paragraph, list, image, heading, quote, table, gallery, columns, buttons, embeds, and more) as well as blocks added by other plugins or page-builder addons.

Can I send someone a link straight to one specific question?

Yes. Click the question in the editor, open “Advanced” in the sidebar, and give it a short name in the “HTML anchor” field (e.g. “shipping-costs”). The plugin then shows you the finished link to copy right underneath — just share that. Anyone who opens it lands on the page with exactly that question already open and scrolled into view, no searching required.

Can multiple items be open at the same time?

By default, no — opening an item automatically closes any other open item in the same block. This can be turned off per block via the “Automatically close other items” toggle in the Type panel, allowing several items to stay open simultaneously.

Can the first item be open by default when the page loads?

Yes, via the “First item open on load” toggle in the Type panel (right above “Automatically close other items”), on a per-block basis. It’s off by default, so existing content keeps its previous, fully collapsed starting state after updating.

Is this plugin accessible?

Yes. Every question is keyboard-operable (Tab, Enter, Space) and carries the correct ARIA roles and states (role="button", aria-expanded, aria-controls, role="region", aria-hidden, aria-labelledby) rendered directly into the HTML, matching WCAG 2.1 Level AA for this interaction pattern. Decorative icons are hidden from screen readers. Since colors are fully customizable, make sure the text/background/icon colors you choose provide sufficient contrast (at least 4.5:1 for normal text) to stay compliant. As with any plugin, “accessible” ultimately also depends on the content you put inside it (meaningful link text, alt text on images, a sensible heading structure) — this plugin covers the interaction pattern itself, not the content you add.

Are images and videos inside the answers lazy-loaded?

Yes. WordPress core already adds native lazy-loading to images and iframes automatically on most pages (since WordPress 5.5/5.7). This plugin adds its own fallback on top of that — applied directly when the block is rendered, so it also works in contexts where WordPress’s own content filter doesn’t run (e.g. block-theme template parts, widgets, or page builders that render the block directly). Any loading, decoding, or preload attribute you or another plugin already set is never overwritten, and media inside an item that’s set to be open by default is left to load immediately, exactly like other above-the-fold content.

Does the block check my FAQ content for common mistakes?

Yes. Whenever a block is set to “FAQ” mode, a “FAQ-Prüfung” (“FAQ check”) panel appears in the sidebar and flags, purely as an editorial aid: questions without text, questions without an answer, duplicate/very similar questions, an accordion/FAQ block nested inside an answer (not supported in the FAQ schema), and unusually short answers (under 40 characters — our own practical guideline, not an official Google requirement). This check is informational only and never blocks saving or publishing.

Note: this section covers the most recent releases only (WordPress.org limits this section to 5000 characters). For the full version history back to 3.0, see: https://engelhardt-medien.de/plugins/emn-faq-accordion-block/changelog-en.txt (German: changelog-de.txt)

5.0.1

  • Fixed the HTML anchor’s id not updating in a WPML translation: since “HTML anchor” is WordPress’s native anchor support, its id is normally baked into the saved markup once at editor-save time, not regenerated on render — so a WPML translation of the anchor field changed the link text but not the target id, breaking the direct link on translated pages. The id is now set from the current (translated) value on every render, like the block’s other dynamic attributes already are.

5.0

Major internal change (no action required): renamed the CSS class for each question/answer pair from accordion-item to emn-accordion-item — the exact class Bootstrap 5 uses for its own accordion component (bundled by many WordPress themes/page builders), a real risk of visual conflicts on sites also loading Bootstrap. The old class stays fully supported for already-published content, unchanged; only new questions use the new class. Continues the 4.6 namespace change. Version bumped to flag this as bigger than usual, though nothing needs re-saving.
* Fixed “This block contains unexpected or invalid content” on accordion items saved before this rename: added the missing block-deprecation entry, disabled the block’s unused native “Additional CSS Class(es)” support (was injecting its own extra class), and made items with an HTML anchor set redeclare anchor support on that deprecation entry too (deprecation entries don’t inherit it automatically).
* The HTML anchor (for “link straight to one question”) is now translatable per language via WPML, instead of being copied unchanged into every translation.
* Added a slider (Type panel) to control how fast a question opens/closes, 0–2s in 0.1s steps. Defaults to 0.35s (the previous fixed speed), so existing accordions are unaffected unless changed. Setting it to 0 (instant) is handled correctly by the scroll-into-view feature, which otherwise relies on an animation-end signal that doesn’t fire without an animation.
* Anchor-link clicks now scroll smoothly instead of jumping first.

4.6

  • Moved the blocks to their own dedicated namespace, emn/accordion and emn/accordion-item, instead of the generic custom/accordion/custom/accordion-item (real collision risk with other plugins registering the same block name; WordPress only allows one registration per name). Old names remain as a hidden alias — no longer in the inserter, but existing content keeps rendering/editing/translating unchanged, no re-saving needed.

4.5.1

  • Fixed the “link straight to one question” feature not opening the target when a theme/plugin intercepts the click before the URL hash actually changes.
  • Fixed the Plugin URI header pointing to an old, no-longer-existing page.
  • Fixed the Domain Path header pointing to a languages folder that isn’t actually part of the package (this plugin ships no bundled translation files by design; translations are delivered via translate.wordpress.org).
  • Fixed a whole class of potential naming collisions with other plugins: block.js declared its many internal helper functions in a way that, without an explicit 'use strict', JavaScript’s own legacy compatibility rules leak them onto the global window object — some of them under fairly generic names. Adding 'use strict' keeps every one of them properly contained to this plugin’s own script, with no functional change.
  • Added the standard “Website”/”Support” links under the plugin’s row on the Plugins screen.
Back to top