Description
STM Barrierelotse is for shops that sell under the German Accessibility Improvement Act (BFSG / Barrierefreiheitsstärkungsgesetz, Germany’s implementation of the European Accessibility Act). It does three things, and it is honest about the line between them.
1. It checks — the real buying journey, not a list of pages.
- A product goes into the cart, and cart and checkout are then measured WITH content, including the error messages a customer meets when a required field is left empty. A page-list scanner checks an empty checkout, which is a different page. Classic checkout and the checkout block both.
- The pages it visits are drawn from what a shop actually is: the front page, the shop page, the biggest category listings, one product of each kind (simple, variable, on sale), the legal pages, a search with a real product word, the 404 page — and the cookie notice, as a visitor meets it. Before the check starts it says in words what it is about to look at.
- Optionally the four most important pages a second time at the width of a phone.
- Your own cart is put aside before the check and put back afterwards, and no order can be placed while a check runs — the checkout step presses the order button on purpose.
2. It generates — the information § 14 BFSG requires.
- The four mandatory elements of Annex 3, including the responsible market-surveillance authority, as a page of your own or as a block for your terms and conditions.
- Element (c) — how you address the requirements — is filled from real data: the measuring stick, the date and size of the last check, and every guided manual check you assessed as met, by name and date.
- Required fields that are empty stop the generator. This plugin publishes no placeholder prose in your name.
3. It documents — so the work can be shown, not asserted.
- A measures log that writes itself: every check, every fix switched on, every manual verdict, every publication of your information — with date and person.
- A finding can be marked as fixed, handed over or deliberately accepted; the next check holds that claim against what it measures and records the contradiction if there is one.
- Check reports are kept, comparable and printable, with an identity line on paper naming shop, report number, scope and measuring stick.
Where automation ends, it says so. Automated rules reliably reach only part of WCAG 2.1 AA (EN 301 549); roughly two thirds of the criteria need a person. Those are shown as unchecked rather than quietly counted as met, and the ones that matter most on a buying journey come as guided checklists — can an order be reviewed and corrected before it binds, do the error messages help, does the account route work with a keyboard.
It is not an overlay. No toolbar is injected, no widget. The fixes it offers are precise, off by default, and each one names exactly what it changes.
Everything runs locally. No cloud service, no external scan API, no telemetry, no customer data leaving your server.
Auf Deutsch
STM Barrierelotse ist für Shops, die unter das Barrierefreiheitsstärkungsgesetz fallen. Er tut drei Dinge:
- Prüfen: die ECHTE Kaufstrecke — ein Produkt liegt im Warenkorb, Warenkorb und Kasse werden MIT Inhalt gemessen, samt der Fehlermeldungen bei leerem Pflichtfeld. Dazu ein Seitenplan aus dem, was ein Shop wirklich ist, und der Cookie-Hinweis, wie Besucher ihn antreffen. Während einer Prüfung kann keine Bestellung ausgelöst werden.
- Erzeugen: die Informationen nach § 14 BFSG (Anlage 3) samt zuständiger Marktüberwachungsstelle — als Seite oder als AGB-Baustein. Pflichtfelder, die leer sind, halten den Generator an: In Ihrem Namen wird kein Platzhaltertext veröffentlicht.
- Dokumentieren: ein Maßnahmenprotokoll, das sich von selbst schreibt, Befund-Status mit Bestätigung durch die nächste Messung, und aufbewahrte, druckbare Berichte.
Wo die Automatik endet, sagt er es. Etwa zwei Drittel der Kriterien kann nur ein Mensch beurteilen; sie stehen als ungeprüft da, statt stillschweigend als erfüllt zu zählen. Kein Overlay, kein Widget, kein Cloud-Dienst.
Privacy
This plugin stores no personal data of your visitors and sends nothing anywhere.
What it stores in your own database: which pages were checked and when, which rules passed or failed, a short markup excerpt of each element a rule failed on, your verdicts on the guided manual checks, and the measures log. Two of those touch people, and both are handled deliberately:
- Markup excerpts have the values of form fields removed before they are stored: the value attribute, every data- attribute, the content of a textarea and the text of a selected option. The checkout renders the signed-in administrator’s own name and address into the markup, and a report that carried those into a support message would be the one path by which personal data could leave a server this plugin promises never to leave.
- The my-account screens are never checked automatically. The check runs in your own logged-in session, so those pages would render your name, your address and your orders into the stored excerpts. They belong to the guided manual checks, which you carry out signed out in a second browser.
Manual verdicts and log entries record WHICH user account made them (the user id and the display name), because a documented process has to say who did what. That is the same data WordPress already keeps for every post and comment.
Deleting the plugin keeps all of it unless you tick “remove all data on uninstall” beforehand.
Credits
This plugin bundles the axe-core accessibility engine by Deque Systems, Inc., unmodified, under the Mozilla Public License 2.0.
- Version: 4.10.3
- Source: https://github.com/dequelabs/axe-core/releases/tag/v4.10.3
- SHA-256 of the bundled assets/axe/axe.min.js: 880970c081707360e64f34cea25ff91892f5bc95675b0776925b9709dd8a68bb
- Source Code Form of that exact build: https://github.com/dequelabs/axe-core/tree/v4.10.3
As MPL-2.0 § 3.2 requires: the Source Code Form of the bundled file is the one linked above, at no charge.
The build refuses to make a release package when that fingerprint does not match — an engine that changed unnoticed is an engine whose results nobody can trace back to a published version. The license text ships in assets/axe/LICENSE.txt. German rule descriptions come from axe-core’s own locale files. All checking happens locally; the engine is never loaded from a CDN.
Screenshots





