---
title: Changelog
url: "https://b13.com/products/vg-wort-pro-for-typo3/changelog"
date: 2026-09-18
modified: 2026-09-19
lastUpdated: 2026-09-19
---

# Changelog

![Black icon featuring a stylized letter "A" with sparkles, set against a light blue and green abstract background.](https://b13.com/fileadmin/_processed_/c/d/csm_sharing-ext-VGWortPro-S_9821f76de1.webp)

 Changelog
===========

 TYPO3 Extension “VG Wort Pro”
 Version 0.10.0 (2026-09-19)

  All notable changes to `b13/vgwort-pro` are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

   0.10.0–2026–09–19
-------------------

  ###  Changed

- **The cache-hash exception for the extraction request lives where the request is made.** It sat in the free extension, which has neither the markers nor the middleware that need it, so nothing there could notice it going missing. It is declared here now, with two tests behind it: a functional one that asks the frontend for a page the way the extractor does—without the exception TYPO3 answers that request with a cache-hash error and every extracted text comes back empty—and a unit test that asks the narrower question the functional one cannot, namely whether this package is what declares the exception rather than the free extension loaded beside it. **This version needs nothing from `b13/vgwort` for it.** The combination to avoid is the other way round: a `b13/vgwort` from 1.0 on, which no longer declares the exception, beside a `vgwort_pro` older than this release, which does not declare it either.
- **`b13/vgwort` resolves like any other dependency.** It is on Packagist now, so the repository entry that pointed Composer at GitHub is gone. Installations that copied that entry into their own `composer.json` can drop it.
- **Every array in a signature says what it holds.** The forty-four that did not are typed now, and three of them turned out to describe something other than what the code does: the row shape of the registration list predated bundled texts and was missing ten of its own keys, an author comparison declared it took author records where it takes a map of card numbers, and two different author shapes were both called `array`. Values that arrive from the database as untyped are cast once, where they are read, instead of being carried through as `mixed`.
- **Error messages from the backend’s own buttons are translated.** Assigning a pixel, validating an author, adopting subpages—each of these answers through a small HTTP call, and every failure it could report was an English sentence written into the PHP. They are labels now, German included, which is where the labels for exactly these messages had been sitting unused all along. That includes the notification titles in the pixel-assign button, which stayed English over German text, and the sentences author validation writes itself—one of which was German while its neighbours were not. What VG Wort itself answers still passes through in whatever language it arrives: translating someone else’s error message is not this extension’s call.
- **The dependency on `b13/vgwort` accepts its 1.0.** Both places that name it—the Composer constraint and `ext_emconf.php`—stopped at 0.99, which would have made this extension uninstallable next to a 1.0 of the free one.

  ###  Removed

- **Eleven methods and seventeen labels nothing used.** Leftovers of earlier shapes of the sync review and the author validation. Nothing calls them, no template asks for the labels, and a reader looking for how something works no longer finds two answers.
- **`MetisApiServiceInterface` loses `getQualityControl()` and `getPixelsWithoutInvolvedMessage()`.** Both lost their last caller and kept an implementation, an interface entry and a test stub each. Anyone implementing this interface can drop those two methods; anyone calling them was not calling them.
- **`RegistrationService::getPagesForRegistration()` is gone.** The module has read the paginated variant for some time; the unpaginated one kept 244 lines of query code alive that no caller reached, and described its rows differently from the method that is actually used. A public service method, so worth naming here even though nothing in this extension called it.

  ###  Fixed

- **The dashboard widget shows what it counted.** It used the dashboard’s layout for widgets whose entire content is one number—a layout that grows with the tile—above a list of four findings, which pushed that list past the edge of every tile size. All five lines are visible now: how many pages have no pixel, how many authors are unverified, how many texts are too short, and how the pool is doing. The declared height applies to a tile as it is placed; a dashboard that already carries the widget keeps the size stored with it, and the dashboard has no resize. Remove the widget and add it again to get the taller tile.
- **The registration list can show everything at once.** The status filter had no option for it, so a reported text and a draft were never on screen together. `all` was accepted by the query only by not being understood, while the select went on displaying a filter that was not in effect. The same select now also offers `manual`, the status a hand-entered pixel gets when no private code is on file—it was counted and reachable by URL all along, but was the one status an editor could not look up, and the one whose texts still need doing by hand.
- **The reporting deadline is written like every other date in the module.** It read the installation’s date format, whose default is ISO, so the one date that decides a year of payout was the only one in `2027-03-31` while the extraction dates two columns over were German.

  ###  Security

- **The AJAX route `/vgwort/validate-author` is gone, and with it a check that was never there.** The action ran no permission check of any kind: any backend account could send it a request and have it verify an arbitrary author record against VG Wort—using whichever site’s API credentials the request named, regardless of whether the author belonged to that site—and write the outcome back to the record’s `verified` flag. Its two neighbours in the same class check page access, and the module’s own version of the action checks the Validate author permission. Nothing ever called this route: the interface has always gone through the module, which is why the gap survived the round of permission hardening that closed the same hole one file over. It is removed rather than guarded—an action with no caller is the one where the next check gets forgotten again.

  ###  Documentation

- **The documentation has pictures.** Nine of them, recorded rather than collected: the pool with all three states, the registration list with five texts in five different conditions, the review step, the bundle field, the dashboard widget, and the page that carries a counting pixel and does not deliver it. Each sits in the chapter that explains it, each with an alt text.
- **The documentation images have a recording setup.** A DDEV installation, a Playwright run and a seed of invented data—a publishing house with a handbook, a pool with free, assigned and retired pixels, one page that carries a pixel and does not deliver it. One command records the set into `Documentation/Images/`, each PNG with its alt text beside it, and a rerun that changes a file means the product changed—with one exception, `deadline-notice`, whose subject is a countdown and which therefore moves with the calendar. The register of what the run owns is in `Tests/playwright/screenshots/README.md`.
- **The README is a README again, and there is documentation behind it.** It was 572 lines and answered "should I install this?" and "what does setting seven do?" in the same breath, which meant it answered neither well. It is now about a hundred lines—what the product is, how to install it, what to read next—and nine chapters under `Documentation/` carry the rest: how a text gets from pixel to payout, every setting with its default, the pixel pool, registration, bundled texts, the sync, the module, and what VG Wort says about consent banners.
- **A `SECURITY.md` says where to report a vulnerability** and what data the extension handles.

   0.9.0–2026–09–17
------------------

  ###  Added

- **Subpages can be adopted into a text in one step.** A manual usually is its page tree, so the entry page’s bundle field now has a button that fills it with the direct subpages, in tree order. Pages that cannot be part of the text are left out and counted—a page with its own pixel, one excluded from VG Wort, a page type that cannot be registered, a page already belonging to another text—by the same rules that reject them when the page is saved. The button only fills the field: the list stays editable and nothing is stored until the page is saved. Every page it offers is checked against the editor’s own page permissions first, because this route never opens the pages it reaches.
- **The module shows the reporting deadline.** Texts have to reach VG Wort by the Meldeschlusstermin of the distribution they belong to, and missing it is the one mistake here that produces no error at all: the texts stay prepared, nothing looks wrong, and a year of payout is gone. The registration view names the next date and the days left, and says it more loudly inside the last eight weeks. The date moves from 1 June to **31 March** with the 2027 distribution, which the module already accounts for.
- **It also says when to report.** A text can be sent at any time—the API does not wait for the minimum access count, and one report keeps earning in every later year the pixel clears it. What matters is that the text has stopped changing, because VG Wort compares the reported text with the page as it stands and a sent report cannot be corrected.
- **The module says which minimum access count applies to a text.** From 10,000 characters, VG Wort accepts a report once the pixel reached half the minimum access count instead of the full one—the longer text has the lower bar, not the higher one. The review view names the class a text falls into, because it decides whether a text is worth reporting this year, and because crossing that line after a report means the pixel has to be swapped. It updates as the extract is edited, and a text under the minimum length is told neither—no access count applies to something that cannot be reported at all.

  ###  Changed

- **The two lengths VG Wort measures by live in one place.** They were a dozen literals across the registration service, the dashboard widget, and a template. VG Wort changes these rules, and a rule that lives in twelve places gets changed in eleven. The README names both lengths, says they are VG Wort’s and not ours, and points at the passage they come from.
- **The response to a report is logged by its field names.** Not their values—one of them would be the text. It means the next question about what METIS actually returns can be answered from the log instead of from the database, which is how the empty field went unnoticed for as long as it did.

  ###  Removed

- **The lower minimum length for poetry is gone from the code.** It was never wired up—no caller ever asked for it—and the exemption it modelled ends with reporting year 2026.
- **The message id field is gone.** METIS never filled it. The documented response to `newMessage` is a single `status` field—no identifier—and the message research returns none either, which is why the column was empty on every reported page. It leaves behind a database column your installation will offer to drop; nothing read it, and the module no longer shows an empty row labelled "Message-ID".

  ###  Documentation

- **What VG Wort says about cookies and consent is written down.** The README said only that local data protection law may apply, which gives an operator no reason not to put the pixel behind a consent banner—and a pixel that renders after someone clicks "accept" counts a fraction of what it should, which decides whether a reported text pays out. VG Wort’s published position is that no personal data is processed, so the GDPR does not apply and, in their reading, neither does the consent requirement of § 25 (1) TDDDG. The README reports that as theirs, names the processor and the purpose of the session cookie, and points at the passage VG Wort provides for a privacy policy.

   0.8.0–2026–09–17
------------------

  ###  Changed

- **TYPO3 14.3 stops reporting the extension as deprecated on every boot.** Two notices were behind it. The package metadata TYPO3 now expects—the version and the list of provided packages—is declared in `composer.json`, so `ext_emconf.php` is no longer read for it; the file stays, because installing without Composer still needs it. And the searchable fields are written where TYPO3 looks for them instead of in the `searchFields` setting it migrates away at boot. What is searchable does not change: an author is still found by name and card number, a pixel by either of its codes, and no one searches for a timestamp.

  ###  Removed

- **The second, unreachable way to send a report is gone.** A `register` route and the method behind it sent a report straight from the database fields, next to the prepare and submit flow that everything in the module actually uses. No button pointed at it, and for a text spread over several pages it built the URL list from every part but the text from the entry page alone—a report that claims those URLs all show the text it sent. It also went out without the permission the supported path requires. Nothing in the interface changes.

  ###  Fixed

- **The sync review says what is wrong instead of showing a label key.** A message shown when the API is not enabled for a site asked for a label that does not exist.
- **Syncing registrations no longer puts a private identification code on the page.** The sync wrote `privateCode` into the message id field, where the module prints it under the label "Message-ID"—and the message research returns no message id to hold there in the first place. It now records the public code as the submitted pixel, which is the value the sync actually knew and previously left empty.

   0.7.0–2026–09–17
------------------

  ###  Added

- **A text spread over several pages can be reported as one text.** A manual or long article split across pages is registered with one pixel, one extract covering every part, and one webrange listing all URLs in reading order—instead of several separate reports that each miss the minimum access threshold. The entry page holds an ordered list of the remaining pages under Further pages of this text in its page properties; the order is the list order, arranged by dragging. Every page of the text renders the entry page’s pixel, which is what VG Wort requires for multi-page texts. A page with an empty list behaves exactly as before, so nothing changes for existing installations. **Requires a database schema update.**
- **The module warns about a pixel that sits on more than one page.** VG Wort binds one pixel to exactly one text; two pages sharing a pixel invalidate both reports rather than just one, and a sent report cannot be corrected. The warning names the affected pages, marks the oldest as the one keeping the pixel, and highlights pixels that have already been reported.
- **Changes to a text after preparation are shown.** A page added, removed or reordered, or an extract edited by hand, are reported in the registration list. For a text that has already been sent, the module states plainly that none of it can be transmitted any more.
- **The limits of the METIS interface are checked before anything is sent** — 250 characters per URL, 100 webranges, 1,000 URLs, and 15 MB for the base64-encoded extract. Running into these as an error code afterwards is expensive, because a rejected report can only be cleared up through VG Wort support.

  ###  Changed

- **A page that does not deliver its pixel is named, and blocks the report.** Preparation now reads the pixel back out of the fetched page instead of trusting the database. A pixel is delivered through TypoScript, and TypoScript breaks in ways that leave a page looking perfectly normal while counting nothing—reporting such a URL gets the pixel deactivated by VG Wort. The check also catches an unexpected exclusion or a template that drops the pixel for one page type. The README explains the case that prompted it: site sets are included before `sys_template` records, so a `page = PAGE` written there replaces the page object the pixel was added to.
- **A text is not reported while a language is missing a part.** If one page of a multi-page text has no translation, that language cannot form a complete appearance. It is now named in the module and blocks the report, instead of being left out silently: the pixel keeps counting on those pages, so omitting their URLs would under-report the text in a way that cannot be corrected afterwards.
- **A page excluded from VG Wort after it was added to a text is dropped from it.** It renders no pixel, so keeping its URL in the report would name a page that counts nothing. The change detection shows it as a removed page rather than letting it disappear quietly.
- **Copying a page no longer carries its VG Wort registration to the copy.** Pixel, reporting status, message id, and extraction data are cleared on copies, including whole branches and bulk operations, and a copied entry page no longer claims the member pages of the original. Translations are unaffected and keep sharing the pixel of their default language page, as they should.
- **The minimum length applies to the whole text.** For a multi-page text the 1,800 characters are counted over all parts, so a chapter below the threshold is unproblematic as long as the text as a whole is above it. The character estimate shown before preparation sums the parts as well; it previously counted the entry page alone and showed texts well over the limit as too short.
- **`registerText()` takes finished webranges instead of a flat list of URLs.** Deciding which URLs form one appearance is a statement about the content and no longer happens inside the API service. Reports for single pages are unchanged.

  ###  Fixed

- **A page that is part of a longer text no longer offers a pixel picker.** Setting a pixel there took the page out of the text without a trace: it would render its own pixel instead of the entry page’s and stop counting towards the text, while looking perfectly normal. The page properties now state which text the page belongs to, which pixel it shows, and in what order the parts are read; the fields that are decided on the entry page are hidden. A pixel already on such a page is cleared on the next save and stays reserved for it—it may have counted accesses already, so it is not offered to another text.
- **A METIS error is handled instead of crashing on guzzle 8.** Guzzle 8 removed `getResponse()` from `RequestException` and moved `ConnectException` out from under it, so every HTTP error from VG Wort became a fatal error in the very block meant to handle it, and a connection failure escaped the handler altogether. Errors are now read in a way that works on both guzzle 7 and 8. Installations on guzzle 7 are unaffected.
- **An installation without `typo3/cms-dashboard` starts again.** The status widget was registered unconditionally although the dashboard is only suggested, so on installations without that package the dependency injection container failed to build—which is not a missing widget but an instance that does not come up at all, backend and frontend alike. The widget is now registered only where there is a dashboard to put it on; with the package present it behaves exactly as before.

  ###  Documentation

- **The README describes when a bundle is right and when it is not**, which pages must not carry a pixel, what the two length thresholds mean, and what can and cannot be done after a report has been sent. Reporting a text incorrectly cannot be undone, so these limits are spelled out rather than implied.
- The note about a lower minimum length for poetry was removed: that exception no longer applies from reporting year 2026 onwards.

  ###  Tests

- **Saving a text from the page properties is covered end to end.** The tests drive the DataHandler the way the backend form does, including the cache invalidation a multi-page text depends on: a page taken out of a text would otherwise go on serving a pixel that is no longer its own, and look perfectly normal while doing so.

   0.6.3 and earlier
-------------------

Released before this changelog was kept. See the README for what the extension does and how to set it up.

 Changelog