{"id":346979,"date":"2026-08-06T05:53:18","date_gmt":"2026-08-06T05:53:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/tidy-seo-ai-refresh-seo-content-audit\/"},"modified":"2026-08-25T08:14:34","modified_gmt":"2026-08-25T08:14:34","slug":"tidy-seo-ai-refresh","status":"publish","type":"plugin","link":"https:\/\/it.wordpress.org\/plugins\/tidy-seo-ai-refresh\/","author":23467890,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.7.8","stable_tag":"1.7.8","tested":"7.0.4","requires":"6.0","requires_php":"8.2","requires_plugins":null,"header_name":"Tidy SEO AI Refresh","header_author":"Pierre","header_description":"Audit your WordPress content for SEO freshness. Detects outdated articles, thin content, missing structure, and prioritizes what to update first.","assets_banners_color":"7a39c6","last_updated":"2026-08-25 08:14:34","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/tidyplugins.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":180,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.7.6":{"tag":"1.7.6","author":"pierreferrolliet","date":"2026-08-06 05:52:56"},"1.7.7":{"tag":"1.7.7","author":"pierreferrolliet","date":"2026-08-23 07:35:17"},"1.7.8":{"tag":"1.7.8","author":"pierreferrolliet","date":"2026-08-25 08:14:34"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3636131,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3636131,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3636131,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3636131,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3636131,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner.svg":{"filename":"banner.svg","revision":3636131,"resolution":false,"location":"assets","locale":false}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.7.6","1.7.7","1.7.8"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3636442,"resolution":"1","location":"assets","locale":"","width":1600,"height":950},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3636442,"resolution":"2","location":"assets","locale":"","width":1600,"height":950},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3636442,"resolution":"3","location":"assets","locale":"","width":1600,"height":1000}},"screenshots":{"1":"Audit dashboard \u2014 health grade, decay alerts, audit history and every post ranked by priority","2":"Orphan pages \u2014 published content with no incoming internal links","3":"Settings \u2014 audit frequency, detection modules and import from Rank Math or Yoast"}},"plugin_section":[262246],"plugin_tags":[19795,11223,250295,186,11421],"plugin_category":[55],"plugin_contributors":[259182],"plugin_business_model":[],"class_list":["post-346979","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-content-audit","plugin_tags-freshness","plugin_tags-outdated-content","plugin_tags-seo","plugin_tags-thin-content","plugin_category-seo-and-marketing","plugin_contributors-pierreferrolliet","plugin_committers-pierreferrolliet"],"banners":{"banner":"https:\/\/ps.w.org\/tidy-seo-ai-refresh\/assets\/banner-772x250.png?rev=3636131","banner_2x":"https:\/\/ps.w.org\/tidy-seo-ai-refresh\/assets\/banner-1544x500.png?rev=3636131","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/tidy-seo-ai-refresh\/assets\/icon.svg?rev=3636131","icon":"https:\/\/ps.w.org\/tidy-seo-ai-refresh\/assets\/icon.svg?rev=3636131","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/tidy-seo-ai-refresh\/assets\/screenshot-1.png?rev=3636442","caption":"Audit dashboard \u2014 health grade, decay alerts, audit history and every post ranked by priority"},{"src":"https:\/\/ps.w.org\/tidy-seo-ai-refresh\/assets\/screenshot-2.png?rev=3636442","caption":"Orphan pages \u2014 published content with no incoming internal links"},{"src":"https:\/\/ps.w.org\/tidy-seo-ai-refresh\/assets\/screenshot-3.png?rev=3636442","caption":"Settings \u2014 audit frequency, detection modules and import from Rank Math or Yoast"}],"raw_content":"<!--section=description-->\n<p>Tidy SEO AI Refresh scans all your published posts and pages, evaluates them against multiple SEO signals, and tells you exactly which content needs updating \u2014 and in what order.<\/p>\n\n<p>Stop guessing which articles to refresh. Tidy SEO AI Refresh gives each post a priority score based on:<\/p>\n\n<ul>\n<li><strong>Freshness<\/strong> \u2014 How long since the post was last updated<\/li>\n<li><strong>Outdated years<\/strong> \u2014 References to past years in titles or content (e.g. \"Best tools 2023\")<\/li>\n<li><strong>Thin content<\/strong> \u2014 Articles under 300 or 600 words<\/li>\n<li><strong>Heading structure<\/strong> \u2014 Missing or insufficient H2 headings<\/li>\n<li><strong>Images<\/strong> \u2014 Posts with no images<\/li>\n<li><strong>Internal links<\/strong> \u2014 Posts with zero or few internal links<\/li>\n<li><strong>FAQ section<\/strong> \u2014 Missing FAQ content<\/li>\n<li><strong>Schema markup<\/strong> \u2014 Missing FAQ\/HowTo structured data<\/li>\n<li><strong>Alt text quality<\/strong> \u2014 Generic or missing image alt attributes<\/li>\n<li><strong>Anchor text quality<\/strong> \u2014 Generic anchor text like \"click here\"<\/li>\n<\/ul>\n\n<h4>Key Features<\/h4>\n\n<ul>\n<li><strong>Priority dashboard<\/strong> \u2014 Posts sorted by urgency: Critical, High, Medium, Low<\/li>\n<li><strong>Health grade<\/strong> \u2014 Overall site content health from A (excellent) to E (needs work)<\/li>\n<li><strong>Automatic weekly audits<\/strong> \u2014 Runs in the background via WP-Cron<\/li>\n<li><strong>Per-post scoring<\/strong> \u2014 See exactly which signals are affecting each post<\/li>\n<li><strong>Dashboard widget<\/strong> \u2014 Quick health overview right on your WordPress dashboard<\/li>\n<li><strong>Batch processing<\/strong> \u2014 Handles large sites without timeout issues<\/li>\n<li><strong>Cannibalization detection<\/strong> \u2014 Finds posts competing for the same keywords; identifies a pillar\/hub or recommends creating one when 4+ posts share a topic<\/li>\n<li><strong>Orphan page detection<\/strong> \u2014 Lists published posts that no other page links to<\/li>\n<li><strong>Internal link suggestions<\/strong> \u2014 In the Gutenberg sidebar, get topically related posts to link from your draft (with 1-click insertion)<\/li>\n<li><strong>FAQ block pattern with auto-schema<\/strong> \u2014 Insert a \"FAQ section\" pattern; FAQPage JSON-LD is emitted automatically (cached on save, no front-end overhead)<\/li>\n<li><strong>Bulk anchor text rewrite<\/strong> \u2014 One click (or <code>wp tidy-seo-ai-refresh fix-anchors<\/code>) replaces \"click here\" \/ \"read more\" with the linked target's title for internal links<\/li>\n<li><strong>Bad anchors \/ bad alt text reports<\/strong> \u2014 Dedicated dashboard tabs listing posts that need attention<\/li>\n<li><strong>Utility page detection<\/strong> \u2014 Contact\/About\/Legal pages are scored against a relaxed template (they are short by design)<\/li>\n<\/ul>\n\n<h4>How It Works<\/h4>\n\n<ol>\n<li>Install and activate Tidy SEO AI Refresh<\/li>\n<li>Go to Tidy SEO AI Refresh &gt; Dashboard<\/li>\n<li>Click \"Run audit\"<\/li>\n<li>Review your posts sorted by priority<\/li>\n<li>Start updating your most critical content<\/li>\n<\/ol>\n\n<h4>More from Tidy Plugins<\/h4>\n\n<p>If you like this plugin, take a look at the rest of the Tidy suite:<\/p>\n\n<ul>\n<li><a href=\"https:\/\/wordpress.org\/plugins\/tidy-table-of-contents\/\">Tidy Table of Contents<\/a> \u2014 automatic, accessible table of contents<\/li>\n<li><a href=\"https:\/\/wordpress.org\/plugins\/tidy-draft-share\/\">Tidy Draft Share<\/a> \u2014 share drafts via secure, expiring preview links<\/li>\n<li><a href=\"https:\/\/wordpress.org\/plugins\/tidy-author-box\/\">Tidy Author Box<\/a> \u2014 author bio box with avatar and social links<\/li>\n<li><a href=\"https:\/\/wordpress.org\/plugins\/tidy-broken-link-scan\/\">Tidy Broken Link Scan<\/a> \u2014 find broken links and images, no external service<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>This plugin can connect to two third-party services. <strong>Both are strictly opt-in<\/strong>: no external request is made unless you have connected the corresponding account in the plugin settings.<\/p>\n\n<p><strong>Google Search Console API<\/strong> (organic search data, optional)\n* Hosts: <code>accounts.google.com\/o\/oauth2\/v2\/auth<\/code> (OAuth authorization page, browser redirect only), <code>oauth2.googleapis.com\/token<\/code> (token exchange and refresh), <code>www.googleapis.com\/webmasters\/v3\/sites\/&lt;your-site&gt;\/searchAnalytics\/query<\/code> (data fetch).\n* OAuth scope: <code>https:\/\/www.googleapis.com\/auth\/webmasters.readonly<\/code> (read-only access to your Search Console data).\n* What is sent: your OAuth client ID, client secret and refresh token (server side); search-performance queries scoped to the site URLs you have verified in Google Search Console (date range, query string, page URL).\n* When: only after you have completed the \"Connect Google Search Console\" flow in the plugin settings. Then, on demand when you open the Content Gap dashboard tab and automatically when the access token needs to be refreshed.\n* Privacy: https:\/\/policies.google.com\/privacy \u2014 Terms: https:\/\/policies.google.com\/terms<\/p>\n\n<p><strong>Anthropic Claude API<\/strong> (AI-generated FAQs, optional)\n* Host: <code>api.anthropic.com\/v1\/messages<\/code>.\n* What is sent: your Anthropic API key (header <code>x-api-key<\/code>), the model identifier (default <code>claude-sonnet-5<\/code>), the title and content of the WordPress post you target (truncated to ~12,000 characters), and a prompt asking Claude to generate FAQ entries grounded in that content.\n* When: only when you (or an administrator) explicitly run the WP-CLI command <code>wp tidy-seo-ai-refresh suggest-faq &lt;post_id&gt;<\/code> after entering an API key in the settings. No call happens automatically.\n* Privacy: https:\/\/www.anthropic.com\/legal\/privacy \u2014 Terms: https:\/\/www.anthropic.com\/legal\/consumer-terms<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>tidy-seo-ai-refresh<\/code> folder to <code>\/wp-content\/plugins\/<\/code><\/li>\n<li>Activate the plugin through the Plugins menu<\/li>\n<li>Navigate to Tidy SEO AI Refresh in the admin sidebar<\/li>\n<li>Click \"Run audit\" to scan your content<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20is%20the%20priority%20score%20calculated%3F\"><h3>How is the priority score calculated?<\/h3><\/dt>\n<dd><p>Each post is evaluated on ~10 SEO signals. Each signal adds points to the total score. Higher scores mean the post needs more urgent attention. Posts scoring 15+ are Critical, 10+ are High, 5+ are Medium, and below 5 are Low priority.<\/p><\/dd>\n<dt id=\"does%20it%20slow%20down%20my%20site%3F\"><h3>Does it slow down my site?<\/h3><\/dt>\n<dd><p>No. Tidy SEO AI Refresh only runs in the admin area and processes posts in small batches via WP-Cron to avoid timeouts. It does not affect frontend performance.<\/p><\/dd>\n<dt id=\"which%20post%20types%20are%20audited%3F\"><h3>Which post types are audited?<\/h3><\/dt>\n<dd><p>Currently, posts and pages. Support for custom post types is planned for a future release.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20yoast%20seo%20or%20rank%20math%3F\"><h3>Does it work with Yoast SEO or Rank Math?<\/h3><\/dt>\n<dd><p>Yes. Tidy SEO AI Refresh reads meta descriptions from Yoast SEO and Rank Math when available. It also detects Yoast FAQ and HowTo schema blocks.<\/p><\/dd>\n<dt id=\"how%20often%20does%20the%20automatic%20audit%20run%3F\"><h3>How often does the automatic audit run?<\/h3><\/dt>\n<dd><p>Once per week via WP-Cron. You can also trigger a manual audit at any time from the dashboard.<\/p><\/dd>\n<dt id=\"do%20i%20need%20an%20api%20key%20to%20use%20the%20plugin%3F\"><h3>Do I need an API key to use the plugin?<\/h3><\/dt>\n<dd><p>No. The audit, the scores, the orphan-page and cannibalization detection all run locally with no key and no external call. A Claude API key is only needed if you want the optional FAQ generation.<\/p><\/dd>\n<dt id=\"what%20is%20an%20orphan%20page%3F\"><h3>What is an orphan page?<\/h3><\/dt>\n<dd><p>A published page that no other page on your site links to. Search engines reach it only through the sitemap, and readers essentially never do. It is usually the cheapest SEO fix available: add a couple of internal links from related articles.<\/p><\/dd>\n<dt id=\"what%20is%20keyword%20cannibalization%3F\"><h3>What is keyword cannibalization?<\/h3><\/dt>\n<dd><p>Two or more of your own pages competing for the same query. They split the clicks and the authority instead of concentrating them. The plugin groups the pages that overlap so you can merge them or differentiate them.<\/p><\/dd>\n<dt id=\"what%20does%20content%20decay%20mean%20here%3F\"><h3>What does content decay mean here?<\/h3><\/dt>\n<dd><p>A post whose grade has dropped since the previous audit \u2014 because it aged, because references to past years became stale, or because its internal links disappeared. The dashboard flags what got worse rather than making you re-read everything.<\/p><\/dd>\n<dt id=\"why%20is%20my%20score%20so%20low%20on%20a%20brand-new%20site%3F\"><h3>Why is my score so low on a brand-new site?<\/h3><\/dt>\n<dd><p>The score rewards depth and internal linking, which a young site has not built yet. Short posts with no incoming links score low by design. Track the trend across audits rather than the absolute number.<\/p><\/dd>\n<dt id=\"does%20the%20audit%20slow%20down%20my%20site%3F\"><h3>Does the audit slow down my site?<\/h3><\/dt>\n<dd><p>No. It runs in the background in batches through WP-Cron, and nothing is computed while a visitor is loading a page. You can also switch it to manual only.<\/p><\/dd>\n<dt id=\"can%20i%20import%20the%20keywords%20i%20already%20set%20in%20yoast%20or%20rank%20math%3F\"><h3>Can I import the keywords I already set in Yoast or Rank Math?<\/h3><\/dt>\n<dd><p>Yes, in one click from Settings. Focus keywords, secondary keywords and meta descriptions are copied over, and posts already scored by this plugin are skipped.<\/p><\/dd>\n<dt id=\"is%20google%20search%20console%20required%3F\"><h3>Is Google Search Console required?<\/h3><\/dt>\n<dd><p>No. Connecting it adds real impression and click data to the analysis, but every detection works without it.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.7.8<\/h4>\n\n<ul>\n<li>Fixed: a FAQ answer containing a double quote left the cached FAQPage schema unparsable, and the page then printed a bare \"null\" script that Search Console flagged as an invalid top-level element. The schema is slashed before it is stored, and a cached value that no longer parses is skipped instead of printed.<\/li>\n<\/ul>\n\n<h4>1.7.7<\/h4>\n\n<ul>\n<li>Fixed: the readability check was stuck on a half score for every post. It called a method that did not exist, so the guard around it always failed. Reading ease is now computed, with the Kandel &amp; Moles coefficients on French sites.<\/li>\n<li>Fixed: the focus keyword is matched the way a search engine reads it. A plural (\"short\" vs \"shorts\") or a filler word (\"sac \u00e0 dos randonn\u00e9e\" vs \"sac \u00e0 dos de randonn\u00e9e\") no longer counts as a miss, and matching is case-insensitive on accented capitals.<\/li>\n<li>Fixed: the H1 check reads the post title when the content carries no <code>&lt;h1&gt;<\/code>, which is what most themes render anyway. Posts were capped at half the weight with no way to fix it.<\/li>\n<li>Changed: a check that cannot apply to a post now leaves the total instead of costing half its weight. This covers secondary keywords when none are set, and the two image checks on short posts.<\/li>\n<li>Changed: an article over 500 words with no image at all now fails the image checks rather than skipping them.<\/li>\n<li>Fixed: an alt attribute containing an apostrophe was read up to that apostrophe only, so the image counted as having no alt at all. This affected both the keyword checks and the \"bad alt text\" audit report.<\/li>\n<li>Fixed: the meta description is now read from the SEO plugin that is actually active. On a site migrated from Yoast to Rank Math, the leftover Yoast meta was scored instead of the description really served. A stored value made only of template variables (%%excerpt%%, %title%) counts as absent.<\/li>\n<\/ul>\n\n<h4>1.7.6<\/h4>\n\n<ul>\n<li>Renamed to \"Tidy SEO AI Refresh\" (the descriptive suffix is gone from the display name).<\/li>\n<li>The posts-list grade styles and the settings importer script are now properly registered and enqueued instead of being printed inline.<\/li>\n<li>The <code>tsar_save_settings<\/code> action receives an unslashed, sanitized copy of the submitted form instead of the raw <code>$_POST<\/code> superglobal.<\/li>\n<li>Editor-side REST endpoints (live keyword score, internal link suggestions) now check <code>edit_post<\/code> on the target post instead of <code>manage_options<\/code>, so authors and editors can use the sidebar. Live scoring no longer writes the meta description as a side effect.<\/li>\n<li>Post meta authorization is now checked per post rather than globally.<\/li>\n<\/ul>\n\n<h4>1.7.5<\/h4>\n\n<ul>\n<li>The FAQ generator no longer sends a <code>temperature<\/code> parameter: recent Claude models reject sampling parameters, which made the request fail for anyone who had selected one in the settings. Grounding is enforced by the prompt.<\/li>\n<li>Default Claude model updated to <code>claude-sonnet-5<\/code>, and the documented default now matches the code.<\/li>\n<li>The review prompt now waits for real usage: it only appears on the plugin screens, once at least three content audits have completed, and it states how many.<\/li>\n<\/ul>\n\n<h4>1.7.4<\/h4>\n\n<ul>\n<li>WordPress.org coding-standards hardening: output escaping and translators comments for i18n placeholders (Plugin Check compliance).<\/li>\n<\/ul>\n\n<h4>1.7.3<\/h4>\n\n<ul>\n<li>Added the required \"External services\" section to readme.txt documenting Google Search Console and Anthropic Claude API calls (WordPress.org guideline 6 compliance). No code change.<\/li>\n<\/ul>\n\n<h4>1.7.2<\/h4>\n\n<ul>\n<li>Remove the <code>load_plugin_textdomain()<\/code> call now that translations are auto-loaded by WordPress.org since WP 4.6.<\/li>\n<\/ul>\n\n<h4>1.7.0<\/h4>\n\n<ul>\n<li>New WP-CLI command <code>wp tidy-seo-ai-refresh suggest-faq &lt;post_id&gt; [--apply] [--count=N] [--language=fr|en] [--model=&lt;id&gt;]<\/code> \u2014 calls the Claude API to generate 3-5 questions a real reader would ask after reading the post, with concise answers grounded only in the post. Use without <code>--apply<\/code> to preview, with <code>--apply<\/code> to append the FAQ block to the post (a WP revision is created so you can roll back).<\/li>\n<li>New settings card \"Claude API\" \u2014 API key (sk-ant-\u2026) and model selector. Default model: <code>claude-haiku-4-5<\/code> (fast and inexpensive).<\/li>\n<li>New <code>--fix-external<\/code> flag on <code>fix-anchors<\/code> \u2014 also rewrites anchor text on external links using a host+slug heuristic. Built-in mappings for UTMB, Decathlon, Wikipedia, Strava, Western States, Hardrock, Diagonale des Fous, Sant\u00e9 Magazine, MovePainFree.<\/li>\n<\/ul>\n\n<h4>1.6.0<\/h4>\n\n<ul>\n<li>New dashboard tabs <strong>Bad anchors<\/strong> and <strong>Bad images<\/strong>, listing affected posts with quick-edit links.<\/li>\n<li>New \"Fix all internal anchors\" button on the Bad anchors tab \u2014 replaces \"click here\" style anchors with the target post's title in one click. Skips external links (need human review).<\/li>\n<li>Cannibalization tab now surfaces <strong>hub detection<\/strong>: groups of 4+ competing posts highlight either an existing pillar (<code>merge_under_hub<\/code>) or recommend creating one (<code>create_hub<\/code>) with a one-click \"Create pillar page\" button.<\/li>\n<li>New WP-CLI command <code>wp tidy-seo-ai-refresh rebuild-faq-cache<\/code> \u2014 backfills the FAQ schema cache on existing posts that already use the FAQ block pattern.<\/li>\n<li>New REST endpoints <code>\/bad-anchors<\/code>, <code>\/bad-images<\/code>, <code>\/link-suggestions\/{post_id}<\/code>, <code>\/fix-anchors<\/code> for programmatic access.<\/li>\n<li>Refactor: extracted anchor rewriting into <code>TSAR_Anchor_Fixer<\/code> (shared between WP-CLI and REST).<\/li>\n<li>Tests: 28 new PHPUnit cases covering utility page detection, year cutoff, cannibalization tokenizer, FAQ extractor and link-suggester tokenizer.<\/li>\n<\/ul>\n\n<h4>1.5.1<\/h4>\n\n<ul>\n<li><strong>Perf<\/strong>: <code>wp_head<\/code> no longer runs <code>apply_filters('the_content')<\/code> to detect FAQ structure. The FAQPage JSON-LD is computed once on <code>save_post<\/code> and cached in post meta <code>_tsar_faq_schema<\/code>. Cheap regex pre-check (<code>TSAR_FAQ::content_might_contain_faq<\/code>) bails out before any DOM work \u2014 used both at save and during audits.<\/li>\n<li>Removed all rendering and scaffolding code for premium-only features (AI rewrite, bulk rewrite queue, schedule publish, CSV export, rewrites database table). The free plugin now ships only the documented audit features. Premium features are implemented entirely in the companion Pro plugin via standard extension hooks (<code>tsar_dashboard_toolbar<\/code>, <code>tsar_dashboard_after_toolbar<\/code>, <code>tsar_dashboard_row_actions<\/code>, <code>tsar_dashboard_after_page<\/code>, <code>tsar_admin_localize_data<\/code>, <code>tsar_after_install<\/code>).<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>New <strong>\"Suggested internal links\"<\/strong> panel in the Gutenberg sidebar \u2014 fetches topically related posts (via focus\/secondary keyword token overlap) and inserts a paragraph block with the link in 1 click.<\/li>\n<li>WP-CLI subcommands now use hyphens: <code>wp tidy-seo-ai-refresh fix-anchors<\/code> (was <code>fix_anchors<\/code>). Each subcommand is registered explicitly to keep the public command surface clean.<\/li>\n<li>Scorer: <code>outdated_refs<\/code> is bypassed for posts modified within the last 30 days \u2014 old years in the body are intentional when the author has just reviewed (book editions, historical references). <code>outdated_title<\/code> still triggers because the title is a public freshness signal.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>New <code>bad_anchors_json<\/code> and <code>bad_images_json<\/code> columns in <code>tsar_scores<\/code> \u2014 the scorer now persists the offending anchors\/images so they can be queried in bulk.<\/li>\n<li>New REST endpoints <code>\/bad-anchors<\/code> and <code>\/bad-images<\/code> listing posts with poor anchor text or missing\/generic alt text.<\/li>\n<li>New <code>TSAR_Link_Suggester<\/code> \u2014 given a post ID, returns N candidate posts to link based on focus\/secondary keyword overlap (Jaccard on tokens). Endpoint <code>\/link-suggestions\/{post_id}<\/code>.<\/li>\n<li>New cannibalization <strong>hub detection<\/strong>: groups with 4+ posts that suggest merging now identify a pillar post (when a generic-titled candidate exists) or suggest creating a new one with a recommended title.<\/li>\n<li>New <code>TSAR_FAQ<\/code> \u2014 block pattern \"FAQ section (with auto schema)\" plus automatic FAQPage JSON-LD emission. The scorer credits posts that use this pattern.<\/li>\n<li>New WP-CLI command <code>wp tidy-seo-ai-refresh fix-anchors [--dry-run] [--limit=N]<\/code> to bulk-replace generic anchors with the linked target's title (internal links only).<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>New content type <code>utility<\/code> automatically detected for boilerplate pages (Contact, About, Legal, T&amp;C, Privacy, Sitemap, Jobs, Contributors). Editorial signals (thin content, missing FAQ, schema, internal links, alt text) are zeroed-out for these pages \u2014 only freshness, outdated references and generic anchors remain. Utility pages no longer dominate the Critical list.<\/li>\n<li><code>outdated_refs<\/code> cutoff is now dynamic: only years older than <code>current_year - 2<\/code> are flagged. Recent years (2024\/2025\/2026 in 2026) are no longer false positives in book editions, comparisons, etc.<\/li>\n<li>Cannibalization tokenizer now strips 4-digit years (1900-2099) from n-grams so unrelated comparison articles published the same year (e.g. \"trail 2026\", \"v\u00e9lo comparatif 2026\") are no longer grouped together.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Added a Rank Math \/ Yoast-style <strong>per-post keyword scorer<\/strong>: focus keyword + secondary keywords + meta description, weighted across 21 SEO checks (keyword in title\/slug\/H1\/first paragraph\/meta-desc\/body\/density\/sub-headings\/alt; title length, meta-desc length, slug length, title-starts-with-focus, sub-headings, min word count, alt text filled, internal\/outbound links, readability).<\/li>\n<li>New per-post <strong>A\u2013E grade pill in the posts list<\/strong> (sortable column).<\/li>\n<li>New <strong>classic-editor meta box<\/strong> with live checks as you type.<\/li>\n<li>New <strong>Gutenberg block-editor sidebar<\/strong> with the same live grade and checklist.<\/li>\n<li>New <strong>REST endpoint<\/strong> <code>\/score-live<\/code> (used by the metabox + sidebar).<\/li>\n<li>New <strong>importer<\/strong> from Rank Math and Yoast SEO (focus + secondary keywords + meta description) \u2014 admin button + WP-CLI command (<code>wp tidy-seo-ai-refresh import rankmath|yoast<\/code>).<\/li>\n<li>New WP-CLI command <code>wp tidy-seo-ai-refresh rescore<\/code> to re-run the scorer on every post.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Removed all licence checks and premium-feature gating from the free plugin code (AI rewriter, bulk rewriter, scheduled publishing and CSV export are now distributed via a separate companion plugin).<\/li>\n<li>Added extension hooks for add-on plugins (<code>tsar_settings_form_extra<\/code>, <code>tsar_settings_sidebar<\/code>, <code>tsar_admin_localize_data<\/code>, <code>tsar_plugin_action_links<\/code>, <code>tsar_save_settings<\/code>, <code>tsar_is_pro<\/code>).<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>Content scoring engine with 10+ SEO signals<\/li>\n<li>Priority dashboard with health grade (A-E)<\/li>\n<li>Automatic weekly audits via WP-Cron<\/li>\n<li>Dashboard widget for quick health overview<\/li>\n<li>REST API for programmatic access<\/li>\n<li>Batch processing for large sites<\/li>\n<\/ul>","raw_excerpt":"Audit your WordPress content for SEO freshness. Detects outdated articles, thin content, missing structure, and prioritizes what to update first.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/346979","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=346979"}],"author":[{"embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pierreferrolliet"}],"wp:attachment":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=346979"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=346979"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=346979"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=346979"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=346979"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=346979"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}