Site-Check Accessibility

Description

Requires a Site-Check account and an active subscription. This plugin is the
connector (client) for Site-Check, a hosted, paid accessibility service; the
scanning and fix-computation run externally on Site-Check’s servers, not inside
WordPress. See “External services” below.

Site-Check Accessibility connects your WordPress site to the Site-Check
accessibility web app. Fixes that you review and approve in the app are applied
directly to your live pages — no manual CSS or markup editing.

Approved fixes are written server-side, straight into the delivered HTML;
only elements created later by your site’s own JavaScript fall back to a small
client-side script. Every change is traceable and reversible, and is delivered
only while an active connection and a valid subscription exist — disconnect
the site or end the subscription and the fixes are removed automatically on the
next page load.

Features:

  • Image alt text, ARIA labels, contrast and CSS corrections
  • Structural fixes (heading levels, lists, form labels, …)
  • Optional accessibility overlay (an assistive aid — not a replacement for real fixes)
  • Guided site connection in the WordPress admin

Deutsch: Site-Check Accessibility verbindet deine WordPress-Seite mit der
Site-Check-Webapp. In der Webapp geprüfte und freigegebene
Barrierefreiheits-Verbesserungen landen automatisch auf der Live-Seite — ohne
manuelle Eingriffe im Code, serverseitig geschrieben und jederzeit widerrufbar.
Die Auslieferung erfolgt nur bei aktiver Verbindung und gültigem Abonnement.

This plugin is the connector (client) for the Site-Check service; the web app
and backend are a separate, proprietary service.

Privacy

The plugin communicates only with the Site-Check web app at
https://site-check.de to exchange accessibility fixes and connection/health
status. It transfers the page URLs and markup needed to compute and verify
fixes; it does not send data to any third party and sets no tracking cookies.
Details: https://site-check.de/datenschutz

External services

This plugin is a connector to Site-Check, a hosted (paid) accessibility service
operated by site-works AG. It requires a Site-Check account and an active
subscription; scanning and fix-computation run on Site-Check’s servers, not
inside WordPress. The plugin communicates with the Site-Check web app at
https://site-check.de in these cases:

  • Connecting the site: the pairing code you enter and your site’s base URL are
    sent to exchange them for a connection token.
  • Fix sync and verification: page URLs and page markup are sent so the service
    can compute and verify accessibility fixes; connection/health status is
    reported back.
  • Assistance overlay (only when enabled): visitor-facing pages load the overlay
    runtime script from https://site-check.de/api/overlay/runtime.js, and the
    overlay fetches its configuration from https://site-check.de/api/overlay/config.

No data is sent to any other third party, and the plugin sets no tracking
cookies.

  • Terms of Service: https://site-check.de/agb
  • Privacy Policy: https://site-check.de/datenschutz