Installation
- Install and activate the plugin. It creates its own tables and adds a “Barrierelotse” entry to the admin menu. Nothing on your site changes and nothing is added to your pages.
- Open Barrierelotse Dashboard and press “Start full check”. The check runs in this browser tab, in your own logged-in session: leave the tab open and in the foreground until it finishes — about five to seven minutes for a normal shop.
- Work through the report. Every group says what is wrong, what usually causes it, and which page each occurrence sits on.
- Under Legal, fill in what the accessibility statement needs and publish it. Required fields that are empty stop the generator on purpose.
- After a repair, measure the rule again from its card, or run the next full check. The measures log records every step with date and person.
WooCommerce is optional. Without it everything works except the buying-journey part of the check, which stays dormant.
FAQ
-
Does this plugin make my shop BFSG-compliant?
-
No — and be wary of any tool that promises that. Automated checks reliably cover only a part of the WCAG 2.1 AA requirements; the rest needs human judgment. This plugin automates what can be automated, guides you through what cannot, generates the required accessibility statement, and documents all of it. Whether the result meets the legal bar for your specific shop is an assessment the law leaves to you and, where needed, your legal counsel.
-
How long does a check take, and does it slow my shop down?
-
A full check of a normal shop takes about five to seven minutes and visits up to forty pages (you can lower that). It runs in YOUR browser tab, in your own logged-in session, and loads each page once — the same load a visitor causes. Your shop keeps serving customers throughout; nothing is queued on the server and nothing runs in the background afterwards. Close the tab and the check stops, keeping everything measured so far.
-
Do I have to keep the tab open?
-
Yes, and in the foreground. A browser slows down tabs in the background so far that measurements become unreliable, so the check pauses while you are elsewhere and carries on when you come back. It tells you that it did.
-
Which browser do I need?
-
Any current Chrome, Edge or Firefox. Safari works too. The check needs nothing installed and no extension.
-
Can I run it on a staging site?
-
Yes, and it is a good idea before a theme update. Results are stored per site, so a staging copy keeps its own history; nothing is shared between installations.
-
What does it store, and how do I get rid of it?
-
Check reports, findings, the rule outcome per page, the state you recorded for a rule and the measures log live in five tables of your own database. Reports are trimmed to the number you choose (a hundred by default, and a report you mark to keep is never trimmed). Deleting the plugin leaves everything in place unless you tick “remove all data on uninstall” in the settings first — the measures log is evidence, and evidence that vanishes with an uninstall is worth nothing.
-
Do I need WooCommerce?
-
No. The site scan, the quick-check and the accessibility statement generator work on any WordPress site. Only the buying-journey scan (cart and checkout with content) needs WooCommerce and simply stays dormant without it.
-
Which standard does it check against?
-
WCAG 2.1 level AA — today’s measuring stick for BFSG services via EN 301 549. The plugin’s architecture is profile-based, so the successor standard (WCAG 2.2 AA) can be added as a profile once the new edition of EN 301 549 is officially referenced.
-
Is this an accessibility overlay or widget?
-
No. Overlays add a toolbar on top of a page without changing the underlying code; accessibility bodies broadly agree they do not achieve conformity, and their use has drawn regulatory action. This plugin works on the source of the problem: it finds issues in the rendered page, applies precise opt-in fixes, and tells you plainly what remains to be fixed by hand.
-
Does any data leave my server?
-
No. Scans run locally in your own browser session against your own site. The plugin calls no external scan service and sends no telemetry. Where a report offers to ask this plugin’s maker for help with a finding, it prepares a message in YOUR OWN email program — you read it and send it yourself; the plugin transmits nothing anywhere.
-
Works this with Germanized or German Market?
-
Yes, by design — the plugin checks the checkout those plugins render instead of replacing anything.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“STM Barrierelotse for WooCommerce” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “STM Barrierelotse for WooCommerce” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.1.3
- The report no longer opens WordPress’s file editor inside a dialog of its own. The button stays, and it still points at the same editor; it opens a tab now instead of a frame, and says so in its own text, because a link that leads elsewhere without announcing it is precisely what this plugin reports on other people’s sites. The plugin directory objected to the frame, and the distinction is worth keeping straight so that nobody rebuilds it by accident: not the link. Linking to an admin screen is ordinary, and that editor belongs to WordPress, which guards it with its own capability and puts the previous version back if a save would stop the site from loading. What invited the objection was putting somebody else’s screen inside ours and hiding its admin chrome, which made it look like a part of this plugin. The dialog, the frame, the CSS that did the hiding and the three strings that went with them are all gone.
- “Tested up to” leaves the plugin header. It belongs in readme.txt and nowhere else. Carried in both places the header can win, and then the compatibility shown on a plugin’s page is not the one its author is maintaining.
1.1.2
- New name: STM Barrierelotse. The plugin directory pointed out that “BFSG Checker” is already carried by another plugin there, and a name that can be mistaken for somebody else’s is a problem whichever of the two came first. A Lotse is a pilot — the one who comes aboard and steers a ship through water it does not know — and that is closer to what this plugin does than “checker” ever was: it does not hand over a list, it says what to do next and in what order. BFSG stays where it belongs, in the description and the tags.
- The text domain moves with it, which is the whole of what a rename means in code: 1,582 places, none of them a key under which anything is stored. Runs, findings, the rule states and the measures log sit in tables and options named for the code, not the name, so an existing installation keeps every one of them.
- The CSS that strips the admin chrome out of WordPress’s file editor is enqueued instead of echoed as a style tag.
- The link to the axe-core source answered 404 and now points at the source tree of the tag. Not cosmetic — the sentence above it is the MPL-2.0 section 3.2 offer of the Source Code Form.
- No more bundled translation, and no more load_plugin_textdomain(). The two belonged together and both go: WordPress reads wp-content/languages/plugins and …/themes and nowhere else, so a catalogue inside the plugin is reached only through a path that call registers. The German moves to translate.wordpress.org, which delivers it where WordPress actually reads it and keeps it current for every language.
1.1.1
- The gradient measurement now reaches the report. Every value a checked page proposes is matched against a list of what it is allowed to look like, and anything unrecognised is dropped — a page being checked is somebody else’s markup, and none of it becomes free text in this database. The rule added in 1.1.0 sent six values that list had never been told about: the two ends of the gradient, the ratio the text reaches against each, the verdict at the worse end, and what kind of thing is behind the text. All six were discarded on the way in. The card that explains those places skips any occurrence without them, so it drew nothing at all, while the chip above it counted 2,167 places and pointed at a section that was never printed. The six are now known, each with the same strictness as its neighbours.
- The cap on how much one occurrence may carry went from ten pairs to twelve. A gradient occurrence carries exactly ten, with the two selectors last in line — so the first thing over the edge would have been the answer to “where is it”.
- A check of the whole chain now runs on every push: every value the checking engine can send is compared against the list that lets values in. It is the gate that was missing, not the list.
- “Open the report” after a check now opens THAT check. The button carried the newest report as of the moment the screen was built, and that screen is built before the check starts — so after a run it led to the report before it. Nothing about that report was wrong except which check it belonged to, which is the hardest kind of wrong to notice. It now carries no number at all: the report picks the newest run when the link is followed, by which time the new one exists.
1.1.0
- Text on a colour gradient is named instead of passed over in silence. The checking engine gives no verdict where it cannot resolve a single background colour, and those places went into no report at all: measured on the shop this plugin was written for, 152 such places on the front page alone, 135 of them sitting on a gradient, 15 of those below the ratio their text needs. They are now measured against both ends of the gradient, and the worse end is the one reported — text has to stay readable across the whole area, not over its friendlier half.
- The measurement is deliberately not a verdict. These occurrences carry no severity and count neither as violations nor as passed: the check result leaves them out in both directions, exactly as it already leaves out every rule the engine could not decide. The card says so above the list, because a number nobody can place is worse than no number.
- What triggers it is not what the engine calls the case. Of the places that really sit on a gradient, only 42 were reported as a background gradient; 84 arrived under another name because a pseudo-element made the engine give up one step earlier. The trigger is that no background colour came back at all — what is really behind the text is then resolved from the open page, veils composited in the order the screen paints them.
- The check no longer measures a page that is still moving. A reveal animation changes a class, and the browser then carries on by itself for the better part of a second; a CSS transition is not a change to the document, so the wait that watches for changes sees none and calls the page still. Measured on the shop this plugin was written for: the badges of a process list were read part-way through their fade and reported as #c65010, #cd652d and #d47b4b, three colours that appear in no stylesheet of that site. They are one colour at 93, 82 and 70 per cent opacity — one step for each of the staggered delays. Eight findings across a run of thirty-one pages, every one of them sending the operator to go and fix a colour that does not exist.
- Movement is now finished rather than waited out. Each animation is put at the end state it was heading for anyway, which is what a visitor sees once the page has come to rest; that costs no time on any page of a run, and it needs no guess at how long a wait would have to be. Endless ones — a spinner, a carousel — are left running, because there is no end state to put them at. The same step answers the opposite failure as well: in a tab the browser is not drawing, an animation never advances past its first frame, and for a reveal that first frame is fully transparent, so the element was invisible to the check rather than measured wrongly.
1.0.3
- Two files were shipped with mixed line endings — a few dozen lines written by a patch script with the other kind of newline. Nothing behaved differently because of it, but a checker reading those files says its own results may be wrong, and a report that doubts itself is worth less than one that does not.
- Three names that are deliberately not ours now say so where they stand: the constant every caching plugin listens for, and the two WPML filters this plugin asks rather than offers. Prefixed, each of them would address nobody.
1.0.2
- The plugin header no longer carries a Plugin URI. It pointed at the same address as the Author URI, and those answer different questions: one is a page about this plugin, the other a page about who wrote it. Only the second exists, so only the second is stated. Neither is required.
1.0.1
- A page that IS the cart is now recognised as one however it was built. The check left out the cart, the checkout and the account screens by asking WooCommerce which pages it is configured with — which answers only for the pages it is configured with. Tried on a second shop, one this plugin had never seen: beside the configured cart there sat a second page holding the cart shortcode, so it went into the plan as an ordinary page and would have been measured with an empty basket. That is the very thing the exclusion exists to prevent, reached through another door. The question is now what a page renders — the configured id, any translation of it, or the shortcode or block that does the rendering.
- Ten checks in the test set hold that open, and the shop it was found on is in them by name.
1.0.0
- First public release. The plugin has been running on a live shop through twenty-four checks and fifty-five rounds of work; what changes here is that the version number says so.
- Prepared for the plugin directory: an installation section, the count of database tables corrected (five, not four), the pointer to the full changelog fixed to name the file that ships with the plugin, and the bundled engine’s unminified source linked directly.
- The redaction of stored markup now covers what somebody typed rather than only where the browser usually keeps it: the content of a textarea and the text of a selected option go the way the value attribute already did. An order note reached the excerpt when the failing element was the form around it.
- The spot check ignores messages from other windows, the way a full run always has. What arrives there becomes a line in the measures log, and this plugin sells nothing but trustworthy evidence.
- Colour values are checked for being colours before they reach a style attribute; a settings screen made reachable by lowering the capability can now also be saved; the caches go with the data when uninstall is told to remove everything.
0.59.0
- The report card is a work surface now. It was a card with an explanation column beside the list, a tinted box per page repeating the same two sentences of provenance in every box, and a line per element that flowed differently each time — a chip, two colour squares, a sentence of numbers, a button. The white colour square read as a checkbox, and the operator this was built with read it as one. Now the head says what and how many with the tools on its right, one sentence says the problem, the guidance folds away where a “start here” block already leads and stays open where none does, and the occurrences of a page are one table — element, colour sample, ratio, values, the way to see it — in columns that line up across every row.
- A page is one line: title, path, step, count, and two short marks saying where the elements come from and what they sit in, each with the full sentence behind an info button. The button that asks where the markup is written stands in that line too, and its answer appears beneath it. Measured on the shop this was built against, same report, same width: the screen went from 6,817 to 5,688 pixels tall, a row from 41 to 34, a page head from two or three lines to one, and 138 repeated provenance sentences became nine marks.
- The colour sample shows the pair as it looks — the text colour on its own background — instead of two squares, and the required ratio is said once per rule instead of once per row. The list keeps its items for assistive technology: rows align through a subgrid, not by dissolving the list.
0.58.0
- A page that is still working is no longer written off as silent. The run gave a loaded page twelve seconds flat to answer, and on the heavy pages of the shop this was built against the engine alone took up to four of those, after up to six of waiting for the page to settle — so the same four pages answered in one run and were filed as “loaded but never answered” in the next, and the run before had named five different ones. The frame now reports each phase it reaches, every report starts the clock again, and only a page that stays quiet for twelve seconds, or works for a minute without a result, is given up on.
- Where it is given up on, the reason says how far it got — settled, scrolled through, check started — and how long it was waited for. And a page that loads late is no longer reported as never having loaded at all: that clock stops at the load event, where it should have stopped all along.
0.57.1
- The changelog is split in two. wp.org shows at most 5,000 words of it, and this one had reached 8,200: the directory page was cutting the history off mid-sentence, while the note at its end said the limit was 5,000 characters — a guess, where the parser’s own source counts words. readme.txt now keeps the recent releases, changelog.txt in the plugin folder holds every one of them, and the build counts the words before a release instead of wp.org counting them after.
0.57.0
- A suggested replacement colour now lands beside the threshold rather than on it. A colour computed to reach exactly 4.5 falls off the other side the moment anything moves, and on a real site something always moves, because “white” is never one colour: measured here, a replacement worked out against #ffffff reached 4.5 while the same text on the site’s near-whites came out at 4.20 on #f5f5f5, 4.35 on #f9f9f9, 4.34 on #f7f9fc. Same colour, same page, one shade of background apart. The size of the margin was measured rather than chosen: the shortfall is proportional, not a fixed amount, so 0.35 still left #f5f5f5 short at 4.47 while 0.5 clears every near-white that site uses. Where even the bare threshold is all that can be reached, the answer is still given.
0.56.1
- The side effect is shown where the fix is actually listed. A correction that works leaves no findings, so its colour pair disappears from the report — and the report was the only place saying anything about it. The settings list is where a switched-on correction still stands, so that is where what it did beyond its own pair belongs.
0.56.0
- A one-click colour correction now says where it went further than it was asked to. A correction is a CSS rule, and a rule is written with selectors measured against one background — those selectors go on matching elsewhere. Measured on the shop this was built for: a price rule taken from prices on white also caught the price in a sticky total bar on dark blue, which had no finding at all before and twenty-three afterwards.
- This is not an argument against the correction. On the pages two runs both measured, that same one took its colour’s findings from 138 to 73. It is an argument against a correction that stays quiet: the check records the colours of every finding, so the arithmetic is done and shown instead of left to the operator to discover.
0.55.3
- Two page counts stood on the dashboard contradicting each other: the header said 26 and the score line said 24. Both were true and they count different things — what the run opened, and how many distinct pages the score averages over, since the buying journey passes the same cart twice and the home page is reached two ways. Where they differ the line now says which is which instead of leaving the reader to decide who is broken.
0.55.2
- Where the check stored no markup, the missing attribute is now shown anyway. Not knowing which tag the element is was reason enough to say nothing at all — and that threw away the part that was known, because which attribute is missing does not depend on the element’s name.
0.55.1
- An element’s attributes are now read from the selector as well as from the stored markup, and the second is not a fallback for old records: a flag icon written as a data URI fills the whole stored excerpt, so the alt=”EN” at the end of the tag was cut off — while the selector, img[alt=”EN”], had kept it all along. That one finding is why the redundant-alt explanation stayed silent.
0.55.0
- Every rule that has ever been measured on this installation now ends with something to act on, and the biggest gap was the commonest outcome of all: where the search did not find the file, the block said so and stopped — a sentence about the search and not a word about the finding. What has to change is usually knowable even when the file is not, so it is now shown either way.
- Where the stored markup settles the cause, it is named in the words of that element: the role that makes a whole section count as one picture, the role that promises a menu which is not there, the aria-hidden over something the Tab key still reaches, the alt text that repeats the words beside it, the list holding something that is not a list item, the viewport line that forbids zooming, the page with no level-1 heading.
- Two more rules can have their corrected line written out — a scrollable box that needs tabindex=”0″ and an unnamed progress bar — by taking the element’s tag from the markup the check stored instead of fixing it in advance. And where the value is a fact rather than a choice, the screen says so instead of asking for words.
- Correcting yesterday’s advice, measured on a live theme: with role=”img” gone, the aria-label should STAY. Without the image role it gives the area a name rather than hiding what is inside it.
0.54.0
- The markup search no longer stops at a style rule. A class name is written in two kinds of place — in the markup that carries it and in every rule that addresses it — and a template writes its CSS at the top and its markup at the bottom, so the first hit in a file was routinely the wrong one: on the case that exposed this, a style rule at line 796 while the section itself is built at line 2843 of the same file. An element wearing the name now ends the search, a rule addressing it is kept only in case nothing else turns up, and where that is what is shown the screen says so.
- “A clickable element inside a clickable element” is now explained in the words of the element itself. Where the stored markup carries a role whose contents count as one thing — role=”img” around a hero section, for instance — the screen names that role as the cause and says what to remove, instead of repeating the general advice not to make a whole tile a link.
0.53.2
- The code block never ends without an answer any more. For a contrast, a heading level, or any rule whose correction is not one attribute in one line, it said nothing at all — it showed somebody their own source code and stopped there, which makes a reader of the person who owns the site. It now says why no line is written out, and where in that card the answer does stand: the measured colours and a sufficient value, the heading levels, or the steps under “How to fix it”.
0.53.1
- The editor dialog now clears up after itself without relying on the “close” event. Measured in the browser this was built against, that event never fires: the dialog closes and the frame — a whole admin page — stays in the document, one per opening. Every way out now goes through the same step, and any leftover is removed before a new one opens.
0.53.0
- A refusal now names the fix as well. Where the corrected line cannot be written out — several such elements on one line, a tag built inside a quoted string, a tag that does not finish there — the missing attribute itself is shown, ready to copy, with the tag it belongs in. Naming a problem and stopping leaves the reader where they started.
- And where the attribute is already in the tag, the screen says which of the two cases it is, because the file settles it: standing there empty is the whole defect, while a value that is present points at a file changed after the check ran — measure the rule again.
- The WordPress file editor now opens in a dialog over the report instead of taking the reader away from it. It is WordPress’s own editor in a frame, with the admin menu and toolbar hidden inside it; the link keeps its address, so a middle click still opens a tab and the screen works without JavaScript.
Older releases are listed in changelog.txt, in the plugin folder — wp.org shows at most 5,000 words of a changelog, and a history cut off mid-sentence is worse than one that says where it continues.
