=== Tidy SEO AI Refresh ===
Contributors: pierreferrolliet
Tags: seo, content audit, freshness, outdated content, thin content
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 8.2
Stable tag: 1.7.6
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Audit your WordPress content for SEO freshness. Detects outdated articles, thin content, missing structure, and prioritizes what to update first.

== Description ==

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 — and in what order.

Stop guessing which articles to refresh. Tidy SEO AI Refresh gives each post a priority score based on:

* **Freshness** — How long since the post was last updated
* **Outdated years** — References to past years in titles or content (e.g. "Best tools 2023")
* **Thin content** — Articles under 300 or 600 words
* **Heading structure** — Missing or insufficient H2 headings
* **Images** — Posts with no images
* **Internal links** — Posts with zero or few internal links
* **FAQ section** — Missing FAQ content
* **Schema markup** — Missing FAQ/HowTo structured data
* **Alt text quality** — Generic or missing image alt attributes
* **Anchor text quality** — Generic anchor text like "click here"

= Key Features =

* **Priority dashboard** — Posts sorted by urgency: Critical, High, Medium, Low
* **Health grade** — Overall site content health from A (excellent) to E (needs work)
* **Automatic weekly audits** — Runs in the background via WP-Cron
* **Per-post scoring** — See exactly which signals are affecting each post
* **Dashboard widget** — Quick health overview right on your WordPress dashboard
* **Batch processing** — Handles large sites without timeout issues
* **Cannibalization detection** — Finds posts competing for the same keywords; identifies a pillar/hub or recommends creating one when 4+ posts share a topic
* **Orphan page detection** — Lists published posts that no other page links to
* **Internal link suggestions** — In the Gutenberg sidebar, get topically related posts to link from your draft (with 1-click insertion)
* **FAQ block pattern with auto-schema** — Insert a "FAQ section" pattern; FAQPage JSON-LD is emitted automatically (cached on save, no front-end overhead)
* **Bulk anchor text rewrite** — One click (or `wp tidy-seo-ai-refresh fix-anchors`) replaces "click here" / "read more" with the linked target's title for internal links
* **Bad anchors / bad alt text reports** — Dedicated dashboard tabs listing posts that need attention
* **Utility page detection** — Contact/About/Legal pages are scored against a relaxed template (they are short by design)

= How It Works =

1. Install and activate Tidy SEO AI Refresh
2. Go to Tidy SEO AI Refresh > Dashboard
3. Click "Run audit"
4. Review your posts sorted by priority
5. Start updating your most critical content

= More from Tidy Plugins =

If you like this plugin, take a look at the rest of the Tidy suite:

