{"id":360598,"date":"2026-09-03T21:22:48","date_gmt":"2026-09-03T21:22:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/fifteenth-labs-ai-search-ready\/"},"modified":"2026-09-03T21:51:26","modified_gmt":"2026-09-03T21:51:26","slug":"fifteenth-labs-ai-search-ready","status":"publish","type":"plugin","link":"https:\/\/azb.wordpress.org\/plugins\/fifteenth-labs-ai-search-ready\/","author":23555290,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.2","stable_tag":"1.2.2","tested":"7.1","requires":"5.8","requires_php":"7.4","requires_plugins":null,"header_name":"Fifteenth Labs AI Search Ready","header_author":"Fifteenth Labs","header_description":"This plugin doesn't get your content found by AI search \u2014 your content does. It checks your content against an AI-readiness framework (structured data, content quality, semantic structure, technical crawlability) and shows exactly what to fix.","assets_banners_color":"1e1c1a","last_updated":"2026-09-03 21:51:26","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/fifteenthlabs.com\/products\/ai-search-ready","header_author_uri":"https:\/\/fifteenthlabs.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":66,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.2.1":{"tag":"1.2.1","author":"fifteenthlabs","date":"2026-09-03 21:22:14","revision":3680414},"1.2.2":{"tag":"1.2.2","author":"fifteenthlabs","date":"2026-09-03 21:51:26","revision":3680444}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3680444,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3680444,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3680444,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3680444,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.2.1","1.2.2"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3680444,"resolution":"1","location":"assets","locale":"","width":1920,"height":919},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3680444,"resolution":"2","location":"assets","locale":"","width":1920,"height":919},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3680444,"resolution":"3","location":"assets","locale":"","width":1920,"height":919}},"screenshots":{"1":"The AI Search Ready dashboard shows your site's average readiness score at a glance, with pages grouped into AI Ready, Getting There, and Needs Work.","2":"A real-time AI Search Readiness score appears right in the page editor, broken down by structured data, content quality, semantic structure, meta discoverability, and technical readiness.","3":"Every page gets a full action plan \u2014 critical fixes, high-priority improvements, and an estimated score after applying them, each with clear how-to-fix guidance."}},"plugin_section":[],"plugin_tags":[2353,127657,944,186,1121],"plugin_category":[55],"plugin_contributors":[277705],"plugin_business_model":[],"class_list":["post-360598","plugin","type-plugin","status-publish","hentry","plugin_tags-ai","plugin_tags-content-analysis","plugin_tags-search","plugin_tags-seo","plugin_tags-structured-data","plugin_category-seo-and-marketing","plugin_contributors-fifteenthlabs","plugin_committers-fifteenthlabs"],"banners":{"banner":"https:\/\/ps.w.org\/fifteenth-labs-ai-search-ready\/assets\/banner-772x250.png?rev=3680444","banner_2x":"https:\/\/ps.w.org\/fifteenth-labs-ai-search-ready\/assets\/banner-1544x500.png?rev=3680444","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/fifteenth-labs-ai-search-ready\/assets\/icon-128x128.png?rev=3680444","icon_2x":"https:\/\/ps.w.org\/fifteenth-labs-ai-search-ready\/assets\/icon-256x256.png?rev=3680444","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/fifteenth-labs-ai-search-ready\/assets\/screenshot-1.png?rev=3680444","caption":"The AI Search Ready dashboard shows your site's average readiness score at a glance, with pages grouped into AI Ready, Getting There, and Needs Work."},{"src":"https:\/\/ps.w.org\/fifteenth-labs-ai-search-ready\/assets\/screenshot-2.png?rev=3680444","caption":"A real-time AI Search Readiness score appears right in the page editor, broken down by structured data, content quality, semantic structure, meta discoverability, and technical readiness."},{"src":"https:\/\/ps.w.org\/fifteenth-labs-ai-search-ready\/assets\/screenshot-3.png?rev=3680444","caption":"Every page gets a full action plan \u2014 critical fixes, high-priority improvements, and an estimated score after applying them, each with clear how-to-fix guidance."}],"raw_content":"<!--section=description-->\n<p><strong>This plugin doesn't get your content found by AI search \u2014 your content does.<\/strong> What AI systems (ChatGPT, Perplexity, Google AI Overviews, etc.) actually find, understand, and cite is the substance and structure of what you've written. This plugin can't change that; what it does is check your content against a framework of structure, clarity, and technical signals, and show you specifically what to fix \u2014 a checklist and a set of concrete edits, not a shortcut around doing the work.<\/p>\n\n<p><strong>Fifteenth Labs AI Search Ready<\/strong> analyzes your WordPress content against an AI-readiness framework covering structured data, content quality, semantic structure, and technical crawlability. Your score reflects how well your content matches these signals, based on this plugin's own scoring methodology \u2014 it is not a live measurement of how any specific AI system will treat your content, and is not a guarantee of visibility, ranking, inclusion, or citation.<\/p>\n\n<h4>What It Checks<\/h4>\n\n<p><strong>Structured Data (25% weight)<\/strong>\n* JSON-LD Schema.org markup (Article, FAQ, HowTo, etc.)\n* Relevant structured-data types\n* Author entity and E-E-A-T signals\n* Breadcrumb markup\n* Date metadata<\/p>\n\n<p><strong>Content Quality (30% weight)<\/strong>\n* Content length and depth\n* Flesch readability score\n* Opening paragraph clarity\n* Direct answer patterns (\"X is...\", \"Steps to...\")\n* Topic focus and keyword consistency\n* Specific evidence (stats, data, quotes)<\/p>\n\n<p><strong>Semantic Structure (20% weight)<\/strong>\n* Heading hierarchy (H2-H6)\n* Paragraph structure\n* List usage (ul\/ol)\n* Semantic HTML5 elements\n* Internal linking\n* Image alt text<\/p>\n\n<p><strong>Meta &amp; Discoverability (15% weight)<\/strong>\n* Title length and descriptiveness\n* Meta description\n* Taxonomy usage (categories + tags)\n* URL readability<\/p>\n\n<p><strong>Technical AI-Readiness (10% weight)<\/strong>\n* Crawl access (noindex check)\n* Server-rendered content\n* FAQ\/Q&amp;A patterns\n* Content navigation (anchor links)\n* Content freshness\n* OpenGraph tags<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li><strong>Per-post analysis<\/strong> via meta box in the post editor<\/li>\n<li><strong>Bulk analysis<\/strong> of all published content<\/li>\n<li><strong>Dashboard<\/strong> with site-wide score overview<\/li>\n<li><strong>AI Score column<\/strong> in post\/page list tables<\/li>\n<li><strong>Auto-analyze<\/strong> on publish\/update (configurable)<\/li>\n<li><strong>REST API<\/strong> for programmatic access<\/li>\n<li><strong>Prioritized recommendations<\/strong> sorted by impact<\/li>\n<\/ul>\n\n<h3>Important Note on Scoring<\/h3>\n\n<p>Fifteenth Labs AI Search Ready does not query ChatGPT, Perplexity, Google AI Overviews, or any other AI system to test how they treat your content. Scores are based on Fifteenth Labs AI Search Ready's own analysis framework \u2014 structured data, content quality, semantic structure, metadata, and technical crawlability \u2014 and are intended as guidance to help you improve your content's AI-readiness. They are not a guarantee of visibility, ranking, inclusion, or citation by any AI-powered search service.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>fifteenth-labs-ai-search-ready<\/code> folder to <code>\/wp-content\/plugins\/<\/code><\/li>\n<li>Activate the plugin through the 'Plugins' menu<\/li>\n<li>Go to <strong>Fifteenth Labs AI Search Ready \u2192 Dashboard<\/strong> to get started<\/li>\n<li>Edit any post\/page to see the AI Score meta box<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20replace%20my%20seo%20plugin%3F\"><h3>Does this replace my SEO plugin?<\/h3><\/dt>\n<dd><p>No. This plugin focuses specifically on AI-readiness \u2014 how well your content aligns with Fifteenth Labs AI Search Ready's framework for structure, clarity, metadata, and machine readability. It complements traditional SEO plugins.<\/p><\/dd>\n<dt id=\"will%20this%20plugin%20get%20my%20content%20found%20by%20ai%20search%3F\"><h3>Will this plugin get my content found by AI search?<\/h3><\/dt>\n<dd><p>No \u2014 and be wary of anything that claims it can. No plugin can guarantee that ChatGPT, Perplexity, Google AI Overviews, or any other AI system will find, use, or cite a specific page; none of them publish how they select sources, and that can change at any time. What actually determines whether AI systems find and use your content is the content itself \u2014 its substance, clarity, and structure. This plugin doesn't change your content for you. It checks it against a framework of structure and clarity signals, and shows you specifically what to fix. The work of writing genuinely useful, well-organized content is still yours to do; this just tells you where it currently falls short.<\/p><\/dd>\n<dt id=\"what%20score%20should%20i%20aim%20for%3F\"><h3>What score should I aim for?<\/h3><\/dt>\n<dd><p>80+ means your content passes most of Fifteenth Labs AI Search Ready's checks. 60\u201379 means there's room to improve. Below 60 flags significant gaps against the checklist. These thresholds are based on Fifteenth Labs AI Search Ready's own analysis framework and are intended as guidance \u2014 not a guarantee of visibility, ranking, inclusion, or citation by any AI-powered search service.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20yoast%2Frank%20math%3F\"><h3>Does it work with Yoast\/Rank Math?<\/h3><\/dt>\n<dd><p>Yes. It detects and accounts for structured data provided by major SEO plugins.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20send%20my%20content%20anywhere%3F\"><h3>Does this plugin send my content anywhere?<\/h3><\/dt>\n<dd><p>No. When analyzing a page, it may fetch that same page's own public URL \u2014 on your own site, nothing external \u2014 to read what's actually rendered there (useful for page builders and other content stored outside the standard editor field). No content, scores, or site data are ever sent to Fifteenth Labs, any third-party service, or any AI system. All analysis runs locally on your own server.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.2.1<\/h4>\n\n<ul>\n<li>Renamed the plugin to Fifteenth Labs AI Search Ready and updated Plugin URI \/ Author URI to fifteenthlabs.com, for directory submission consistency.<\/li>\n<li>Moved the Bulk Analyze and Email Report admin pages' inline scripts into properly enqueued files, with JSON_HEX_TAG protection on embedded report HTML.<\/li>\n<li>Scoped the admin stylesheet to only load on this plugin's own pages, the post editor, and post list screens, instead of every admin screen.<\/li>\n<li>Fixed the Installation section to reference the current folder name.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Prepared for public release: standardized plugin header, updated author\/contributor info<\/li>\n<li>Security: added object-level capability checks (edit_post per post ID) on single-post REST routes and the Action Plan admin page, preventing users from accessing or triggering analysis on posts they don't have permission to edit<\/li>\n<li>Fixed: the page classifier read raw post_content directly to detect empty\/placeholder pages, which misclassified any post type that stores its content outside the standard editor (e.g. custom post types with content in meta fields, some page builders) as an empty page and skipped analysis entirely \u2014 even when published with substantial real content. The classifier now uses the same resolved content (page builder aware, with a live-page-fetch fallback) that the rest of the analysis already relies on.<\/li>\n<li>Fixed: clicking \"Re-Analyze\" on the standalone Action Plan page correctly re-ran the analysis and updated the stored report, but the visible score circle, action list, and counts on that page never refreshed \u2014 they're server-rendered PHP with no matching live-update path, unlike the meta box and dashboard list table, which do update in place. A successful re-analyze on this page now reloads it so what's shown matches what was just calculated.<\/li>\n<li>Fixed: the JSON-LD Schema and Rich Schema Type checks never looked at the actual page \u2014 they guessed \"found\" from whether an SEO plugin's PHP constant was defined (regardless of whether that plugin outputs anything for this specific post) and guessed the schema @type from the post type name (Article for 'post', WebPage for 'page', nothing for anything else, including custom post types). Both checks now fetch the live page and read its real JSON-LD script blocks \u2014 including schema written to  dynamically by a theme, a custom post type's own schema code, or an SEO plugin \u2014 falling back to the old heuristic only if the fetch itself fails.<\/li>\n<li>Added: a \"Diagnose Content Resolution\" button on the Action Plan page, next to Re-Analyze. Runs the existing (previously REST-only) content-resolution diagnostic and shows the result inline \u2014 which strategy found the post's content, how much text it found, and what meta keys are involved \u2014 useful for confirming whether a low score is a real content gap or a resolution issue, without needing to construct and authenticate a REST request by hand.<\/li>\n<li>Fixed: content resolution tried a generic \"scan all post meta for the single longest field\" guess before trying to fetch and read the actual live page. That guess is right for BeTheme's one-big-serialized-blob storage pattern (what it was built for), but wrong for any post type that splits real content across several meaningful fields \u2014 like a case study with separate brief\/approach\/outcome fields \u2014 where it would silently keep only the single longest field and discard the rest, understating word count and missing all real headings (which only exist in the rendered template, not in any one raw field). The live-page fetch now runs first, since it reflects everything actually on the page regardless of how many fields feed it; the meta scan remains as a fallback for when the live fetch itself fails.<\/li>\n<li>Fixed: the FAQ-section suggestion (and its JSON-LD example) rendered with a blank topic \u2014 \"What is ?\" instead of \"What is X?\" \u2014 because generate_technical_actions() used $title without ever receiving it as a parameter. Silently undefined in PHP rather than an error, so it just came through empty. $title is now correctly passed through.<\/li>\n<li>Fixed: the Topic Focus check extracted \"keywords\" from the title using a plain word-length filter (anything over 3 characters) with no stopword list, so pure function words like \"that\" got treated as equally meaningful topic keywords as real subject nouns \u2014 most visible on titles written as full sentences rather than short topic phrases. Both the check and its action-plan suggestion text (previously two separate, silently-drifting copies of the same logic) now share one keyword-extraction helper with an actual stopword list.<\/li>\n<li>Fixed: the internal-links suggestion matched \"related\" posts by category, but WordPress automatically assigns any uncategorized post to a default \"Uncategorized\" category rather than leaving it with none \u2014 so any two posts that simply hadn't been categorized yet were treated as related to each other regardless of actual subject matter, surfacing suggestions with no real topical connection. The default category is no longer treated as a relatedness signal; a post falls back to the generic linking advice until it has a real category assigned.<\/li>\n<li>Changed: renamed and reworded the seven most jargon-heavy check names and their explanations (Canonical URL, OpenGraph, JSON-LD Schema, Rich Schema Type, Author Entity\/E-E-A-T, Breadcrumb Markup, Readability\/Flesch Score) into plain language, since these assumed the reader already knew SEO\/technical-AI terminology. The original technical term is kept in parentheses in each explanation for anyone who wants to look it up, so nothing is lost for advanced users \u2014 the goal was making the plugin usable for someone with no SEO background, not hiding the substance.<\/li>\n<li>Added: a new \"Quick Fixes\" page. On a site with many pages, opening each page's Action Plan individually to fix the same simple issue over and over doesn't scale. This page instead lists each of the four safe, mechanical issues (missing\/wrong-length meta description, missing image alt text, no categories or tags, an unreadable URL slug) across every affected page or image site-wide, with an inline field and Save button per row \u2014 fixed directly, no need to open the post editor. Deliberately limited to short, low-risk fields; anything touching actual body content (headings, sentence rewrites, new sections) stays in the per-page Action Plan, next to the content it changes.<\/li>\n<li>Added: uninstall.php, so deleting the plugin (not just deactivating it) also removes its settings and per-post analysis data (score, report, action plan) from the database, instead of leaving it behind indefinitely.<\/li>\n<li>Fixed: the FAQ claimed Rank Math support, but the meta description check and Quick Fixes only ever read Yoast's and AIOSEO's fields \u2014 Rank Math's actual field (rank_math_description) was never checked. Worse, Quick Fixes' save logic was a two-way Yoast\/AIOSEO guess that defaulted to writing into Yoast's field whenever AIOSEO wasn't active \u2014 including when Rank Math was the only SEO plugin actually installed, silently saving into a field nothing would ever read. Both the read and save paths now correctly detect and use whichever SEO plugin (Yoast, Rank Math, or AIOSEO) is actually active, falling back to the post excerpt when none are.<\/li>\n<li>Fixed: skipped pages (utility pages the classifier intentionally excludes from scoring, stored as score -1) were being pulled into the REST site-summary and the emailed report as if they were real scores \u2014 dragging down the average, permanently setting the lowest score to -1, and miscategorizing them as \"Needs Work\" in the email. Both now exclude skipped pages from every bucket and the average, matching how the main dashboard already handles them, and track them as their own distinct count instead.<\/li>\n<li>Fixed: two admin-side rendering functions (the post-editor meta box update and the bulk-analyze results list) built their HTML by concatenating values \u2014 including a post's own title \u2014 directly into strings inserted via jQuery's .html(). A post title is freely settable by any Contributor or Author, so this was a real stored-XSS path: a crafted title could execute in an administrator's browser when they viewed the dashboard or bulk-analyzed their content. Both functions now build the DOM safely (every dynamic value via .text(), matching the pattern already used correctly in the Quick Fixes screen).<\/li>\n<li>Changed: softened the Quick Fixes URL-slug wording, which called a slug change unconditionally \"safe\" because WordPress redirects the old URL. That's true for the URL itself, but doesn't cover external links, caches, custom redirect setups, or third-party SEO tooling tied to the old URL \u2014 the copy now says so plainly instead of asserting blanket safety.<\/li>\n<li>Changed: caught two more absolute-sounding claims that slipped through the earlier language-softening pass (\"give AI richer context,\" \"helps AI map content sections\") and reworded them to match the \"can help\" framing used consistently everywhere else.<\/li>\n<li>Fixed: a third, independent copy of the meta description lookup \u2014 inside the action-plan generator this time \u2014 still only checked Yoast and AIOSEO, missed when the check itself and Quick Fixes were fixed for Rank Math. A Rank Math user could pass the Meta Description check but get an Action Plan built from the wrong (empty) value. Now routes through the same shared helper as the other two, so this can't drift out of sync again.<\/li>\n<li>Changed: added wp_unslash() before sanitizing $_GET values (page, view, order, paged, post_id), per WordPress coding standards.<\/li>\n<li>Changed: reworded the one remaining \"AI-friendly schema types\" reference in the readme to \"Relevant structured-data types,\" matching the neutral positioning used everywhere else.<\/li>\n<li>Fixed: a full pass against the official WordPress.org Plugin Check tool. Added missing \"translators:\" comments throughout (required wherever a translatable string contains a placeholder, so translators know what each one means); numbered multi-placeholder strings correctly (e.g. %1$s\/%2$d) so translators can reorder them per their language's grammar; escaped several previously-unescaped dynamic values in the dashboard, Action Plan, and emailed report (a threshold value, breakdown-bar percentages, several counts, a category color); fixed two spots (Title Length and Content Length details) where part of the message was a raw, untranslated PHP string instead of going through a translation function; converted three multi-line strings built via concatenation into single literals (concatenation isn't parseable by WordPress's translation-extraction tools); and replaced a timezone-unsensitive date() call with gmdate(). A few remaining Plugin Check notices are left as-is with reasoning: read-only GET parameters for admin-screen navigation (view\/sort\/page state, not a state-changing action) don't need nonce verification; querying and sorting by post meta is inherent to how this plugin stores and compares scores; a VIP-tier advisory about a small bounded exclude() query; and two flagged hook\/array-key patterns that are false positives (WordPress's own 'the_content' core filter, and a plain data array that happens to use the string \"meta_key\" as a key name rather than an actual database query parameter).<\/li>\n<li>Fixed: a second Plugin Check pass caught what the tool couldn't verify from the first \u2014 printf()\/sprintf() arguments substituted into an already-escaped template still need to be individually wrapped (e.g. absint() for a %d placeholder), since static analysis can't confirm a substituted value is safe just because the surrounding template went through esc_html__(). Also: a translators comment must sit directly above the actual translation function call, not above a wrapping printf() one line up, for multi-line calls; one internal-links count genuinely missed a translators comment in the first pass; and one spot with intentional HTML in a translatable string (a hardcoded &lt;strong&gt; tag around an already-escaped value) is marked with a justified phpcs:ignore rather than escaped in a way that would break the formatting.<\/li>\n<li>Changed: a third Plugin Check pass came back with zero remaining errors \u2014 only the 20 warnings already identified and explained in earlier notes (read-only GET navigation params, meta-key\/meta-query queries inherent to how this plugin stores and compares scores, four false-positive array-key matches, and one VIP-tier advisory on a small bounded query). Each is now marked with an explicit, justified phpcs:ignore comment explaining why it's safe, so Plugin Check reports a clean pass rather than requiring a reviewer to take the earlier written explanation on faith.<\/li>\n<li>Fixed: Bulk Analyze didn't distinguish a genuinely low score from a skipped page's placeholder -1 score, unlike the dashboard, email report, and site summary (all fixed earlier this cycle) \u2014 a skipped utility page could drag down the average and show up under \"Pages Needing Attention\" with a score of -1. The REST response now reports each result's skipped state, and Bulk Analyze excludes skipped pages from every statistic, showing them as their own honest count instead. The same -1-as-a-real-score gap existed in two smaller places too: the list-table score badge and the post-editor meta box both now show a neutral \"Skip\" indicator instead of styling -1 as a failing score.<\/li>\n<li>Fixed: Quick Fixes applied a change (meta description, categories\/tags, slug) and removed it from the list, but the post's cached score\/report weren't refreshed \u2014 update_post_meta() and the taxonomy functions Quick Fixes uses don't trigger save_post at all, so the only path that could auto-refresh (the site's general \"auto analyze on save\" setting) didn't apply, and was unreliable even when it did apply (that setting can be off, or restricted to certain post types). Each of those three fixes now explicitly re-analyzes the post right after saving, independent of that setting, so the score is accurate immediately. Alt text intentionally isn't auto-reanalyzed \u2014 an image can appear on more than one page, and there's no reliable way to know which ones without an expensive site-wide scan; the affected page(s) pick up the change on their next regular re-analysis instead.<\/li>\n<li>Changed: reduced the timeout on both frontend-fetch calls (content resolution: 15s \u2192 8s; structured-data detection: 10s \u2192 6s). Both can run synchronously during save_post when \"Auto Analyze\" is on (the default), and can both fire in the same request for some page types \u2014 worst-case combined blocking time is now 14s instead of 25s. This wasn't independently verified against real hosting conditions (loopback request behavior varies a lot by host\/security-plugin setup) \u2014 recommend testing directly before relying on it: publish\/update both a normal post and a page-builder page, with the site publicly reachable and with any caching\/security plugins active, and confirm the editor doesn't hang uncomfortably. If it's still a problem on some hosts, the more thorough fix is making auto-analysis asynchronous instead of running inline during save_post \u2014 a larger change, and one to make once there's a concrete case showing it's needed rather than speculatively now.<\/li>\n<li>Changed: removed flush_rewrite_rules() from activation and the entire deactivation hook (which existed only to call it). This plugin registers no custom post types or rewrite rules, so there was nothing to flush.<\/li>\n<li>Changed: rewrote the plugin's short description, main description, and header description to lead with the honest causality up front, rather than leaving it as an implication: this plugin doesn't get content found by AI search, the content itself does \u2014 the plugin checks it against a framework and shows what to fix. Also added a dedicated FAQ entry (\"Will this plugin get my content found by AI search?\") answering this directly, since it's an easy thing to misread from a name like \"AI Search Ready\" and better to state plainly than leave to inference.<\/li>\n<li>Fixed: the Taxonomy Usage check called wp_get_post_categories()\/wp_get_post_tags() unconditionally, with no check for whether the post type actually supports either taxonomy. WordPress core Pages don't support categories or tags at all by default \u2014 so with the plugin's default settings (which analyze both posts and pages), every single Page on every site would always fail this check, permanently, regardless of anything the user did, since there's no field to even set it in. The check now only runs when the post type actually supports at least one of the two taxonomies. A second, related bug caught in review: even after that fix, the check still required BOTH a category AND a tag to pass, so a custom post type registered with only one of the two (a common setup) could still never pass \u2014 and the failing-case guidance in the Action Plan told users to add tags to post types that have no tag field at all. It now requires only whichever taxonomy the post type actually supports, and excludes the site's default \"Uncategorized\" category from counting as real categorization (it's auto-assigned to every post, so counting it made the check trivially pass for anything that supports categories, regardless of whether the user did anything) \u2014 matching logic Quick Fixes' categories\/tags list already used correctly.<\/li>\n<li>Fixed: the URL Readability check flagged a short or generic slug (e.g. \"home\") on the site's designated static front page \u2014 but WordPress always serves that page at the site root regardless of its own slug, so the slug has zero effect on the real, live URL. There was nothing to actually fix, just a cosmetic internal field. Both the check and Quick Fixes' slug list now skip the static front page entirely.<\/li>\n<li>Changed: the Meta Descriptions section in Quick Fixes listed pages with a genuinely non-empty, visible description with no indication of why they were still listed (length outside the 120-160 target), which could look like the page had been misread as blank. Each field now shows a live, updating character count with the actual reason underneath (\"87 characters \u2014 below the 120-160 target\"), and the section's own description spells out that a real description can still appear here if it's the wrong length.<\/li>\n<li>Fixed: the URL Readability check's 2-8 word rule doesn't fit a small set of universal, conventional single-word page slugs \u2014 \"about\", \"contact\", \"pricing\", \"services\", and similar. These are recognizable and expected precisely because they're short; flagging them as needing to be \"more descriptive\" would mean recommending against genuinely standard, good practice, not fixing a real gap. Both the check and Quick Fixes' slug list now recognize a short whitelist of these conventional single-word slugs and no longer flag them.<\/li>\n<li>Fixed: the Image Alt Text check matched every raw  tag in a page's rendered content with no filtering, including invisible tracking\/analytics pixels injected by third-party widgets (booking tools, CRMs, marketing scripts) \u2014 a 1x1, display:none image with no visual content, existing purely as an analytics beacon. Flagging these for \"descriptive alt text\" doesn't make sense; there's nothing to describe. The check now excludes any image matching that pattern (1x1 dimensions, or explicitly hidden via inline display:none) before counting or requiring alt text.<\/li>\n<li>Fixed: the \"Add OpenGraph meta tags\" check was checking the wrong things \u2014 Yoast's own internal action name (<code>wpseo_head<\/code>, not a reliable signal of anything) and a per-post OG title override meta field that's only set if the user manually typed a custom OpenGraph title in, which normal use of Yoast, Rank Math, or AIOSEO never requires, since all three auto-generate full OpenGraph tags (title, description, type, url, site name) the moment they're active. The check now looks for whether one of those plugins is active, which is what actually determines whether OpenGraph tags are being output. A more accurate version would fetch the live page and read the actual og: tags rather than inferring from plugin presence (a plugin can have its social-meta feature turned off) \u2014 deliberately not done in 1.2.0, since it would add a third live-page fetch on top of the two content resolution and structured-data detection already make during save_post when Auto Analyze is on. Worth revisiting in a later version.<\/li>\n<li>Fixed: two Quick Fixes (the slug fix, and the meta description fix when no SEO plugin is active) use wp_update_post(), which fires WordPress's own save_post action \u2014 triggering a full auto-analysis if that setting is on, in addition to the analysis Quick Fixes already explicitly runs right after applying the fix. One click could result in two full analyses back to back, each potentially making its own live-page fetches. The auto-analyze handler now checks a flag Quick Fixes sets around its own internal updates and skips itself when it's set, since Quick Fixes' own explicit re-analysis always runs regardless.<\/li>\n<li>Fixed: the Bulk Analyze results screen only ever listed and linked to pages scoring below 60 (\"Pages Needing Attention\") \u2014 any page scoring 60 or higher, including a perfect page with nothing to fix, had no listing and no way to reach its Action Plan from that screen at all, even though visiting it directly worked fine and correctly showed a \"No Actions Needed\" confirmation. Every scored page now gets a link somewhere on that screen \u2014 low scorers stay in the always-visible list, everything else is in a collapsed \"Other Pages\" section so a large site's full list of already-fine pages doesn't crowd out what actually needs attention.<\/li>\n<li>Fixed: analyze_post() resolves a post's content once (page-builder aware, with a live-page-fetch fallback), then generated its Action Plan \u2014 which created its own separate Content Resolver and resolved the exact same post a second time. On a page-builder site where resolution falls back to fetching the live page, this meant two live-page fetches for one analysis instead of one, on top of whatever else the analysis was already fetching. Action Plan generation now accepts the already-resolved content as an optional parameter and reuses it when available, only resolving on its own when generated independently of a fresh analysis (e.g. regenerating from a cached report with no resolved content to reuse). Reduces the worst-case synchronous fetch chain during save_post from roughly 22 seconds to about 14.<\/li>\n<li>Verified SSL when fetching frontend content for page-builder analysis<\/li>\n<li>Clarified scoring language throughout readme, dashboard, and email reports: scores reflect Fifteenth Labs AI Search Ready's own analysis framework, not a live measurement of how ChatGPT, Perplexity, or other AI systems will actually treat content<\/li>\n<li>Verified against WordPress 7.1 through live functional testing across multiple post types (posts, pages, and a custom post type) \u2014 Dashboard, Action Plan, Re-Analyze, and Quick Fixes all confirmed working correctly.<\/li>\n<li>Softened absolute claims in recommendation copy (Action Plan, Analyzer, Content Quality, Structured Data checks) \u2014 e.g. \"AI needs X\" now reads as \"X can improve machine readability,\" reflecting best-practice guidance rather than asserted facts about how AI systems work<\/li>\n<li>Aligned OpenGraph messaging to consistent, neutral wording across dashboard and action plan; removed a readme sentence that stated a claim and disclaimed it in the same breath<\/li>\n<li>Completed a full pass across all recommendation copy (word count, readability, topic focus, headings, paragraphs, internal links, alt text, title length, URL slugs, anchor links, content freshness, taxonomy, author E-E-A-T) to remove remaining absolute claims about how AI systems operate, replacing them with guidance framed around this plugin's own scoring methodology<\/li>\n<li>Softened the main plugin description, readme FAQ answer, and two internal file-header comments that still described the plugin as helping \"AI systems understand\/extract\/cite\" content<\/li>\n<li>Removed remaining AI assertions from meta description, anchor links, JavaScript\/crawler, heading, and paragraph structure copy, plus an internal code comment, so recommendations describe content structure benefits without asserting how AI crawlers specifically behave<\/li>\n<li>Softened four more recommendation strings (lists, title keywords, FAQ detection, meta description length) that referenced \"AI extraction\" language<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Added page builder content resolver (BeTheme\/Be Builder, Elementor, Divi, WPBakery, Beaver Builder, Oxygen, Brizy)<\/li>\n<li>Added \"Getting There\" (60-79) status category alongside Needs Work and AI Ready<\/li>\n<li>Added visual breakdown bar on dashboard showing all 3 score buckets<\/li>\n<li>Added full Action Plan system with ADD\/REMOVE\/CHANGE instructions per page<\/li>\n<li>Added Email Report with status picker (choose which statuses to include)<\/li>\n<li>Added HTML download and PDF download for reports<\/li>\n<li>Added diagnostic REST endpoint for troubleshooting content detection<\/li>\n<li>Added \"Back to Dashboard\" button on Action Plan pages<\/li>\n<li>Added version badge in dashboard header<\/li>\n<li>Fixed script loading on all plugin pages<\/li>\n<li>Fixed score bucket math so all numbers add up to total analyzed<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<li>5-category analysis system with 30+ individual checks<\/li>\n<li>Dashboard, bulk analysis, and per-post meta box<\/li>\n<li>REST API endpoints<\/li>\n<li>Auto-analyze on publish<\/li>\n<\/ul>","raw_excerpt":"A content checklist for AI search readiness. This plugin doesn&#039;t get you found by AI \u2014 your content does. It just shows what to improve.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/360598","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=360598"}],"author":[{"embeddable":true,"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/fifteenthlabs"}],"wp:attachment":[{"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=360598"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=360598"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=360598"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=360598"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=360598"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/azb.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=360598"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}