Installation

  1. Upload the plugin ZIP under Plugins Add New Upload Plugin, or unpack
    it into wp-content/plugins/site-check-accessibility/.
  2. Activate Site-Check Accessibility under Plugins.
  3. Open Site-Check Accessibility in the admin sidebar.
  4. Generate a pairing code in the Site-Check web app (https://site-check.de) and
    paste it into the plugin form to connect the site.
  5. Scan your site in the web app, review and approve fixes — they appear on the
    live site automatically.

Requirements: WordPress 6.0+, PHP 8.0+ with the dom extension. Pretty
permalinks should be enabled.

FAQ

Does the plugin change my content permanently?

No. Fixes are applied at delivery time and are fully reversible. They are served
only while the site is connected and the subscription is active; otherwise the
original markup is delivered unchanged.

Do I need to edit code or templates?

No. Once connected, approved fixes are applied automatically — no theme or
template edits are required.

The connection or fixes don’t work on my host.

Some hosts strip the Authorization header before it reaches PHP. The plugin
also accepts the pairing token via the X-Sw-Api-Token header, which survives
most such configurations; if pairing still fails, make sure either that header
or Authorization: Bearer is passed through to PHP (typically an .htaccess
rule on Apache + mod_php).

What data leaves my site?

Only the data needed to sync fixes and connection status with the Site-Check web
app. See the Privacy section below.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“Site-Check Accessibility” is open source software. The following people have contributed to this plugin.

Contributors

Changelog

1.0.2

  • Fixed: a fix that was already written into the delivered HTML was applied a
    second time by the client runtime. Because the two run against differently
    shaped documents — the served page on one side, the page after the site’s own
    JavaScript on the other — the second write could land on a different element
    than the first. On sliders that clone their slides this produced labels on the
    wrong slide. The server half now tells the runtime which fixes it already
    applied, and the runtime skips them.

1.0.1

  • Front-end scripts and styles are now added through the WordPress enqueue API
    (wp_enqueue_script / wp_enqueue_style + wp_add_inline_script /
    wp_add_inline_style) instead of being written into the page HTML. The client
    apply runtime ships as a real enqueued file (assets/js/sc-acc-apply.js) with
    the per-page data attached inline. Server-side fixes are unchanged.
  • REST: /connect-status and /webapp-status now require authorization
    (manage_options or the connector bearer token) instead of being public.
  • Themes that do not call wp_head()/wp_footer() fall back to an output-buffer
    injection so the overlay + client runtime still work there; standards-compliant
    themes use the enqueue path only (assets injected once, never duplicated).

1.0.0

(2026-07-23)
* Store release under the new name Site-Check Accessibility (renamed from
“sw-acc-connector”). Relicensed to GPLv2-or-later. The plugin folder, text
domain, classes, admin menu and upload directory were renamed; the REST wire
(namespace, option keys, signing key) is unchanged, so existing pairings keep
working after re-installing — the pairing token stays in wp_options and the
upload directory is migrated automatically on first load.
* Added: fail-open output buffering — a mutation error can never blank the page;
the original response is served instead.
* Version reset to 1.0.0 (continuation of the 2.6.0 line; same feature set).
* Requires re-installing the renamed plugin on customer sites.

2.6.0

(2026-07-22)
* Fix: fixes are now removed on the frontend when the site is disconnected or
the subscription lapses — not only when the admin plugin page is opened. The
injector serves from the signed cache (24h grace); the only frontend
revalidation (try_refresh_signed_cache) previously acted on HTTP 200/304 only
and ignored 401/403, so disconnected/unsubscribed sites kept serving cached
fixes for up to 24h. Now it reconciles like the admin healthcheck:
– 401 (token revoked — site disconnected/deleted) -> clear_stored_api_token()
drops the token AND the signed cache; fixes disappear on the next pageload
and the status shows “disconnected” immediately.
– 403 (entitlement_inactive — subscription lapsed) -> drop the signed cache
only, keep the pairing; delivery resumes automatically on re-subscribe.
Guarantees fixes are delivered only with an active connection + valid
subscription. The webapp /clear-cache push on disconnect remains the immediate
path; this is the fail-safe reconciliation.
* Requires re-deployment of the plugin on customer sites.

2.5.0

(2026-07-22)
* Fix: the accessibility overlay would not load on WordPress sites. The
hard-coded webapp base URL pointed at the www host
(https://www.site-check.de) while the Grav connector uses the canonical apex
(https://site-check.de). Post-EU-cutover www 301-redirects to the apex, and
the overlay runtime’s config fetch (GET /api/overlay/config, CORS
origin-bound) plus the heartbeat POST (Authorization bearer -> preflighted)
do not follow a cross-origin 301 cleanly -> the overlay panel never mounted.
Base URL corrected to the apex, identical to the Grav connector.
* Requires re-deployment of the plugin on customer sites for the overlay to be
delivered again.

2.4.0

(2026-07-22)
* Added: label_append server-side render path (WCAG 3.3.2 required indicator).
label_append overrides were persisted but never rendered — the output loop
had no handler. ServerHtmlMutator::applyLabelAppend now resolves the field’s
(explicit label[for], then nearest wrapping <label>, then an
unambiguous unassociated sibling <label> in the field’s parent) and appends a
visible ” *”; inject_label_append_bootstrap runs it server-side first with a
client fallback for post-JS/SPA fields. Idempotent (data-sc-acc-required-marked);
a safe no-op when the field has no label (the paired aria-required write still
lands). The marker span is aria-hidden so it reinforces visually only. New
healthcheck feature: label-append.
* Powers the reworked missing-required-indicator fix: aria-required="true" +
a visible ” *” on the field’s label, instead of a “Pflichtfeld” text node after
the input. Re-deployment required for the visible marker to render.
* Fixed: label_append was dropped before render — the cache normaliser
(index_override_items_by_id) had no branch for it, so the attribute-required
catch-all silently discarded it. Added the branch; the leading space of ” *”
is preserved (was trimmed).
* Fixed: disconnect left fixes live. clear_stored_api_token() now also unlinks
the signed cache, so the webapp-status reconciler (401 / DISCONNECTED) removes
the fixes instead of leaving them until the 24h grace expired. Combined with
the webapp calling /clear-cache on delete/disconnect, fixes are removed
immediately from both sides.

2.3.3

  • Hotfix on top of 2.3.2: tag_replace runtime now remembers per-item which
    items have already been applied (appliedIndex map inside the IIFE). Without
    this, the MutationObserver re-ran apply() after the first replacement and
    the originally-second <h2> became the new “first match” of a positional
    selector like div.bp-container h2:nth-of-type(1) — and got promoted too.
    Per-item idempotency makes apply() safe across the entire page lifecycle.

2.3.2

  • Bugfix: tag_replace runtime applies the transformation to the first
    eligible match only
    (previously: all matches). This alone was not enough
    — see 2.3.3 for the actual fix.

2.3.1

  • Schema bump to pipeline version 1.0.1 (additive, backward-compatible).
  • sibling_text_insert carries an optional wrapTag (whitelisted to
    h1–h6/p/span/legend) so the runtime can render an <h1> (and not a
    ) where the fix is meant to add a real heading.
  • tag_replace carries an optional inlineStyle — a compact CSS string the
    runtime merges onto the replaced element’s style attribute. Prevents
    theme styling from breaking when promoting e.g. <h2> to <h1>.
  • Disconnect (admin button + REST endpoint) now removes cache.json and the
    cached state option, so a previously paired site stops shipping fixes
    immediately after disconnect. Plugin deactivation stays a no-op.

2.3.0

  • Initial WordPress release. Feature-parity with the Grav plugin v2.3.0
    on the apply pipeline (alt-text, aria-label, attribute-override,
    contrast-adjustment, css-declaration-set, sibling-text-insert,
    label-append, placeholder-append, html-insert-before, text-content-override,
    document-override, tag_replace, element_replace, element_remove).

2.0.0

(2026-07-08)
* Breaking (delivery model): fixes are now written server-side into the
delivered HTML (raw HTTP response, no client JS required); only post-JS/SPA
elements fall back to a client bootstrap (data-sc-acc-fallback="1"). Same
target elements, same result, same reversibility, same subscription binding —
only the mutation site changes (server HTML instead of browser DOM).
* Vendored HTML5-spec serializer (masterminds/html5) + a CMS-agnostic
ServerHtmlMutator engine. Adds server-side-apply to the healthcheck feature
list so the webapp can verify fixes statically.
* Security: the retained client-fallback scripts keep the 1.1.1 JSON escaping
(JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) on all sinks.
* Requires re-deployment of the plugin on customer sites.

1.1.1

(2026-07-06)
* Security: extends the 1.0.6 XSS-hardening (JSON_HEX_TAG | JSON_HEX_AMP |
JSON_HEX_APOS | JSON_HEX_QUOT
) to every inline-<script> JSON sink added
since — the client-side alt injector and the Phase-0 bootstraps
sr_only_text_insert / css_rule_inject / element_insert.
* Requires re-deployment of the plugin on customer sites.

1.1.0

(2026-07-04)
* Parity with Grav plugin 1.3.0: new fix type attribute_remove — pure
client-side attribute deletion via the selector-overrides bootstrap
(operation: "remove"), verify anchor data-sc-acc-managed-removed.
Includes the optional removeAttributes piggyback field on
alt_text_override / aria_label_set / attribute_override /
text_content_override items (removal applied after the value write).
* Three new WCAG-Phase-0 fix types (shared-decisions §1.1) — 1:1 port of
Grav plugin 1.4.0 (identical validators, id derivation and bootstrap JS),
all applied strictly client-side via bootstraps (no DOM
re-serialization):
* sr_only_text_insert — visually-hidden screenreader text
(<span class="sc-acc-sr-only" data-sc-acc-sr-only-id="<item-id>">,
text via createTextNode, </> rejected; the class is defined once
via <style data-sc-acc-sr-only-style>).
* css_rule_inject — fail-closed validated CSS rules collected into a
single <style data-sc-acc-css-inject> tag (no at-rules, no
url()/expression()/javascript:, no {}/<>/;/@/backslash in
values; re-validated on the render path).
* element_insert — whitelisted HTML (a/span/p/button/div only; no
script/style/iframe, no event handlers, no javascript:/vbscript:/
data:text/html URLs, no &#/&colon; entities, no comments/doctype)
inserted via template + insertAdjacentElement, de-dup via
data-sc-acc-insert-id=””.
* Apply dispatcher hardened: unknown fix types are now rejected with
unsupported_fix_type: instead of being silently treated as
alt_text_override. Every webapp-sent type has an explicit case; a
missing/empty type still means alt_text_override (legacy alt payloads).
* Cache-store id normalization: explicit branches for attribute_remove,
text_content_override (Grav 2.3.2 parity — id-less items were silently
dropped), sr_only_text_insert, css_rule_inject and element_insert.
* Healthcheck features list extended: attribute-remove, sr-only-insert,
css-rule-inject, element-insert.
* Requires re-deployment of the plugin on customer sites.

1.0.6

  • Security: XSS-hardening of the inline <script> bootstrap injectors. All JSON
    embedded in an inline script (selector-overrides, sibling-inserts,
    document-overrides, tag_replace / element_replace / element_remove, overlay
    bootstrap) now also uses JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS |
    JSON_HEX_QUOT
    , so a fix value / overlay label containing </script>… can no
    longer break out of the inline script.
  • Fix: default webapp base URL corrected from https://www.site-check.de to the
    canonical apex https://site-check.de — post-EU-cutover www 301-redirects and
    the plugin’s POST callbacks (sync/register) must target the apex.
  • Requires re-deployment of the plugin on customer sites.

1.0.4

  • Bootstrap-Payload for the overlay runtime now ships apiToken so the
    browser-side overlay can authenticate the new POST /api/overlay/heartbeat
    call against the webapp. Without the token the runtime simply skips the
    heartbeat — overlay itself keeps working.
  • New WP-admin toggle “Overlay-Runtime auf der Website laden” (default ON)
    acts as a local kill-switch independent of the webapp-driven enabled flag.
  • sync-status response now reports the real overlayRuntimeEnabled value
    instead of a hard-coded true.
  • Requires re-deployment of the plugin on customer sites so the heartbeat
    appears in the dashboard health view.