{"id":302172,"date":"2026-05-11T13:33:27","date_gmt":"2026-05-11T13:33:27","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/savoy-accessible\/"},"modified":"2026-09-22T21:23:40","modified_gmt":"2026-09-22T21:23:40","slug":"savoy-accessible","status":"publish","type":"plugin","link":"https:\/\/bho.wordpress.org\/plugins\/savoy-accessible\/","author":15445049,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.84","stable_tag":"1.0.84","tested":"6.9.9","requires":"6.2","requires_php":"7.4","requires_plugins":null,"header_name":"Savoy Accessibility \u2013 Drop-In PDF Accessibility for WordPress (WCAG 2.1 AA)","header_author":"Savoy","header_description":"Automatically convert PDFs on your site into WCAG-accessible HTML versions with AI-powered document chat.","assets_banners_color":"c8dad9","last_updated":"2026-09-22 21:23:40","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/savoy.chat\/accessible","header_author_uri":"https:\/\/savoy.chat","rating":0,"author_block_rating":0,"active_installs":0,"downloads":1067,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.32":{"tag":"1.0.32","author":"peteclark3","date":"2026-05-13 17:49:58","revision":3531276},"1.0.33":{"tag":"1.0.33","author":"peteclark3","date":"2026-05-13 21:07:04","revision":3531383},"1.0.34":{"tag":"1.0.34","author":"peteclark3","date":"2026-05-14 13:13:27","revision":3532026},"1.0.35":{"tag":"1.0.35","author":"peteclark3","date":"2026-05-14 13:25:15","revision":3532046},"1.0.36":{"tag":"1.0.36","author":"peteclark3","date":"2026-05-14 14:07:12","revision":3532113},"1.0.37":{"tag":"1.0.37","author":"peteclark3","date":"2026-05-14 14:11:17","revision":3532117},"1.0.38":{"tag":"1.0.38","author":"peteclark3","date":"2026-05-19 17:48:35","revision":3537790},"1.0.39":{"tag":"1.0.39","author":"peteclark3","date":"2026-05-20 12:01:05","revision":3539161},"1.0.40":{"tag":"1.0.40","author":"peteclark3","date":"2026-06-16 16:25:05","revision":3574770},"1.0.41":{"tag":"1.0.41","author":"peteclark3","date":"2026-06-16 16:48:17","revision":3574801},"1.0.45":{"tag":"1.0.45","author":"peteclark3","date":"2026-08-28 20:52:26","revision":3670920},"1.0.46":{"tag":"1.0.46","author":"peteclark3","date":"2026-09-01 19:57:01","revision":3676772},"1.0.47":{"tag":"1.0.47","author":"peteclark3","date":"2026-09-01 20:04:05","revision":3676784},"1.0.48":{"tag":"1.0.48","author":"peteclark3","date":"2026-09-02 12:01:48","revision":3677940},"1.0.49":{"tag":"1.0.49","author":"peteclark3","date":"2026-09-02 12:20:34","revision":3677974},"1.0.50":{"tag":"1.0.50","author":"peteclark3","date":"2026-09-02 12:31:33","revision":3677986},"1.0.51":{"tag":"1.0.51","author":"peteclark3","date":"2026-09-02 12:40:25","revision":3678006},"1.0.52":{"tag":"1.0.52","author":"peteclark3","date":"2026-09-02 13:01:00","revision":3678044},"1.0.54":{"tag":"1.0.54","author":"peteclark3","date":"2026-09-02 13:19:37","revision":3678073},"1.0.55":{"tag":"1.0.55","author":"peteclark3","date":"2026-09-15 13:31:33","revision":3697047},"1.0.56":{"tag":"1.0.56","author":"peteclark3","date":"2026-09-15 13:54:07","revision":3697087},"1.0.57":{"tag":"1.0.57","author":"peteclark3","date":"2026-09-15 14:16:08","revision":3697117},"1.0.58":{"tag":"1.0.58","author":"peteclark3","date":"2026-09-15 14:36:15","revision":3697147},"1.0.59":{"tag":"1.0.59","author":"peteclark3","date":"2026-09-15 16:17:27","revision":3697349},"1.0.60":{"tag":"1.0.60","author":"peteclark3","date":"2026-09-15 17:20:45","revision":3697446},"1.0.61":{"tag":"1.0.61","author":"peteclark3","date":"2026-09-15 17:37:28","revision":3697471},"1.0.62":{"tag":"1.0.62","author":"peteclark3","date":"2026-09-15 17:42:05","revision":3697477},"1.0.63":{"tag":"1.0.63","author":"peteclark3","date":"2026-09-15 17:53:26","revision":3697496},"1.0.64":{"tag":"1.0.64","author":"peteclark3","date":"2026-09-15 18:04:12","revision":3697521},"1.0.65":{"tag":"1.0.65","author":"peteclark3","date":"2026-09-15 18:32:50","revision":3697558},"1.0.66":{"tag":"1.0.66","author":"peteclark3","date":"2026-09-17 14:32:51","revision":3700445},"1.0.67":{"tag":"1.0.67","author":"peteclark3","date":"2026-09-17 16:29:59","revision":3700607},"1.0.68":{"tag":"1.0.68","author":"peteclark3","date":"2026-09-17 17:02:36","revision":3700645},"1.0.69":{"tag":"1.0.69","author":"peteclark3","date":"2026-09-21 14:10:27","revision":3705724},"1.0.70":{"tag":"1.0.70","author":"peteclark3","date":"2026-09-21 14:12:13","revision":3705728},"1.0.71":{"tag":"1.0.71","author":"peteclark3","date":"2026-09-21 14:19:36","revision":3705748},"1.0.72":{"tag":"1.0.72","author":"peteclark3","date":"2026-09-21 14:32:48","revision":3705776},"1.0.73":{"tag":"1.0.73","author":"peteclark3","date":"2026-09-21 14:42:07","revision":3705790},"1.0.74":{"tag":"1.0.74","author":"peteclark3","date":"2026-09-21 15:02:40","revision":3705823},"1.0.75":{"tag":"1.0.75","author":"peteclark3","date":"2026-09-21 15:29:44","revision":3705868},"1.0.76":{"tag":"1.0.76","author":"peteclark3","date":"2026-09-21 16:29:52","revision":3705952},"1.0.77":{"tag":"1.0.77","author":"peteclark3","date":"2026-09-21 17:34:58","revision":3706041},"1.0.78":{"tag":"1.0.78","author":"peteclark3","date":"2026-09-21 17:42:05","revision":3706050},"1.0.79":{"tag":"1.0.79","author":"peteclark3","date":"2026-09-21 17:48:07","revision":3706062},"1.0.80":{"tag":"1.0.80","author":"peteclark3","date":"2026-09-21 17:53:34","revision":3706073},"1.0.81":{"tag":"1.0.81","author":"peteclark3","date":"2026-09-21 18:01:55","revision":3706087},"1.0.82":{"tag":"1.0.82","author":"peteclark3","date":"2026-09-21 18:05:36","revision":3706093},"1.0.83":{"tag":"1.0.83","author":"peteclark3","date":"2026-09-21 18:08:06","revision":3706096},"1.0.84":{"tag":"1.0.84","author":"peteclark3","date":"2026-09-22 21:23:40","revision":3708128}},"upgrade_notice":{"1.0.43":"<p>Cosmetic rebrand from &quot;Savoy AI&quot; to &quot;Savoy&quot; in the plugin author field. No functional changes.<\/p>","1.0.42":"<p>The PDF domain allowlist now defaults to this site&#039;s own domain only (previously it allowed all domains by default). If you rely on converting PDFs hosted on another domain, add it under Settings after upgrading.<\/p>","1.0.41":"<p>Adds a PDF domain allowlist to prevent errors from off-site PDF links. Configure under Settings in the Savoy Accessible admin page.<\/p>","1.0.40":"<p>Adds a &quot;Silent rewrite&quot; link mode that routes PDF links to the accessible HTML viewer without changing how the links look.<\/p>","1.0.39":"<p>Fixes a schema migration bug where progress tracking and validation scores were missing for sites that auto-updated from 1.0.37 or earlier.<\/p>","1.0.38":"<p>Adds WCAG validation scores (powered by axe-core) to the documents list so you can see which converted PDFs need manual review.<\/p>","1.0.37":"<p>Security fix: viewer URLs no longer contain the API key. Update recommended.<\/p>","1.0.36":"<p>PDF links in navigation menus are now rewritten to the accessible HTML version automatically.<\/p>","1.0.35":"<p>Refresh Statuses now detects server-side HTML regeneration and automatically re-syncs the WordPress post.<\/p>","1.0.34":"<p>Processing error messages now persist and display in the documents list so you can see exactly why a PDF failed to convert.<\/p>","1.0.33":"<p>Renames the plugin display name to Savoy Accessibility. No behavior changes.<\/p>","1.0.32":"<p>Moves the opt-in hardening styles (focus outline, reduced-motion, skip link) into the wp_enqueue_scripts pipeline. No behavior changes.<\/p>","1.0.31":"<p>Addresses the next round of WordPress.org plugin reviewer feedback: removed the small &quot;Powered by&quot; link in the chat sidebar, hardened escaping in the PDF link rewriter, and moved the document viewer&#039;s CSS\/JS into proper enqueued assets. No behavior changes.<\/p>","1.0.30":"<p>Code-quality release clearing WordPress.org plugin-check warnings. No behavior changes.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3531265,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3531265,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3531265,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3531265,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.32","1.0.33","1.0.34","1.0.35","1.0.36","1.0.37","1.0.38","1.0.39","1.0.40","1.0.41","1.0.45","1.0.46","1.0.47","1.0.48","1.0.49","1.0.50","1.0.51","1.0.52","1.0.54","1.0.55","1.0.56","1.0.57","1.0.58","1.0.59","1.0.60","1.0.61","1.0.62","1.0.63","1.0.64","1.0.65","1.0.66","1.0.67","1.0.68","1.0.69","1.0.70","1.0.71","1.0.72","1.0.73","1.0.74","1.0.75","1.0.76","1.0.77","1.0.78","1.0.79","1.0.80","1.0.81","1.0.82","1.0.83","1.0.84"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3531248,"resolution":"1","location":"assets","locale":"","width":1200,"height":656},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3531248,"resolution":"2","location":"assets","locale":"","width":2172,"height":1676},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3531248,"resolution":"3","location":"assets","locale":"","width":1200,"height":848},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3531248,"resolution":"4","location":"assets","locale":"","width":1200,"height":687}},"screenshots":{"1":"Documents list showing converted PDFs with ready status","2":"On-demand WCAG audits: image alt text, generic link text, heading hierarchy, tables without headers, and button labels","3":"Accessible HTML version of a converted PDF, with PDF View and Accessible HTML tabs","4":"Accessible Documents post type in WordPress admin"}},"plugin_section":[],"plugin_tags":[1953,2682,1764,130919,1956],"plugin_category":[34,50],"plugin_contributors":[262572],"plugin_business_model":[],"class_list":["post-302172","plugin","type-plugin","status-publish","hentry","plugin_tags-accessibility","plugin_tags-ada","plugin_tags-pdf","plugin_tags-section-508","plugin_tags-wcag","plugin_category-accessibility","plugin_category-media","plugin_contributors-peteclark3","plugin_committers-peteclark3"],"banners":{"banner":"https:\/\/ps.w.org\/savoy-accessible\/assets\/banner-772x250.png?rev=3531265","banner_2x":"https:\/\/ps.w.org\/savoy-accessible\/assets\/banner-1544x500.png?rev=3531265","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/savoy-accessible\/assets\/icon-128x128.png?rev=3531265","icon_2x":"https:\/\/ps.w.org\/savoy-accessible\/assets\/icon-256x256.png?rev=3531265","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/savoy-accessible\/assets\/screenshot-1.png?rev=3531248","caption":"Documents list showing converted PDFs with ready status"},{"src":"https:\/\/ps.w.org\/savoy-accessible\/assets\/screenshot-2.png?rev=3531248","caption":"On-demand WCAG audits: image alt text, generic link text, heading hierarchy, tables without headers, and button labels"},{"src":"https:\/\/ps.w.org\/savoy-accessible\/assets\/screenshot-3.png?rev=3531248","caption":"Accessible HTML version of a converted PDF, with PDF View and Accessible HTML tabs"},{"src":"https:\/\/ps.w.org\/savoy-accessible\/assets\/screenshot-4.png?rev=3531248","caption":"Accessible Documents post type in WordPress admin"}],"raw_content":"<!--section=description-->\n<p>Savoy Accessibility scans the PDFs on your WordPress site and uses the Savoy cloud service to generate WCAG 2.1 AA-friendly HTML versions of each one, so screen readers and other assistive technologies can read the content directly. It also includes a set of on-demand audits and opt-in hardening toggles for common WCAG issues elsewhere on your site.<\/p>\n\n<p>The plugin is intended for sites that publish a lot of PDF content (schools, universities, government agencies, nonprofits, and businesses).<\/p>\n\n<h4>Key features<\/h4>\n\n<ul>\n<li>Automatic PDF detection across posts, pages, and the media library<\/li>\n<li>Conversion of PDF text content to semantic HTML using the Savoy service<\/li>\n<li>Automatic scanned PDF detection \u2014 text is extracted directly when a text layer is present; vision AI OCR is used when the entire document is image-only (e.g. a scanned page). Embedded images in any PDF are described separately via vision AI for alt text.<\/li>\n<li>Automatic alt-text generation for images inside PDFs<\/li>\n<li>Every converted document is automatically audited with axe-core (the accessibility engine used in Chrome DevTools), shown as Pass, Warning, or Needs Review<\/li>\n<li>Generated documents are stored as a custom post type so you can edit them in Gutenberg<\/li>\n<li>Adjustable text size and a real high-contrast reading mode in the document viewer, remembered per visitor<\/li>\n<li>Optional AI chat sidebar in the document viewer (off by default)<\/li>\n<li>Inline accessibility badge next to PDF links<\/li>\n<li>Optional automatic link rewriting so visitors land on the HTML version<\/li>\n<li>Automatic scanning every 4 hours to catch newly uploaded PDFs, plus an instant check when a visitor opens a document that's still converting<\/li>\n<li>Works with any theme<\/li>\n<\/ul>\n\n<h4>On-demand audits<\/h4>\n\n<ul>\n<li>Image alt text audit<\/li>\n<li>Generic link text audit (WCAG 2.4.4) \u2014 flags \"click here\", \"read more\", bare URLs<\/li>\n<li>Heading hierarchy audit (WCAG 1.3.1, 2.4.6) \u2014 flags multiple H1s and skipped levels<\/li>\n<li>Tables-without-headers audit (WCAG 1.3.1)<\/li>\n<li>Empty or missing button labels audit (WCAG 4.1.2)<\/li>\n<\/ul>\n\n<h4>Opt-in hardening toggles<\/h4>\n\n<ul>\n<li>Inject <code>&lt;html lang&gt;<\/code> if missing<\/li>\n<li>Visible focus outlines for keyboard navigation<\/li>\n<li>Respect <code>prefers-reduced-motion<\/code><\/li>\n<li>\"Skip to main content\" link<\/li>\n<\/ul>\n\n<h4>Software as a Service<\/h4>\n\n<p>This plugin is a client for the Savoy service at <a href=\"https:\/\/savoy.chat\/accessible\">savoy.chat<\/a>. PDF processing, OCR, HTML generation, and AI chat all run on Savoy's servers. The plugin only communicates with Savoy when you provide an API key. See the Savoy Terms of Service and Privacy Policy at <a href=\"https:\/\/savoy.chat\/terms\">savoy.chat\/terms<\/a> and <a href=\"https:\/\/savoy.chat\/privacy\">savoy.chat\/privacy<\/a>.<\/p>\n\n<p>The free portion of the plugin (PDF detection and the audit\/hardening tools) does not require an API key and does not contact Savoy's servers. PDF conversion and link rewriting require a Savoy subscription.<\/p>\n\n<h4>How it works<\/h4>\n\n<ol>\n<li>Install and activate the plugin.<\/li>\n<li>Go to Settings &gt; Savoy Accessibility. Click \"Rescan all content\" to see how many PDFs are on your site.<\/li>\n<li>(Optional) Sign up at savoy.chat\/accessible, paste in your API key, and click Save and Verify.<\/li>\n<li>Detected PDFs are sent to the Savoy service for conversion.<\/li>\n<li>Each converted document is stored as an Accessible Document post in WordPress, which you can edit.<\/li>\n<li>Links on your site are optionally rewritten to point at the accessible HTML version.<\/li>\n<\/ol>\n\n<h4>What happens to my original PDFs?<\/h4>\n\n<p>The plugin never modifies your original files. It creates parallel HTML pages and optionally points visitors to them. You can disable link rewriting at any time.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin from the WordPress Plugin Directory, or upload the zip via Plugins &gt; Add New &gt; Upload.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Go to Settings &gt; Savoy Accessibility.<\/li>\n<li>Click \"Rescan all content\" to see how many PDFs on your site need accessibility work. This step is free and works without an API key.<\/li>\n<li>(Optional) Sign up at <a href=\"https:\/\/savoy.chat\/accessible\">savoy.chat\/accessible<\/a>, get an API key, paste it in, and click \"Save and Verify\".<\/li>\n<li>Once an API key is connected, the plugin sends detected PDFs to Savoy for conversion.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"is%20this%20free%3F\"><h3>Is this free?<\/h3><\/dt>\n<dd><p>Scanning, PDF detection, the WCAG audits, and the hardening toggles work without any account and without contacting an external service. Conversion and link rewriting require a Savoy subscription.<\/p><\/dd>\n<dt id=\"does%20this%20guarantee%20compliance%20with%20any%20specific%20regulation%3F\"><h3>Does this guarantee compliance with any specific regulation?<\/h3><\/dt>\n<dd><p>No. The plugin generates WCAG 2.1 AA-friendly HTML, which is the conformance level cited by Section 508 and by the updated ADA Title II rule. Whether your site as a whole conforms depends on your theme, your other content, and your authoring practices. We strongly recommend a professional accessibility audit for any formal compliance certification.<\/p><\/dd>\n<dt id=\"is%20this%20an%20overlay%3F\"><h3>Is this an overlay?<\/h3><\/dt>\n<dd><p>No. The plugin generates real HTML pages with semantic structure, alt text, and reading order, stored as WordPress posts. It does not inject an overlay widget.<\/p><\/dd>\n<dt id=\"what%20about%20scanned%20pdfs%20%28image-only%20pdfs%29%3F\"><h3>What about scanned PDFs (image-only PDFs)?<\/h3><\/dt>\n<dd><p>The Savoy service uses vision-AI OCR for scanned PDFs.<\/p><\/dd>\n<dt id=\"can%20i%20edit%20the%20generated%20html%3F\"><h3>Can I edit the generated HTML?<\/h3><\/dt>\n<dd><p>Yes. Each converted document is a custom post type. You can edit it in Gutenberg like any other page; revisions are preserved.<\/p><\/dd>\n<dt id=\"how%20does%20pricing%20work%3F\"><h3>How does pricing work?<\/h3><\/dt>\n<dd><p>See <a href=\"https:\/\/savoy.chat\/accessible\">savoy.chat\/accessible<\/a> for current pricing and plan tiers.<\/p><\/dd>\n<dt id=\"does%20this%20slow%20down%20my%20site%3F\"><h3>Does this slow down my site?<\/h3><\/dt>\n<dd><p>The plugin adds a lightweight content filter on the frontend. PDF conversion and OCR run on Savoy's servers, not yours.<\/p><\/dd>\n<dt id=\"what%20if%20i%20cancel%20my%20subscription%3F\"><h3>What if I cancel my subscription?<\/h3><\/dt>\n<dd><p>Already-converted documents remain in your WordPress install. New conversions stop.<\/p><\/dd>\n<dt id=\"can%20i%20use%20this%20for%20section%20508%3F\"><h3>Can I use this for Section 508?<\/h3><\/dt>\n<dd><p>The HTML output is designed to meet WCAG 2.1 AA, which Section 508 references as its conformance standard. As with any accessibility work, a professional audit is recommended for formal compliance certification.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.84<\/h4>\n\n<ul>\n<li>Fix: a document whose source PDF was confirmed gone could stay stuck permanently failing to convert, since the check that removes it only ran during a content scan, not a status sync. \"Sync All Doc Statuses\" now runs that check too, so a document with a dead source link is cleaned up the next time statuses are synced, not only when content is rescanned.<\/li>\n<\/ul>\n\n<h4>1.0.83<\/h4>\n\n<ul>\n<li>Fix: syncing a document (manually or automatically) no longer changes its Author. A page's Author is set blank only when the plugin first creates it, then follows whoever last saves it by hand. Syncing and reprocessing leave it exactly as it was; the Revisions panel still shows an automatic replacement as an automatic change.<\/li>\n<\/ul>\n\n<h4>1.0.82<\/h4>\n\n<ul>\n<li>Fix: PDFs deleted from the media library stayed in the Documents list, and their accessible pages stayed live. Deleting a PDF now removes its document from the list, moves its accessible page to the trash (so it can be restored), and deletes Savoy's stored copy. PDFs removed some other way (over FTP or from your host's file manager) are cleaned up by the next scan. Nothing is remembered about a deleted PDF: if the same file is added again it is converted as a brand-new document. Only files inside your own uploads folder that are confirmed gone are removed (never external links, and never files that still have a media-library entry, such as offloaded cloud storage), at most 25 per scan, and a page that still links to a deleted PDF does not bring it back.<\/li>\n<\/ul>\n\n<h4>1.0.81<\/h4>\n\n<ul>\n<li>Change: an Accessible Document's Author now shows who last edited it. Whenever someone saves a document in the editor, they become its Author (their name also appears on that revision). Changes made by the plugin itself, such as syncing or reprocessing a document, are treated as automatic and leave the Author blank, so an administrator clicking Sync is never recorded as an editor. If someone deliberately picks a different Author in the editor, that choice is kept.<\/li>\n<\/ul>\n\n<h4>1.0.80<\/h4>\n\n<ul>\n<li>New: Accessible Documents now have an Author field and full revision history like regular posts. Each save records who made it and when, and any earlier version can be restored from the editor's Revisions panel. The original converted version is saved before a document's first edit, so a person's very first change can be rolled back too; a newer automatic conversion is recorded as an automatic change (no user), separate from human edits. Up to 25 revisions are kept per document unless your site sets its own limit.<\/li>\n<\/ul>\n\n<h4>1.0.79<\/h4>\n\n<ul>\n<li>Change: the automatic background sync now checks documents that are still converting first, so a document that just finished reaches your site on the very next run instead of waiting for the full sweep to come around to it. It also checks up to 100 documents per request (was 25), so a full sweep of a large site takes far fewer requests.<\/li>\n<\/ul>\n\n<h4>1.0.78<\/h4>\n\n<ul>\n<li>Change: the automatic background sync now checks every document, not just the most recent few. It keeps a saved position and picks up exactly where the previous run stopped (up to 150 documents or about 20 seconds per run, wrapping around after the last one), so no document can be skipped no matter how many a site has. It now also re-checks documents that hit your monthly limit or were temporarily not found, and can no longer overlap with a run that is still going.<\/li>\n<\/ul>\n\n<h4>1.0.77<\/h4>\n\n<ul>\n<li>Fix: documents could stay stuck showing \"processing\" even though they had finished converting. Status checks always asked about the same batch of already-finished documents and never reached newer ones still waiting. \"Sync All Doc Statuses\" now walks every document exactly once in order (ten at a time) and its \"X of Y checked\" counter ends at your real document count. The background sync now checks unfinished documents before finished ones, and no longer asks about more documents per run than the server answers.<\/li>\n<\/ul>\n\n<h4>1.0.76<\/h4>\n\n<ul>\n<li>Change: \"Sync All Doc Statuses\"'s progress counter now shows a real \"X of Y documents checked\" that climbs toward and stops exactly at the site's actual document count, instead of a raw touch count that could run past the real total.<\/li>\n<\/ul>\n\n<h4>1.0.75<\/h4>\n\n<ul>\n<li>Fix: \"Sync All Doc Statuses\" could loop far past the site's actual document count and never stop on its own, since already-up-to-date documents kept getting endlessly re-selected as \"needing a check.\" It now stops once the genuine backlog is actually cleared, and no longer lets already-settled documents crowd out ones still waiting on a real status update.<\/li>\n<li>Fix: a long accessible HTML document's later content could render past the bottom of its white content area, spilling onto the page background behind it, instead of the content area growing to fit.<\/li>\n<\/ul>\n\n<h4>1.0.74<\/h4>\n\n<ul>\n<li>Fix: on a multisite network using a shared network-wide API key, an invalid key was incorrectly recorded as a successfully-registered instant-update subscription and never retried. A rejection is now correctly detected and retried on the next scan.<\/li>\n<li>Change: the Documents section's action buttons have been consolidated for clarity. \"Refresh Statuses\" is removed (it made the exact same check as \"Sync All Documents\", just once instead of repeatedly). \"Rescan all content\" is renamed to \"Scan for New PDFs\", and \"Sync All Documents\" is renamed to \"Sync All Doc Statuses\" to better describe what each does. \"Check for Plugin Update\" moved to the Settings section, next to the plugin's version number.<\/li>\n<\/ul>\n\n<h4>1.0.73<\/h4>\n\n<ul>\n<li>New: your site now registers itself to be notified the moment a document finishes converting, instead of only finding out on the next scheduled sync (still every 30 minutes as a backup). No setup needed -- this happens automatically.<\/li>\n<\/ul>\n\n<h4>1.0.72<\/h4>\n\n<ul>\n<li>Fix: visiting a document's page could redirect forever (\"too many redirects\") if the background sync that runs on page-view hit a local data inconsistency. The redirect now only happens after confirming that sync actually succeeded; a failure leaves the current page showing instead of looping.<\/li>\n<\/ul>\n\n<h4>1.0.71<\/h4>\n\n<ul>\n<li>Fix: a document could end up permanently stuck showing \"pending\" even after it finished converting on the server, if the local status update that's supposed to follow a successful report never landed. Both the background sync and \"Refresh Statuses\" now also double-check pending documents against the server (a harmless no-op for one that's genuinely never been reported) instead of only ever checking already-reported ones.<\/li>\n<\/ul>\n\n<h4>1.0.70<\/h4>\n\n<ul>\n<li>Change: up to 50 documents are now reported for conversion per sync cycle (was 10). A single shared worker made a bigger burst a real bottleneck before; that's no longer the case, so the limit now exists mainly to stay within reasonable bounds rather than as a hard infrastructure ceiling.<\/li>\n<\/ul>\n\n<h4>1.0.69<\/h4>\n\n<ul>\n<li>Change: background sync (checking for new PDFs, pulling in finished conversions) now runs every 30 minutes instead of every 4 hours. Existing sites pick up the new schedule automatically on the next page load, no reactivation needed.<\/li>\n<\/ul>\n\n<h4>1.0.68<\/h4>\n\n<ul>\n<li>New: clicking Reprocess on a document you've edited directly in WordPress now warns you first, since the new version will overwrite those edits once it's ready. Confirming authorizes that one overwrite; canceling leaves your edit untouched and does not reprocess.<\/li>\n<\/ul>\n\n<h4>1.0.67<\/h4>\n\n<ul>\n<li>Fix: automatic and manual syncs could silently overwrite a document you'd edited directly in WordPress (e.g. in the block editor) if a newer version was also available from Savoy. We now detect when a document's content has diverged from what we last synced and skip the automatic overwrite, flagging it \"Edited locally\" in your documents list instead. Use Reprocess if you want the newer version anyway.<\/li>\n<\/ul>\n\n<h4>1.0.66<\/h4>\n\n<ul>\n<li>Fix: a document reprocessed on the server after it was already synced to your site (for example, a super-admin support action) never automatically reached your WordPress site -- the background sync only ever checked documents that hadn't been synced yet. It now also picks up documents whose accessible HTML changed after the fact, same as manually clicking \"Refresh Statuses.\"<\/li>\n<\/ul>\n\n<h4>1.0.65<\/h4>\n\n<ul>\n<li>Fix: the redundant \"view the original PDF\" link on the placeholder page, removed in 1.0.61, had come back in 1.0.62-1.0.64 due to a packaging mistake on our end. Removed again, for real this time.<\/li>\n<\/ul>\n\n<h4>1.0.64<\/h4>\n\n<ul>\n<li>Fix: navigation menu PDF links always jumped to the Accessible HTML tab regardless of the Default Tab setting added in 1.0.63 -- that setting only reached content links, not menu links. Both now respect it consistently.<\/li>\n<\/ul>\n\n<h4>1.0.63<\/h4>\n\n<ul>\n<li>New: \"Default Tab\" setting (Settings &gt; Savoy Accessibility) controls which tab -- PDF View or Accessible HTML -- a visitor lands on, independent of the PDF Link Display Mode. Previously this was hardcoded per mode (Silent\/Prominent\/Replace always jumped to the HTML tab, Icon always landed on PDF View). Defaults to PDF View.<\/li>\n<\/ul>\n\n<h4>1.0.62<\/h4>\n\n<ul>\n<li>Fix: deactivating and reactivating the plugin left every accessible-document link showing a 404, since WordPress's cached rewrite rules never got refreshed to include the document permalink structure again. Existing sites self-heal on the next page load after updating; reactivating the plugin fresh flushes correctly from now on.<\/li>\n<\/ul>\n\n<h4>1.0.61<\/h4>\n\n<ul>\n<li>Change: the \"still converting\" placeholder page no longer shows a separate \"view the original PDF\" link -- the PDF View tab already shows the same file and is the default active tab.<\/li>\n<\/ul>\n\n<h4>1.0.60<\/h4>\n\n<ul>\n<li>New: visiting a document's page while it's still converting now checks its live status right then, instead of waiting for the next background sync or a manual Sync click. If it's finished, the page updates in place immediately.<\/li>\n<\/ul>\n\n<h4>1.0.59<\/h4>\n\n<ul>\n<li>Change: background sync (checking for new PDFs, pulling in finished conversions) now runs every 4 hours instead of once a day. Existing sites pick up the new schedule automatically on the next page load, no reactivation needed.<\/li>\n<\/ul>\n\n<h4>1.0.58<\/h4>\n\n<ul>\n<li>New: a document still converting now gets a real placeholder page on your own site the moment it's detected, instead of sending visitors to savoy.chat while it processes -- the same page updates in place with the finished accessible version once conversion completes, so the URL never changes.<\/li>\n<li>New: \"Sync All Documents\" button pulls in every document that finished converting server-side but hasn't synced to this site yet, in one click (previously required repeatedly clicking \"Refresh Statuses\").<\/li>\n<li>New: \"Reprocess All Documents\" button re-runs the full conversion pipeline on every document, with a warning since this uses real monthly quota.<\/li>\n<li>Fix: a server-side error (an expired subscription, a disabled account, an invalid key) always showed a generic \"Failed to...\" message with no explanation, hiding the real reason. Now shows the actual server response.<\/li>\n<li>Fix: silent-mode badge suppression, verified across every code path in the plugin, not just the one case previously fixed.<\/li>\n<\/ul>\n\n<h4>1.0.57<\/h4>\n\n<ul>\n<li>Fix: a PDF link rewritten while its accessible version was still processing always showed the accessibility badge icon, ignoring the \"Silent rewrite\" display mode setting -- the mode check only applied once a document was ready. Now respected in both states.<\/li>\n<\/ul>\n\n<h4>1.0.56<\/h4>\n\n<ul>\n<li>New: \"Clean Document Titles\" setting (off by default) drops the \".pdf\" file extension from an accessible document's page title and URL -- \"Employee-Handbook.pdf\" becomes a page titled \"Employee-Handbook\" at a matching URL, instead of literally including \".pdf\" in both.<\/li>\n<\/ul>\n\n<h4>1.0.55<\/h4>\n\n<ul>\n<li>Fix: PDF links placed in a widget (a sidebar Text widget, a footer Custom HTML block, or any block added via the Widgets screen) were never detected or rewritten to the accessible version, since widget content is stored separately from post\/page content. Now scanned and rewritten the same way.<\/li>\n<\/ul>\n\n<h4>1.0.54<\/h4>\n\n<ul>\n<li>Change: trimmed the Network Settings page copy.<\/li>\n<\/ul>\n\n<h4>1.0.53<\/h4>\n\n<ul>\n<li>Fix: corrected the Network Settings page copy, which incorrectly said Network Activate was required for a child site to inherit the network-wide key. Normal per-site activation is enough.<\/li>\n<\/ul>\n\n<h4>1.0.52<\/h4>\n\n<ul>\n<li>New: on WordPress Multisite, network admins can set one API key (Network Admin &gt; Savoy Accessible) that every site on the network uses automatically, no need to activate the plugin or enter a key on each individual site. A site can still connect its own separate key to override the network one just for itself.<\/li>\n<li>Fix: documents are now matched by their full URL instead of just their filename, so two different sites sharing one account (e.g. a multisite network) can each have a \"handbook.pdf\" without them being confused for the same document.<\/li>\n<\/ul>\n\n<h4>1.0.51<\/h4>\n\n<ul>\n<li>Fix: the WCAG validation check was testing the generated HTML in isolation, without the same  landmark both real viewer pages already wrap it in, causing a false \"Warnings\" score on nearly every document. Fixed so the check matches what visitors actually see.<\/li>\n<li>New: hover over a \"Warnings\" badge in the Documents list to see exactly what was flagged.<\/li>\n<li>Improvement: documents now always get exactly one heading (title), even short single-page letters that previously might have been generated without one.<\/li>\n<\/ul>\n\n<h4>1.0.50<\/h4>\n\n<ul>\n<li>Change: documents list defaults to 10 per page (was 25), and now shows \"Showing docs X - Y of Z\" instead of \"page X of Y\".<\/li>\n<li>New: a Per Page dropdown (10\/25\/50\/100) lets you choose how many documents to see at once.<\/li>\n<\/ul>\n\n<h4>1.0.49<\/h4>\n\n<ul>\n<li>New: Documents list is now paginated (25 per page, Previous\/Next), instead of silently cutting off after 100 documents. Sites with hundreds or thousands of PDFs can now see and manage all of them.<\/li>\n<li>New: \"Retry Failed Documents\" button, retries up to 10 failed documents at a time (click again for more) instead of retrying one at a time.<\/li>\n<li>Change: renamed \"Check for Update\" to \"Check for Plugin Update\" for clarity.<\/li>\n<\/ul>\n\n<h4>1.0.48<\/h4>\n\n<ul>\n<li>Fix: a crash in the backend conversion pipeline was causing \"Processing failed: cannot access local variable 'Site'...\" on every document for some sites. Backend-only bug, fixed server-side.<\/li>\n<li>Change: \"Refresh Statuses\" no longer reports newly-scanned PDFs for conversion as a side effect, it only checks the status of documents already submitted. Reporting new PDFs stays with \"Scan Now,\" where it belongs.<\/li>\n<\/ul>\n\n<h4>1.0.47<\/h4>\n\n<ul>\n<li>Fix: your own site's domain could get silently dropped from the PDF conversion allowlist if you clicked Save Settings before ever filling in Allowed Domains, blocking all PDF conversion until you noticed and re-added it by hand. Your own connected domain is now always allowed regardless of what's in that field.<\/li>\n<li>Change: removed the automatic status-check polling loop entirely. Statuses now only refresh once when you load this page, or when you click \"Refresh Statuses\"; no more background checking while the tab sits open.<\/li>\n<\/ul>\n\n<h4>1.0.46<\/h4>\n\n<ul>\n<li>Fix: a site with a large backlog of PDFs (100+) could bog down under the status-check polling. The admin page now checks statuses in small batches (a single combined request instead of one per document) once a minute instead of every 3 seconds, and only reloads the page when a status actually changes. Newly discovered PDFs are now also reported for conversion in small batches instead of all at once.<\/li>\n<\/ul>\n\n<h4>1.0.45<\/h4>\n\n<ul>\n<li>Added a tooltip on the \"X \/ Y documents this month\" usage count explaining that documents over 30 pages count as more than one conversion, so the number can run ahead of your actual document count.<\/li>\n<\/ul>\n\n<h4>1.0.44<\/h4>\n\n<ul>\n<li>New: reading preferences in the document viewer -- adjustable text size and a real high-contrast mode (pure black-on-white, not a color filter), both applied to the viewer's own semantic markup and remembered per visitor.<\/li>\n<\/ul>\n\n<h4>1.0.43<\/h4>\n\n<ul>\n<li>Change: rebranded from \"Savoy AI\" to \"Savoy\" throughout (plugin author field only -- no functional changes).<\/li>\n<\/ul>\n\n<h4>1.0.42<\/h4>\n\n<ul>\n<li>Change: the PDF domain allowlist now defaults to allowing only this site's own domain, instead of allowing every domain. Prevents the plugin from scanning and converting PDFs linked from unrelated sites. Your own domain is always allowed automatically; add others under Settings if you need to.<\/li>\n<li>Fix: the domain allowlist you configure is now synced to and enforced by the Savoy server too, not just used locally for link rewriting.<\/li>\n<\/ul>\n\n<h4>1.0.41<\/h4>\n\n<ul>\n<li>New: PDF domain allowlist \u2014 restrict link rewriting and scanning to specific domains. Prevents 403\/404 errors from off-site PDF links.<\/li>\n<\/ul>\n\n<h4>1.0.40<\/h4>\n\n<ul>\n<li>New: \"Silent rewrite\" link mode \u2014 rewrites PDF links to the accessible HTML viewer with no visual change to link text or styling.<\/li>\n<\/ul>\n\n<h4>1.0.39<\/h4>\n\n<ul>\n<li>Fix: database schema migrations now run automatically on plugin upgrade, not just on fresh activation. Fixes cases where columns added in recent releases (validation_score, etc.) were missing after an auto-update, which prevented processing progress from being stored and displayed.<\/li>\n<\/ul>\n\n<h4>1.0.38<\/h4>\n\n<ul>\n<li>New: WCAG validation score shown alongside each converted document (Pass \/ Warnings \/ Needs review), powered by axe-core.<\/li>\n<\/ul>\n\n<h4>1.0.37<\/h4>\n\n<ul>\n<li>Security: viewer URLs no longer contain the API key. The site ID (a read-only identifier) is used instead, so API keys are never exposed in browser history or server logs.<\/li>\n<\/ul>\n\n<h4>1.0.36<\/h4>\n\n<ul>\n<li>PDF links in navigation menus are now rewritten to point at the accessible HTML version, the same as links in post content.<\/li>\n<\/ul>\n\n<h4>1.0.35<\/h4>\n\n<ul>\n<li>When HTML is regenerated server-side, Refresh Statuses now detects the change and automatically re-syncs the accessible HTML to the WordPress post.<\/li>\n<\/ul>\n\n<h4>1.0.34<\/h4>\n\n<ul>\n<li>Error messages from document processing (e.g. broken PDF links, access errors) now persist in the database and display below the status badge in the documents list. Previously errors were only visible while the processing job was active.<\/li>\n<\/ul>\n\n<h4>1.0.33<\/h4>\n\n<ul>\n<li>Renamed plugin display name to Savoy Accessibility. No behavior changes.<\/li>\n<\/ul>\n\n<h4>1.0.32<\/h4>\n\n<ul>\n<li>Moved the three opt-in hardening styles (focus outline, reduced-motion, skip link) out of inline <code>&lt;style&gt;<\/code> tags and into the <code>wp_enqueue_scripts<\/code> pipeline via <code>wp_register_style()<\/code> and <code>wp_add_inline_style()<\/code>. No visual or behavioral changes.<\/li>\n<\/ul>\n\n<h4>1.0.31<\/h4>\n\n<ul>\n<li>Removed the small \"Powered by Savoy\" link from the document viewer's chat sidebar footer.<\/li>\n<li>Hardened the PDF link rewriter: only plugin-controlled attributes are emitted on rewritten links; link text passed through <code>wp_kses_post()<\/code>.<\/li>\n<li>Moved the document viewer's inline <code>&lt;style&gt;<\/code> and <code>&lt;script&gt;<\/code> blocks into properly enqueued asset files. PHP values supplied via <code>wp_localize_script()<\/code>.<\/li>\n<\/ul>\n\n<h4>1.0.30<\/h4>\n\n<ul>\n<li>Code quality: cleared WordPress.org plugin-check warnings. No behavior changes.<\/li>\n<\/ul>\n\n<h4>1.0.29<\/h4>\n\n<ul>\n<li>Documentation: rewrote readme to remove promotional superlatives and definitive compliance claims. No behavior changes.<\/li>\n<\/ul>\n\n<p>For the full changelog see <a href=\"https:\/\/plugins.svn.wordpress.org\/savoy-accessible\/trunk\/changelog.txt\">changelog.txt<\/a>.<\/p>","raw_excerpt":"Convert PDFs to WCAG-friendly HTML, run on-demand WCAG audits, and apply opt-in site-wide accessibility enhancements.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/302172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=302172"}],"author":[{"embeddable":true,"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/peteclark3"}],"wp:attachment":[{"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=302172"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=302172"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=302172"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=302172"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=302172"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/bho.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=302172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}