* [Tidy Table of Contents](https://wordpress.org/plugins/tidy-table-of-contents/) — automatic, accessible table of contents
* [Tidy Draft Share](https://wordpress.org/plugins/tidy-draft-share/) — share drafts via secure, expiring preview links
* [Tidy Author Box](https://wordpress.org/plugins/tidy-author-box/) — author bio box with avatar and social links
* [Tidy Broken Link Scan](https://wordpress.org/plugins/tidy-broken-link-scan/) — find broken links and images, no external service


== Installation ==

1. Upload the `tidy-seo-ai-refresh` folder to `/wp-content/plugins/`
2. Activate the plugin through the Plugins menu
3. Navigate to Tidy SEO AI Refresh in the admin sidebar
4. Click "Run audit" to scan your content

== Frequently Asked Questions ==

= How is the priority score calculated? =

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.

= Does it slow down my site? =

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.

= Which post types are audited? =

Currently, posts and pages. Support for custom post types is planned for a future release.

= Does it work with Yoast SEO or Rank Math? =

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.

= How often does the automatic audit run? =

Once per week via WP-Cron. You can also trigger a manual audit at any time from the dashboard.

== External services ==

This plugin can connect to two third-party services. **Both are strictly opt-in**: no external request is made unless you have connected the corresponding account in the plugin settings.

**Google Search Console API** (organic search data, optional)
* Hosts: `accounts.google.com/o/oauth2/v2/auth` (OAuth authorization page, browser redirect only), `oauth2.googleapis.com/token` (token exchange and refresh), `www.googleapis.com/webmasters/v3/sites/<your-site>/searchAnalytics/query` (data fetch).
* OAuth scope: `https://www.googleapis.com/auth/webmasters.readonly` (read-only access to your Search Console data).
* 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).
* 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.
* Privacy: https://policies.google.com/privacy — Terms: https://policies.google.com/terms

**Anthropic Claude API** (AI-generated FAQs, optional)
* Host: `api.anthropic.com/v1/messages`.
* What is sent: your Anthropic API key (header `x-api-key`), the model identifier (default `claude-sonnet-5`), 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.
* When: only when you (or an administrator) explicitly run the WP-CLI command `wp tidy-seo-ai-refresh suggest-faq <post_id>` after entering an API key in the settings. No call happens automatically.
* Privacy: https://www.anthropic.com/legal/privacy — Terms: https://www.anthropic.com/legal/consumer-terms

== Screenshots ==

1. Content audit dashboard with health score, audit history and prioritized issues
2. Orphan pages — published content nothing else on the site links to
3. Settings — audit frequency, detection modules and SEO plugin import

== Changelog ==

= 1.7.6 =
* Renamed to "Tidy SEO AI Refresh" (the descriptive suffix is gone from the display name).
* The posts-list grade styles and the settings importer script are now properly registered and enqueued instead of being printed inline.
* The `tsar_save_settings` action receives an unslashed, sanitized copy of the submitted form instead of the raw `$_POST` superglobal.
* Editor-side REST endpoints (live keyword score, internal link suggestions) now check `edit_post` on the target post instead of `manage_options`, so authors and editors can use the sidebar. Live scoring no longer writes the meta description as a side effect.
* Post meta authorization is now checked per post rather than globally.

= 1.7.5 =
* The FAQ generator no longer sends a `temperature` 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.
* Default Claude model updated to `claude-sonnet-5`, and the documented default now matches the code.
* 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.

= 1.7.4 =
* WordPress.org coding-standards hardening: output escaping and translators comments for i18n placeholders (Plugin Check compliance).

= 1.7.3 =
* 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.

= 1.7.2 =
* Remove the `load_plugin_textdomain()` call now that translations are auto-loaded by WordPress.org since WP 4.6.

= 1.7.0 =
* New WP-CLI command `wp tidy-seo-ai-refresh suggest-faq <post_id> [--apply] [--count=N] [--language=fr|en] [--model=<id>]` — 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 `--apply` to preview, with `--apply` to append the FAQ block to the post (a WP revision is created so you can roll back).
* New settings card "Claude API" — API key (sk-ant-…) and model selector. Default model: `claude-haiku-4-5` (fast and inexpensive).
* New `--fix-external` flag on `fix-anchors` — 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é Magazine, MovePainFree.

= 1.6.0 =
* New dashboard tabs **Bad anchors** and **Bad images**, listing affected posts with quick-edit links.
* New "Fix all internal anchors" button on the Bad anchors tab — replaces "click here" style anchors with the target post's title in one click. Skips external links (need human review).
* Cannibalization tab now surfaces **hub detection**: groups of 4+ competing posts highlight either an existing pillar (`merge_under_hub`) or recommend creating one (`create_hub`) with a one-click "Create pillar page" button.
* New WP-CLI command `wp tidy-seo-ai-refresh rebuild-faq-cache` — backfills the FAQ schema cache on existing posts that already use the FAQ block pattern.
* New REST endpoints `/bad-anchors`, `/bad-images`, `/link-suggestions/{post_id}`, `/fix-anchors` for programmatic access.
* Refactor: extracted anchor rewriting into `TSAR_Anchor_Fixer` (shared between WP-CLI and REST).
* Tests: 28 new PHPUnit cases covering utility page detection, year cutoff, cannibalization tokenizer, FAQ extractor and link-suggester tokenizer.

= 1.5.1 =
* **Perf**: `wp_head` no longer runs `apply_filters('the_content')` to detect FAQ structure. The FAQPage JSON-LD is computed once on `save_post` and cached in post meta `_tsar_faq_schema`. Cheap regex pre-check (`TSAR_FAQ::content_might_contain_faq`) bails out before any DOM work — used both at save and during audits.
* 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 (`tsar_dashboard_toolbar`, `tsar_dashboard_after_toolbar`, `tsar_dashboard_row_actions`, `tsar_dashboard_after_page`, `tsar_admin_localize_data`, `tsar_after_install`).

= 1.5.0 =
* New **"Suggested internal links"** panel in the Gutenberg sidebar — fetches topically related posts (via focus/secondary keyword token overlap) and inserts a paragraph block with the link in 1 click.
* WP-CLI subcommands now use hyphens: `wp tidy-seo-ai-refresh fix-anchors` (was `fix_anchors`). Each subcommand is registered explicitly to keep the public command surface clean.
* Scorer: `outdated_refs` is bypassed for posts modified within the last 30 days — old years in the body are intentional when the author has just reviewed (book editions, historical references). `outdated_title` still triggers because the title is a public freshness signal.

= 1.4.0 =
* New `bad_anchors_json` and `bad_images_json` columns in `tsar_scores` — the scorer now persists the offending anchors/images so they can be queried in bulk.
* New REST endpoints `/bad-anchors` and `/bad-images` listing posts with poor anchor text or missing/generic alt text.
* New `TSAR_Link_Suggester` — given a post ID, returns N candidate posts to link based on focus/secondary keyword overlap (Jaccard on tokens). Endpoint `/link-suggestions/{post_id}`.
* New cannibalization **hub detection**: 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.
* New `TSAR_FAQ` — block pattern "FAQ section (with auto schema)" plus automatic FAQPage JSON-LD emission. The scorer credits posts that use this pattern.
* New WP-CLI command `wp tidy-seo-ai-refresh fix-anchors [--dry-run] [--limit=N]` to bulk-replace generic anchors with the linked target's title (internal links only).

= 1.3.0 =
* New content type `utility` automatically detected for boilerplate pages (Contact, About, Legal, T&C, Privacy, Sitemap, Jobs, Contributors). Editorial signals (thin content, missing FAQ, schema, internal links, alt text) are zeroed-out for these pages — only freshness, outdated references and generic anchors remain. Utility pages no longer dominate the Critical list.
* `outdated_refs` cutoff is now dynamic: only years older than `current_year - 2` are flagged. Recent years (2024/2025/2026 in 2026) are no longer false positives in book editions, comparisons, etc.
* 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élo comparatif 2026") are no longer grouped together.

= 1.2.0 =
* Added a Rank Math / Yoast-style **per-post keyword scorer**: 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).
* New per-post **A–E grade pill in the posts list** (sortable column).
* New **classic-editor meta box** with live checks as you type.
* New **Gutenberg block-editor sidebar** with the same live grade and checklist.
* New **REST endpoint** `/score-live` (used by the metabox + sidebar).
* New **importer** from Rank Math and Yoast SEO (focus + secondary keywords + meta description) — admin button + WP-CLI command (`wp tidy-seo-ai-refresh import rankmath|yoast`).
* New WP-CLI command `wp tidy-seo-ai-refresh rescore` to re-run the scorer on every post.

= 1.1.1 =
* 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).
* Added extension hooks for add-on plugins (`tsar_settings_form_extra`, `tsar_settings_sidebar`, `tsar_admin_localize_data`, `tsar_plugin_action_links`, `tsar_save_settings`, `tsar_is_pro`).

= 1.0.0 =
* Initial release
* Content scoring engine with 10+ SEO signals
* Priority dashboard with health grade (A-E)
* Automatic weekly audits via WP-Cron
* Dashboard widget for quick health overview
* REST API for programmatic access
* Batch processing for large sites
