=== EMN FAQ & Accordion Block ===
Contributors: beatcore
Tags: faq, accordion, gutenberg, schema, block
Requires at least: 6.0
Tested up to: 7.1.3
Requires PHP: 7.4
Stable tag: 5.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Lightweight Gutenberg FAQ & accordion block with automatic Schema.org FAQPage JSON-LD — no code. WPML, Polylang & Loco Translate ready.

== Description ==

Developed by [Engelhardt Medien](https://engelhardt-medien.de/), 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- and Polylang-compatible; translation-ready via translate.wordpress.org or Loco Translate.
* 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; translations are delivered per locale via translate.wordpress.org. English without a language pack (e.g. English (US)) is covered by a built-in fallback. A `.pot` template for Loco Translate/Poedit is in `/languages`.
* Includes a `wpml-config.xml` (read by WPML and Polylang), so only the question text and the HTML anchor are offered for translation — all styling attributes are copied as-is across languages.

== Installation ==

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.

== Frequently Asked Questions ==

= 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 and Polylang? =

Yes. The included `wpml-config.xml` (read by both) marks the question text and the HTML anchor as translatable; styling stays identical across languages.

= Can I translate the editor texts with Loco Translate? =

Yes — use the `.pot` in `/languages` and save to Loco's "Custom" location (files inside the plugin folder are overwritten on updates).

= 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.

== Screenshots ==

1. The default design in FAQ mode in the frontend (schema.org markup is added automatically).
2. The custom styled plugin in Accordion mode in the frontend.
3. The default design and several individually styled items (gradients, borders, icons) in the frontend.
4. Block sidebar: background and text colors, each with separate Normal and Hover settings.
5. Block sidebar: border width, border color, border radius and spacing between items.

== Changelog ==

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.3 =
* New: border width can now be set per side (top/right/bottom/left) in the Borders panel, in the same native look as Padding; the chain icon changes all four at once. Existing accordions are unaffected — a side without its own value keeps following the previous single border width.
* Compact spacing (5px) between the fields in the sidebar panels, to better match the editor look.
* Fixed: in the editor, an answer no longer grows taller (extra space below it) while its item is selected.

= 5.2 =
* New: "Hover Speed (seconds)" slider (Type panel) — controls how fast background, text, icon and border colors change on mouseover (and when opening), 0–2s in 0.1s steps. Defaults to 0.3s (the previous fixed value), so existing accordions are unaffected.
* Fixed editor/admin texts staying German when WordPress is set to English (US) or any English locale without a language pack: a built-in English fallback now fills in untranslated strings. Existing language packs always take precedence; German and other languages are untouched. Two messages that could never be translated before (the "very short answer" check and a toggle label) are now translatable.
* Fixed the default open/close animation speed being rounded from 0.35s to 0.4s on the frontend since 5.0 (and decimals like 0.35 in general); it is exactly 0.35s again, as before 5.0.
* Fixed the editor marking FAQ items saved with 4.4.3–4.6 as "invalid content" when a custom "Additional CSS class" had been set on the item (frontend was never affected). Verified with the real block editor against markup saved by every version from 4.4.4 to 5.1.1.
* Hardened the editor: a question no longer errors in editors without the post-editor data store (e.g. the block widgets screen).
* Translation tooling: added a `.pot` template (`/languages`) plus the `Domain Path` header for Loco Translate/Poedit; the included `wpml-config.xml` is now documented as Polylang-compatible too.

= 5.1.1 =
* Fixed a regression from 5.1's answer text color fix: the new, deeper-reaching color rule also forced links inside the answer to the answer's text color, overriding their own theme/editor link color and making them harder to recognize as links. Links are now excluded and keep their own color, as before 5.1.

= 5.1 =
* Fixed the answer's text color setting not reliably applying: the color rule only reached the answer's direct wrapper element, not the actual content one level deeper (paragraphs, lists, ...), which then fell back to plain CSS inheritance and could be overridden by generic theme rules. Now reaches every depth.
* Fixed doubled left/right padding, plus an extra gap above the first element, on the answer in the editor preview only (frontend was never affected) — both caused by Gutenberg's own editor-only markup picking up spacing meant for the block's actual saved structure.
* Added a "Line height" field (Question panel) and an "Outer spacing" field next to the existing "Inner spacing" one — mainly useful when "Question — HTML element" is set to a heading (h2 etc.), whose theme-default margin/line-height otherwise applies unpredictably; margin already resets to 0 by default even without touching this.
* Moved "Question — HTML element" and "Custom font size" from the Type panel into the Question panel where they belong, alongside the two new fields above; the font-size Desktop/Tablet/Mobile fields now stack instead of showing 3 cramped columns.

= 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.
