= 2.9.110 =
* Added a read-only Pre-publication Preflight queue in Publisher Toolkit for editable drafts, pending stories and scheduled posts, with local SEO checklist scores, concise suggestions and site-timezone schedule display; it never blocks or changes publication.
* Added **Setup Wizard** directly under Dashboard in the PublishRank sidebar (also kept in the dashboard hero, workflow card, Plugins row and toolbar).
* Added the animated PublishRank logo as a loader on every PublishRank admin screen, with a CSS-only failsafe and an opt-out (`data-pr-no-loader`) for forms.
* Redesigned the Dashboard and screen headers to match the official website: white header bar, pink hero with a live preview of your site checks, pill buttons, feature strip and a three-step publishing workflow (`assets/css/website-theme.css`).
* Added the official website, https://publishrankseo.vercel.app/, to the plugin header, Plugins screen (Official Website), dashboard, Documentation & Help, front-end credit and readme, replacing the old netlify address.
* Made the version consistent: plugin header, `PUBLISHRANK_SEO_VERSION`, readme stable tag, Branding fallback, docs and in-dashboard documentation all read 2.9.110 (documentation previously still said 2.9.105 and 2.9.108).
* Restructured `docs/` into getting-started, features, admin and maintenance folders with a new index, installation guide and setup-wizard guide.
* Synchronised the reviewable `src/assets` copies with the shipped `assets` files.
* Fixed the loader staying on screen after export/download actions; it now skips download links and forms and always hides after 12 seconds.
* Newsroom attachments notice now only appears on PublishRank screens and explains the fix; added the optional `PUBLISHRANK_PRIVATE_DIR` constant (and `publishrank_private_storage_base` filter) for hosts that need a custom private folder outside the web root.
* Uninstall now also removes Newsroom (`uj_newsroom_*`) options and the weekly-audit and sitemap-cursor scheduled tasks.
* Added `tools/check-version.sh` and `VersionConsistencyTest` to keep versions consistent.

= 2.9.109 =
* Align the WordPress-loaded admin palette with the PublishRank website brand colors.
* Replace the plugin menu mark with the supplied PublishRank menu icon and refresh asset cache keys.
* Render a blank 404 log table body after the log is cleared.

= 2.9.108 =
* Improved dashboard tool-search feedback: the live result count shows matching tools out of the available total, with localized announcements for assistive technology.
* Corrected the WordPress readme stable tag and outdated guidance about template variables in social metadata.
* Organization/WebSite JSON-LD is now omitted until publication and publisher names are configured, avoiding empty identity nodes and broken graph references; the Schema screen links to the setup wizard when identity is incomplete.
* Kept story-specific Web Story logos out of the site-wide Organization entity and preserved alt text and dimensions for attachment-backed default social images, including CDN URL rewriting.
* Redirect cycle checks now include active regex rules and fail closed when the configured chain-analysis depth is exceeded. Foreign-host source URLs are rejected, and the supported 303 status is selectable in the form.
* Added regression tests for publisher graph readiness and redirect source/cycle safety.
* Added an opt-in SEO ownership handoff: when enabled, PublishRank suppresses its overlapping frontend metadata, hreflang and page JSON-LD only when a supported SEO plugin is detected. Warning-only behavior remains the default; external plugin settings, redirects, sitemaps and standalone schema feeds are not changed.
* Added regression tests for handoff defaults, supported-plugin detection and the separation between saved preferences and effective frontend output.
* Newsroom private attachments now use a writable directory outside DOCUMENT_ROOT, migrate existing uploads without changing stored file IDs, serve only through the authorized download handler, and fail closed for new uploads if private storage is unavailable.
* Added sitewide wp-admin Newsroom pop-up alerts and a recent-notifications inbox for assignment, stage, overdue-reminder and discussion events, with per-user email, in-app and pop-up preferences. AJAX polling and read actions require Newsroom access and a nonce; notification records are scoped to stories the user can still access.
* Added Newsroom export-filter and adjacent-stage regression coverage and stage-change success feedback.
* Moved Newsroom notifications into a dedicated bell tab with server-rendered and live unread counts, clearer dashboard naming, and keyboard-friendly notification badges.
* Restricted role-matrix changes to administrators, added a separately delegable setup-wizard capability, preserved administrator access, and hardened nested role input handling against malformed requests.
* Fixed duplicate breadcrumb schema output by collapsing multiple BreadcrumbList nodes to one canonical list and removing repeated breadcrumb items with the same label and URL.
* Extended the 404 monitor with request normalization, common probe suppression, GET/HEAD filtering, crawler classification, short-lived write locking, 90-day retention, safer referrer/path limits, and searchable/sortable admin summaries.
* Added dedicated 404 Monitor documentation covering privacy, capture exclusions, throttling, retention, filters, redirect validation, dismissal, clearing and troubleshooting in the package, readme and in-dashboard help.
* Added a complete versioned feature inventory for PublishRank 2.9.108, covering all dashboard cards and all Technical Health checks shown in the supplied dashboard reference image.

= 2.9.105 =
* New: Google Preferred Sources tool (PublishRank → Google Preferred Sources), shown with a "New" badge in the menu and on the dashboard until you open it.
* Generates your Preferred Sources link (https://www.google.com/preferences/source?q=DOMAIN) from the site's home URL or an address you enter; paths, queries and fragments are removed, unsafe schemes are rejected and internationalized domains are preserved.
* Shows Google's documented button code (div with google-add-preferred-source-btn plus the official publisher.js script) with Copy, a placeholder preview, optional documented data-theme and data-lang, and Reset to Default.
* Custom Button Builder generates an accessible, independently styled link to your Preferred Sources URL, clearly labelled as a custom link and not Google's official button, because Google documents no custom styling for its own button.
* Advanced HTML editor with warnings, strict allow-list validation, no code execution, and exact saving (code that fails validation is not saved or rewritten).
* Optional automatic placement (off by default): top of page, above, middle or below the article, or footer, on the page types you choose. The button is printed in the normal page flow with its own spacing so it does not overlap theme content. Google's script is added only when Google's button is shown, never in wp-admin.
* One simple panel: choose Default or Custom once, then choose where it appears.
* Shortened the PublishRank sidebar to Dashboard, Newsroom, Settings and Documentation. Every other tool, including all Newsroom screens, is reached from a Dashboard card and remains registered, so direct links keep working.

= 2.9.104 =
* Ensured the admin tool icons load on every wp-admin screen with Dashicons available, and fixed dropdown group handlers for multiple navigation groups.
* Automatic classic-theme breadcrumbs now print at main-loop start, above the headline path, with the content filter retained as a fallback for non-standard themes.
* Corrected the breadcrumb root to `Home` using the actual homepage URL; publication identity remains unchanged everywhere else.
* Added expandable, keyboard-accessible PublishRank admin submenu groups.
* Added distinct Dashicons for each tool; they follow the menu text color with no custom tile or background.
* Preserved every registered submenu destination to prevent WordPress's generic authorization error on dashboard deep links.
* Resolved schema aggregator template variables before publishing descriptions in JSON-LD.
* Added the supplied PublishRank brand mark to `assets/images/publishrank-brand-mark.png`.
* Replaced every icon with the single official PublishRank mark (`assets/images/publishrank-brand-mark.png`) in the admin sidebar, toolbar and its dropdown, screen headers, setup wizard and sitemap view. The extra PNG icon sizes and `publishrank.svg` were removed from the package.
* Removed the custom dark background and the coloured icon tiles from the PublishRank admin dropdown; it now uses WordPress's native submenu colours, so it follows every admin colour scheme. The Dashboard entry shows the PublishRank mark.
* Redesigned the XML sitemap view in the bordeaux-to-pink brand palette: branded header, showcase hero with the PublishRank mark, summary tiles, a content showcase bar with per-type URL shares, colour-coded type cards with URL counts, light and dark modes, and a version footer.
* Made the version consistent everywhere: the Branding fallback and the Newsroom module now follow `PUBLISHRANK_SEO_VERSION` (2.9.104); sitemap view and admin headers display the same number; the readme changelog headings were corrected.
* Fixed the sidebar and dropdown icons not updating or not showing: the menu stylesheet and onboarding stylesheet are now cache-busted by file time (they were cached under the unchanged version number), and the brand mark is drawn as a plain background image instead of a CSS mask, which browsers refuse to paint for cross-origin assets.
* Bumped the internal integrity build marker (not the plugin version) so the file-integrity baseline is rebuilt after this package replaces the earlier 2.9.104 files, which otherwise reported changed PHP files.
* Expanded the documentation: new in-dashboard sections (menu and toolbar, sitemap view, live blogs and Newsroom, versions, troubleshooting) and a new `docs/` folder with guides for sitemaps, branding, navigation, troubleshooting, versioning and a compatibility checklist.

= 2.9.103 =
* Updated the admin palette using a navy/teal analogous foundation with coral action accents and gold attention states.
* Improved contrast and focus colors across dashboard, onboarding, status badges, and tool filters.

= 2.9.102 =
* Added a dashboard Tools Showcase search and category filter.
* Reduced the native PublishRank submenu to essential destinations while preserving direct tool access from the dashboard.
* Added the uploaded search-style mark as assets/images/publishrank.svg and applied it to the PublishRank admin menu. (Superseded in 2.9.104: replaced by publishrank-brand-mark.png and removed.)

= 2.9.101 =
* Fixed homepage SEO template variables appearing literally in wizard and dashboard configuration summaries.
* Unified administrative homepage-title previews with the frontend template resolver.
* Added responsive dashboard identity/title summary with safe wrapping.

= 2.9.99 =
* Added: PublishRank's publication title and description now override the WordPress Site Title and Tagline on the public website (on by default; Settings > Visible publication identity). Themes, block themes, Elementor widgets, feeds, the REST index and get_bloginfo() show the PublishRank values after a single setup. The values stored in Settings > General are never written or changed, wp-admin and the settings REST route still see the real WordPress values, and a PublishRank value that is empty leaves the WordPress value in place. A notice on Settings > General explains the override.
* Note: the visible-identity hiding from 2.9.98 is a separate switch and is still on by default, so the theme's visible title and tagline stay hidden on screen. Turn "Hide the visible site/publication title" off to show the (now PublishRank-provided) title in the header.
* Added: tests/cases/10_identity_override.php.

= 2.9.98 =
* Changed: the publication (website) title and description are owned by PublishRank. They are read only from PublishRank settings (publication name / Identity name, Identity description) and are never taken from the WordPress Site Title or Tagline: titles and the %%sitename%% / %%site_description%% variables, meta description, Open Graph, WebSite/Organization schema, breadcrumbs, sitemaps and stylesheet, llms.txt, Live Preview and audit e-mails all use the same PublicationProfile values. Nothing is copied from WordPress on install or in the wizard any more; values already saved by earlier versions are kept untouched. When a value is empty the dependent output is left out and PublishRank screens show a notice asking for it.
* Changed: the visible site title and tagline printed by the theme are hidden on screen by default on every public page (both switches default to on; an explicit earlier choice is kept, and each can be turned off in Settings). The rule is visually-hidden instead of display:none, so the text stays available to screen readers and crawlers; SEO output is unchanged. Added Elementor site-title widget selectors and the `publishrank_hidden_identity_selectors` filter.
* Note: sites that never saved the two switches become hidden after the update; turn them off in Settings > Visible publication identity if your header uses the site title as its logo text.
* Added: tests/cases/09_publication_identity.php.

= 2.9.97 =
* Fixed (root causes of missing visible trails): automatic placement only existed for singular views via the content filter, so archives, the posts page and any template that does not run the main-loop content filter (Elementor theme-builder templates, Canvas/Header-Footer page templates) printed nothing while BreadcrumbList JSON-LD was still output. Added placement for classic archives (main loop start), block-theme archives (above the archive title) and block-theme templates without a title block (above post content), plus the documented Elementor hooks `elementor/widget/render_content` (Pro title widgets) and `elementor/page_templates/canvas|header-footer/before_content`. With Elementor loaded, the content filter is also accepted outside the main loop (never during wp_head).
* Fixed: duplicate prevention used one request-wide flag; it is now a per-context registry (main-query object), and the manual-trail check also reads Elementor `_elementor_data` shortcode widgets. A trail printed by a shortcode no longer blocks unrelated contexts.
* Fixed: the shortcode and Breadcrumbs block now respect "Print the breadcrumb trail on the site" (off = nothing). Placement "Structured data only" still allows a hand-placed trail, as before.
* Fixed: the static front page no longer gets a "Home › Home" trail or BreadcrumbList (opt in with the `publishrank_breadcrumb_show_on_front_page` filter); the posts page now gets Home › Posts page.
* Fixed: BreadcrumbList suppression assumed another SEO plugin emitted breadcrumb data whenever its function existed. Yoast SEO and Rank Math are now checked against their own breadcrumb setting; All in One SEO is only released when its option explicitly reads off (option path not verified on a live install). Use the `publishrank_breadcrumb_schema_external_owner` filter to override.
* Fixed: the site check counted the separator `<span class="publishrank-breadcrumb-separator">` as a second renderer (false "multiple trails" warning) and counted the word BreadcrumbList inside text; it now decodes the JSON-LD.
* Improved: the Breadcrumbs site check tests an article, a page and a category archive, shows HTTP status and the settings in force, and separates confirmed facts (settings, markup, a one-time probe note printed by the plugin during that request) from unconfirmed candidate causes. It reports disabled/manual/schema-only settings, unregistered placement, too few items, hooks that never ran, PublishRank markup, other plugin or theme markup, stylesheet/inline-hiding checks, multiple trails, multiple or dangling BreadcrumbList, cache hints and fetch errors. Administrator-only, nonce-protected, rate-limited to one run per 20 seconds, own-site URLs only, never on visitor requests.
* Improved: breadcrumb stylesheet is versioned by file time and scoped to `.publishrank-breadcrumbs` (own row in Elementor/flex containers); no `!important`.
* Added: tests/cases/08_breadcrumb_placement_and_diagnostics.php.

= 2.9.96 =
* Hardened frontend visibility detection for WordPress installations where `is_rest()` is not available.
* Retained the breadcrumb detector improvements for quoted markup and page/post site checks.

= 2.9.95 =
* Breadcrumb site checks now detect both single- and double-quoted class attributes and inspect the latest published post or page.
* Added opt-in visual-only hiding for the visible publication/site title and description on home, page and post views; SEO output remains intact.

= 2.9.94 =
* Breadcrumbs screen now shows an actual latest-published-post preview with real site values and a separate JSON-LD item preview without visual separators.
* Added same-screen appearance, color, invalid-item recovery, fallback and local error logging controls with validation.

= 2.9.93 =
* Fixed literal `\\n` provenance text and duplicate SEO branding markers in frontend HTML.
* Resolved article schema descriptions through the shared template resolver and ignored title-only `%%sep%%` tokens in descriptions.

= 2.9.92 =
* Added: a grouped "Insert variable" dropdown under the SEO title, meta description, social title and social description fields in the post editor, in the Live Preview snippet editor and on the setup wizard's homepage title and description. It lists every variable the plugin resolves (Site, Content, Author, Taxonomy, Dates, SEO), explains each one and what it returns when empty, inserts the exact token at the cursor without touching the rest of the text, is a native select (keyboard and mobile friendly) and also works in fields the block editor adds later.
* Added: Meta\TemplateVariables, one registry of variables (token, label, description, contexts, fallback). The resolver's list of supported names is now read from it, so the dropdown, help text and resolver cannot disagree. Variables unavailable for a content type (for example categories on pages) are shown disabled with the reason.
* Fixed: social title and social description overrides did not resolve variables, so a template such as %%title%% was printed literally in og:title, og:description, twitter:title, twitter:description and in the REST/preview data. They now go through the same resolver; unknown tokens are dropped and an empty result falls back to the SEO title/description.
* Fixed: the Live Preview snippet editor offered only a legacy "Insert %focus_keyword%" button; it now uses the full dropdown. Help text lists are generated from the registry.
* Added: Breadcrumbs screen (dashboard card "Breadcrumbs"): visible trail on/off, frontend override, separator preset list and custom Unicode separator with live preview, placement and theme hook, first-crumb label, BreadcrumbList on/off, and a site check that reports which breadcrumb renderers the live page prints and warns about duplicate trails or duplicate BreadcrumbList blocks.
* Added: frontend override option (publishrank_breadcrumb_frontend_override, on by default, existing choices untouched). When on, PublishRank's separator is applied through the separator filters of Yoast SEO, Rank Math, WooCommerce and All in One SEO instead of editing HTML. Off leaves those plugins untouched. Extend with the publishrank_breadcrumb_override_filters filter.
* Added: separator presets "»»" and "…".
* Note: PublishRank contains no code that reads All in One SEO settings, so a separator that survives that plugin's removal comes from the theme, cached pages or leftover content. Use Breadcrumbs > Site check to identify the source.
* Added: tests 05 (registry, resolver agreement, social resolution) and 06 (override, separators, detector, screen).

= 2.9.91 =
* Fixed: global SEO title templates and per-post SEO titles/descriptions now share one resolver (Meta\TemplateResolver). Global templates previously supported only 8 variables; both places now support the same 15: %%title%%, %%sitename%%, %%site_description%%, %%category%%, %%primary_category%%, %%author%%, %%date%%, %%modified%%, %%excerpt%%, %%sep%%, %%page%%, %%id%%, %%permalink%%, %%focus_keyword%% and %%focuskw%% (the legacy %focus_keyword% / %focuskw% forms still work). Unknown variables are dropped, values are never re-expanded, and dangling separators left by empty values are removed.
* Fixed: saving %%date%% or %%category%% in a title/description template (post editor, REST, settings, import) corrupted it to "%te%%" / "%tegory%%" because sanitize_text_field() strips percent-encoded sequences. Templates are now sanitized token-safely. The upgrade repairs these two corrupted forms in the global templates and homepage title/description; per-post values already damaged on a site are not rewritten automatically.
* Fixed: the REST/dashboard view of a post's meta description did not resolve variables and could differ from the front end.
* Fixed: spaced breadcrumb separators (for example " › ", "» ") lost their spaces on save, and "no separator" and a non-breaking space could not be stored. Separators are now validated by a dedicated sanitizer: plain text only, up to 10 characters, markup/control/bidi characters removed, invalid input rejected with a notice and the previous value kept.
* Added: grouped breadcrumb separator presets (arrows, angles, slashes and lines, dots and bullets, dashes, other symbols, spaced variants, space / non-breaking space / none), a custom field and a live preview. Existing saved choices keep showing as presets.
* Changed: right-to-left mirroring now applies only to directional separators (arrows and angle brackets), and separators keep their spacing (white-space: pre).
* Fixed: when BreadcrumbList output was off, the WebPage node still pointed at a BreadcrumbList that was not printed. The reference is now only emitted when the list is.
* Added: separate "Organization and WebSite entities" switch (publishrank_org_website_schema_enabled, default on). Turning it off removes those two entities and every reference to them while keeping the WebPage/Article/BreadcrumbList entities valid.
* Changed: every output switch (metadata, schema, organization/website, visible breadcrumbs, BreadcrumbList) is read through one helper, is honoured at run time (including the document title), and treats a missing option as enabled and a saved false-like value as disabled.
* Changed: BreadcrumbList is not added when Rank Math or All in One SEO already prints breadcrumbs (as was already the case for Yoast SEO); the filter publishrank_breadcrumb_schema_external_owner can override this.
* Fixed: with the block-theme automatic placement, a trail placed by hand (block or shortcode) in the post no longer produces a second trail.
* Added: saving any identity, schema, social, breadcrumb, title-template or output-switch option clears per-request caches, bumps the cache epoch and schema-index generation, and fires the publishrank_seo_output_settings_changed action for page-cache plugins.
* Upgrade: safe to repeat; existing explicit on/off choices are kept, missing switches are created enabled.
* Added: automated integration tests (tests/), run against a real WordPress install.

= 2.9.90 =
* Expanded per-post SEO title and meta-description variables for reusable templates.
* Added token-based placeholders and clearer variable guidance in the post editor.
* Expanded title separator and breadcrumb separator presets, retaining custom separator input.
* Clarified that enabled frontend metadata, schema and breadcrumb controls publish the configured values to the visible site.

= 2.9.89 =
* Added an opt-in Crawl Optimization admin screen for WordPress metadata cleanup, feed discovery cleanup, emoji asset removal, search hygiene, robots.txt crawl hints, UTM URL-bar cleanup, and guarded URL parameter cleanup.
* Kept all new controls disabled by default. REST discovery-link removal does not disable the REST API; optional robots rules target only the core `/wp-json/wp/v2/` content namespace so PublishRank's schema index endpoint remains discoverable.
* Added conservative safeguards for query parameter redirects and documented that robots.txt is not access control.

= 2.9.88 =
* Added the public, paginated `/wp-json/publishrank/v1/schema-index` REST endpoint to help AI agents and other consumers discover public structured-data URLs without first traversing the whole site.
* Added the endpoint to generated `llms.txt` resources while schema output is enabled. The endpoint returns a compact index; each canonical page remains the source of its complete JSON-LD graph.
* Added short-lived caching and cache invalidation for content changes. Newsroom changes are deferred.

= 2.9.87 =
* Frontend SEO and structured-data sections now close with the exact comment: <!-- end of SEO data Powered by PublishRank -->.

= 2.9.86 =
* Frontend HTML provenance comments now start with “SEO Powered by PublishRank” and close generated SEO sections with “Data generated by PublishRank”.

= 2.9.85 =
* Fix Assistant: retain the saved meta description when the editor meta panel has not mounted or synchronized yet.
* Image alt assistant: prefill missing article-image alt text from the latest Media Library alt value before using caption or filename suggestions, and clarify that publishers can edit and override the value.

= 2.9.84 =
* Breadcrumbs: added separate controls for the visible frontend trail and BreadcrumbList SEO/schema output. You can hide the trail on the site while keeping structured data enabled.

= 2.9.83 =
* Fixed administrator dashboard cards opening WordPress's generic "Sorry, you are not allowed to access this page" screen. Registered PublishRank submenu pages are no longer removed after registration, so direct dashboard links and the full submenu remain available.
* Retained and validated the breadcrumb separator symbol list, visible styles, and shared visible/schema breadcrumb trail.

= 2.9.82 =
* Breadcrumbs: choose the separator symbol from a list (arrow, angle, slash, pipe, dot, bullet, and more, or your own), pick a look (Plain, Chips, Bar, Underline) and size, and set optional text, link and background colours.
* Breadcrumbs: the visible trail and the BreadcrumbList structured data now come from one shared trail, so they always match (Google requires markup to describe a trail visitors can see).
* Breadcrumbs: new placement setting — Automatic (above the post title in block themes, above the content in classic themes), Above the content, Theme hook, Manual, or Structured data only. Added a "PublishRank Breadcrumbs" block, the publishrank_breadcrumbs() template tag, and a first-crumb label option.
* Breadcrumbs: added theme-neutral styling (no more numbered list), RTL-aware separators, category/tag/taxonomy/post-type archive trails, primary-category support, and the current crumb now uses the post title instead of the document title ("Title | Site").
* Breadcrumbs: a trail with fewer than two items is no longer printed or emitted as schema, and the WebPage node only references a BreadcrumbList that is actually output.
* Fix assistant: "Apply description" no longer reports "Enter a value first" — the apply handler now reads the field it belongs to.
* Fix assistant: Fix buttons now also cover focus keyword in the title (SEO headline), focus keyword in the opening paragraph (insert-as-first-paragraph), keyword missing from the meta description, title width and orphan pages; blocks always render with placeholders so there is somewhere to type.
* Fix assistant: every image without alt text (including images with no alt attribute) gets an alt field; saving writes the alt into the editor content as well as the media library, so the score updates.
* Fix assistant: applied SEO values are also pushed into the block editor's post state so pressing Update does not write the old value back; text typed into the assistant survives live re-analysis.

= 2.9.81 =
* Refined Newsroom cards, workflow stages, calendar events, and priority colors to use PublishRank's plum, evergreen, brass, coral, and warm ivory palette.
* Moved Newsroom into the PublishRank submenu directly after Dashboard and renamed the menu item to "Newsroom".
* Placed Site Verification immediately beneath Newsroom in the PublishRank submenu.
* Loaded the shared PublishRank palette and admin styles on Newsroom screens.

= 2.9.80 =
* Integrated the standalone Umarjaum Newsroom editorial workflow as the built-in PublishRank Newsroom module.
* Added newsroom stories, workflow stages, reporter/editor assignment, planning board, calendar, private collaboration, attachment handling, activity history, role controls, reminders, CSV export, and WordPress draft handoff to the PublishRank package.
* Preserved the newsroom's existing option keys and story metadata for compatibility with the standalone module; branded the admin menu and toolbar shortcut as PublishRank Newsroom.
* Updated the integrated module's asset paths and activation/deactivation lifecycle to run through PublishRank.

= 2.9.79 =
* Expanded built-in WP Hide Login to route dashboard scripts through the configured slug, including admin.php, index.php, AJAX and assets, while keeping the login page at /slug/.
* Added direct /wp-admin/ and /wp-login.php 404 handling, Apache rewrite-rule verification, a safe fallback when .htaccess changes cannot be confirmed, and migration-safe rule refreshes.
* Improved generated admin redirects and settings links; retired old slug rewrite rules when the configured slug changes.
* Reused WordPress core login handling and added an admin warning when the host cannot confirm the required Apache rules. Live-host and shared-host compatibility still require staging tests.

= 2.9.77 =
* Added an optional built-in WP Hide Login module with a configurable custom login slug, administrator settings page, nonce/capability checks, rewrite-rule handling, and generated login URL rewriting.
* Reuses the WordPress core login controller rather than replacing authentication logic; documented that custom login URLs are not a substitute for layered security.

= 2.9.76 =
* Corrected the settings/readme attribution disclosure: technical provenance markers are always on, but the plugin does not insert a visible footer credit or promotional link.
* Updated and expanded release regression checks for package metadata, local sitemap assets, removed remote News feed code, and nonce-protected admin handlers.
* Prepared a clean WordPress.org submission ZIP with the 2.9.76 version and current stable tag.

= 2.9.75 =
* Removed the optional live News feed (remote announcements.json request) and its admin screen, prompt, styles and script; the plugin no longer requests remote announcement data or remote images.
* Removed WordPress.org directory asset files (icons, banners, social images) from the plugin package; they are uploaded separately through SVN.
* The sitemap stylesheet (XSL) now embeds the bundled sitemap CSS and JavaScript from the plugin's own local files instead of linking them.
* Added explicit nonce and capability verification inside every handler that reads submitted data, including the Netlify account-link callback state.

= 2.9.74 =
* Sitemap stylesheet (XSL) no longer prints inline style/script blocks; its CSS and JavaScript are served from bundled assets/css/sitemap.css and assets/js/sitemap.js.
* Sanitized all remaining $_POST, $_GET, $_REQUEST, $_COOKIE, $_SERVER and $_FILES reads at the point of use (AdminAccess, TrafficGuard, redirects, 404 monitor, import, Baidu, post meta, local SEO, onboarding, live blog, internal links, authentication and Search Console forms).
* Verification files are filtered through a strict tag allow-list before saving and when served, and are output with wp_kses().
* Escaped output late for the editor score ring, live bar, verification meta tags, schema-type dropdown and JSON-LD (JSON-LD no longer uses JSON_UNESCAPED_SLASHES).

= 2.9.73 =
* Losslessly optimized the large publisher banner, social-sharing image, and two animated WordPress directory icons while preserving exact decoded pixels, format, dimensions, 24-frame timing, and looping.
* Reduced the combined size of the 20 shipped PNG/GIF assets from 4,083,704 to 3,948,728 bytes (134,976 bytes, 3.31%); no remote assets or image services were introduced.
* Kept tiny Composer development-vendor SVG report icons unchanged; they are not runtime plugin assets and are excluded from the WordPress ZIP. The bundled Font Awesome vendor directory contains only CSS/fonts, not image files.
* Synchronized plugin header, runtime version constant, and WordPress.org stable tag to 2.9.73.

= 2.9.72 =
* Changed the opt-in News feed source to the official public GitHub announcements.json file and accepted GitHub Raw’s text/plain JSON delivery.
* Added a branded, dismissible activation consent prompt with explicit enable, decline, and not-now choices; the feed remains off until enabled.
* Disclosed GitHub Raw and Netlify image/link requests in the consent UI, privacy-policy suggestion, and WordPress.org readme.
* Applied a solid-white alpha-mask treatment to the PublishRank sidebar icon so it matches the header logo.
* Added activation-state, endpoint, and text/plain MIME regression coverage; synchronized version metadata to 2.9.72.

= 2.9.71 =
* Added an explicitly opt-in PublishRank News admin screen with a validated, cached live JSON feed, announcement images, summaries, details and approved links.
* Protected feed controls with the standard capability/nonce guard; disabled remote requests by default and added cache cleanup, stale fallback, strict same-host HTTPS URL validation and privacy disclosures.
* Added dedicated News feed documentation and synchronized plugin version metadata to 2.9.71.

= 2.9.70 =
* Applied project-wide PHP coding-standard corrections and added a repository-owned PHP-scoped PHPCS ruleset compatible with PSR-4 class files.
* Preserved the optional Netlify Identity account-linking changes on main and aligned its account-linking documentation.
* PHPCS now reports zero errors; 177 warnings across 50 files remain visible as a tracked non-blocking backlog.
* Updated four source-level regression checks to accept formatting variations without relaxing the tested IndexNow, schema, or sitemap limits.
* Verified all 31 standalone PHP tests, PHP lint, JavaScript syntax checks, and release packaging.
* Recorded the unresolved live WordPress editor/screen interaction testing gap in `docs/RELEASE-2.9.70.md`.

= 2.9.69 =
* Resolve the follow-up WordPress Plugin Check findings: add translator context for placeholder strings, order printf placeholders, replace dynamic gettext labels with literal strings, and escape/Sanitize the flagged admin output.
* Add a clean release ZIP builder that omits repository metadata, hidden files, tests, development tools, and local dependencies; the generated archive contains a single `publishrank/` directory.
* Remove the unused invalid `brain/context ^3.0` development dependency, allow the PHPCS installer explicitly, and add a usable smoke-check Composer script.
* Add another release validation and gap report in `docs/RELEASE-2.9.69.md`.

= 2.9.68 =
* Enqueue the editor SEO score-card interaction script on supported post editor screens so the card can be moved with mouse, pen, or touch input.
* Replace the admin-toolbar raw style block with a local stylesheet enqueued through WordPress.
* Restrict Local SEO form helper output to an explicit HTML allowlist.
* Synchronize the plugin header, runtime version, and readme stable tag.
* Add a detailed development, security, troubleshooting, testing, and release guide.

= 2.9.67 =
* Restyled the PublishRank dashboard welcome banner in a deliberate plum-to-wine palette, using blush for readable supporting text and hot pink only for the main action and small accents; added a responsive publisher-themed motif.

= 2.9.66 =
* Added WPS-style custom login routing: standard direct login is hidden when enabled, WordPress-generated login links use the configured key, and unauthenticated `/wp-admin/` requests are sent to the custom entry link.
* Kept native admin URLs and plugin pages unchanged for signed-in users; preserved the requested admin subpage after login and left recovery, registration, logout, AJAX, REST, cron and admin-post flows available.
* Used a query-key entry URL to avoid taking over existing page/permalink slugs; clarified the security, caching, compatibility and recovery limitations in Settings.

= 2.9.65 =
* Safety correction: removed all PublishRank blocking of native `/wp-admin/` and `/wp-login.php` routes so publishers retain the normal WordPress recovery path and other plugins' administration pages keep working.
* Replaced the path-based entry alias with a query-key login shortcut, preventing collisions with existing WordPress pages and permalinks. Updated Settings to state that this shortcut is not an access-control boundary.

= 2.9.64 =
* Hardened custom wp-admin entry handling with an init-time fallback for server/permalink configurations that bypass the standard rewrite parser.
* Replaced the redirect add action with an explicit submit button and made the PublishRank toolbar submenu open consistently on hover and keyboard focus.

= 2.9.55 =
* Fixed technical source provenance not appearing when a theme omits `wp_head()` or when SEO metadata was already present. The fallback now injects the always-on provenance markers independently of metadata/schema recovery and avoids duplicates. Added regression tests for themes missing wp_head() and for pages where SEO metadata already exists.
* Added guarded shutdown cleanup for PublishRank-owned frontend fallback output buffers; cleanup only flushes the matching topmost PublishRank buffer and does not close another plugin's buffer.
* Added direct-web-access guards to all standalone regression tests and corrected the stale source-provenance test fixture and Branding fallback version.
* Synchronized first-party runtime CSS with reviewable source copies and restored the onboarding quick-start styles used by the current onboarding markup.

= 2.9.53 =

= 2.9.52 =
* Added a responsive activation welcome screen with a quick-start guide and clearer legal disclosure for optional public attribution.
* Improved PublishRank toolbar and dashboard menu alignment across desktop, folded-sidebar and mobile admin layouts; shipped a white icon treatment for dark WordPress chrome.

= 2.9.51 =
* New: Site Verification page, first entry of the PublishRank menu. Verify ownership with Google Search Console, Bing, Yandex, Baidu, Naver, Seznam, Pinterest and Facebook domain meta tags, any other tag through a safe free-form box, or verification files (google….html, BingSiteAuth.xml and similar) uploaded or pasted in the page and served from the site root without FTP; a real copy is also written to the web root when it is writable.
* Pasting a complete <meta> tag now works everywhere (previously the tag was stripped to garbage). Tags pasted in the wrong field are moved to the right engine.
* Live check fetches the home page and each file the way a crawler does and reports Live, Warning (another plugin prints a conflicting value) or Problem, with the reason. Common page caches are purged on save. Tags are printed early in <head> with a last-resort injector for themes that omit wp_head().
* Integrity baseline build bumped (r5) so adding the new files does not raise a false tamper warning.
* New one-click "Sign in with Google" for Search Console through the PublishRank sign-in service (Supabase Edge Function): site owners no longer create or paste a Google OAuth client ID/secret. Refresh tokens and the OAuth client secret stay on the service; the site keeps only a revocable connection. A connection is issued only when the Google account has a Search Console property for the requesting domain.
* Property is matched to the site automatically; data syncs on connect.
* Live data layer: hourly background sync plus Heartbeat (15 s) updates for clicks, impressions, 48-hour hourly chart, top queries and pages, Google Discover and Google News totals, and a newsroom feed (published today, article SEO scores, IndexNow queue, 404 count). Live status bar under every PublishRank header. REST: GET /publishrank/v1/live, POST /publishrank/v1/live/refresh (administrators only).
* Search Console data now includes provisional current-day numbers (dataState all) so newsroom changes appear sooner.
* Publisher Account: Continue with Google is primary; other providers are shown only if enabled on the Supabase project.
* Replaced duplicate dashboard action lists with seven direct-action workspace cards, including Traffic Guard, with no nested action menus.
* Added opt-in local IP/CIDR block and allow rules plus trusted-proxy Cloudflare country rules. Invalid/untrusted geo headers fail open; admin, recovery, API and sitemap routes are exempt; Traffic Guard stores no visitor IPs.
* Admin palette refreshed to warm paper, deep plum, evergreen and brass; the dashboard hero artwork and active PublishRank menu highlight now match. Bundled Font Awesome Free 7.3.1 assets include their license.
* Disconnect revokes Google access and removes the service-side connection.
* Advanced: own Google OAuth client is still supported and takes precedence when saved.
* Live Preview in the post editor (block and classic): search snippet with pixel and character meters, Facebook and X cards, every meta tag, the exact JSON-LD (syntax-highlighted, copyable, with a Rich Results Test link) and a checks list. It is built from your unsaved edits by the same code that outputs the page, nothing is saved by previewing, and it refreshes as you type. REST: POST /publishrank/v1/preview/{id} (users who can edit the post).
* Fixed: the article score card now reads the real SEO title, description and focus keyword fields and the block-editor title.
* Fixed: JSON-LD identifiers could mix http and https on sites behind a proxy that does not forward HTTPS, leaving references unresolved. The configured scheme is now kept.
* XML sitemaps: styled index and child pages gain a type switcher, and Topics and Authors now carry a lastmod in the index.
* robots.txt: new SEO-tool crawler group (Ahrefs, Semrush, Majestic, Moz, DataForSEO, BLEXBot, PetalBot) with a one-click preset, optional WordPress housekeeping rules (xmlrpc.php, wp-login.php, ?author= enumeration, REST users list, comment feeds), WooCommerce cart and account rules, and protected paths that keep AI crawlers out of paywalled or members-only areas. Per-crawler groups now repeat the low-value and tracking rules instead of silently dropping them. Each section carries its own explanatory comment.
* llms.txt: password-protected and noindex posts are never listed; About, Contact, Editorial policy, Corrections, Ethics, Team and Privacy pages are detected and listed first; authors, tags, custom post types and a machine-readable resources section (sitemaps, news sitemap, robots.txt, RSS) were added; archives move under the Optional section defined by the format; descriptions use the PublishRank meta description and carry the publish date. llms-full.txt now has per-article metadata (date, update, author, section), authority pages first, a per-article word cap, a clean header and no empty summary line. Both files are cached until content changes and answer conditional requests (ETag, Last-Modified, 304). The settings screen shows a preview with a review of common mistakes (physical file in the web root, credentials in text, size, robots.txt conflicts).

= 2.9.50 =
* Added publisher schema types: ReportageNewsArticle, AnalysisNewsArticle, OpinionNewsArticle, BackgroundNewsArticle, ReviewNewsArticle, SatireNewsArticle, AskPublicNewsArticle and BlogPosting, plus FAQPage, AboutPage, ContactPage, CollectionPage, AudioObject and PodcastEpisode.
* Schema type is now selectable per post, page, category, tag and other taxonomy term (edit screen), plus site-wide defaults for category, tag, other archives, author pages and search results (PublishRank > Schema). FAQ Page takes questions and answers in the schema box and falls back to a standard web page when none are complete, so an empty FAQPage is never published.
* Public attribution is optional and disabled by default. No promotional HTML comment, link or footer credit is forced into public pages; administrators can opt in to version/fingerprint markers or a visible footer credit in Settings.
* Removed the forced head-comment module and its theme-recovery path; the SEO fallback now restores only missing metadata and JSON-LD. Generated sitemap audits verify child references against enabled providers and report duplicate URLs. Expanded live diagnostics to validate actual JSON-LD and check the sitemap index and up to ten same-origin child sitemap endpoints, including News Sitemap date freshness.
* Documented Google OAuth/Search Console, Supabase Auth, IndexNow and Baidu outbound data and official terms/privacy links; corrected the inaccurate external-link-check description.
* Added linear-gradient styling to the dashboard, settings screens and XML sitemap viewer. Public publisher pages are not styled by PublishRank.
* Robustness: schema and head output are now fail-safe (a PHP error while building them can no longer break the public page); the integrity baseline rebuilds automatically so this update does not trigger a false tamper warning; fixed the stale 2.9.49 fallback version string.
* Made Standard WebPage the explicit default schema for pages and made it selectable in the page editor.
* Added automatic ImageObject nodes for singular pages and posts with safe image fallbacks.
* Added multiple organization alternate-name variants and expanded PublishRank dashboard/toolbar shortcuts.
* Fixed dashboard welcome contrast and SEO score ring typography.

= 2.9.49 =
* Synchronized the package version metadata across the plugin header, runtime constant, readme stable tag and release checks.
* Removed the standalone local integration harness that invoked shell_exec and hard-coded localhost; it is not required for normal plugin operation.

= 2.9.48 =
* Maintenance release for the corrected news-publisher schema and breadcrumb output.
* Updated WordPress.org submission metadata and release version consistency.

= 2.9.47 =
* Normalize legacy Report/Review schema metadata to supported Article or NewsArticle output.
* Harden breadcrumb labels and ListItem positions when publisher or canonical data is incomplete.
* Keep the public source repository documented for WordPress.org review.

= 2.9.46 =
* Fixed the blank white XML sitemap page: the sitemap stylesheet request ended in a PHP fatal error ("Cannot use output buffering in output buffering display handlers"), so the browser had nothing to render. The head-recovery fallback no longer opens an output buffer inside a buffer callback; it renders at shutdown instead.
* Fixed the same fatal error blanking every front-end page whenever PublishRank's head output was off or missing, which also removed all JSON-LD from those pages.
* The sitemap stylesheet now has the same stale-rewrite-rule safety net as the sitemap XML, discards stray output before the XML declaration and is served as text/xsl.
* Every front-end document now gets a WebPage-family schema node: author archives output ProfilePage, search results SearchResultsPage, 404 pages WebPage, and the "Homepage webpage type" setting is honored on blog-style home pages (previously always CollectionPage).
* Fixed "Run graph scan": the follow-up auto-continue script threw "form.submit is not a function" (WordPress names the button "submit"), leaving the scan stuck at 0% until "Continue graph scan" was clicked by hand.
* Fixed the Graph settings form, which printed settings_fields() and so posted action=update instead of its own admin-post action.
* The content graph and image/video sitemaps now include pages (pages are public but not publicly_queryable, so they were silently excluded).
* Fixed persistent JSON-LD output for themes that omit wp_head() by adding a safe head-injection fallback.
* Fixed internal-link graph statistics by preserving edges after each scan.
* Added automatic external-link nofollow with explicit approved-domain exceptions; the primary domain and all subdomains remain followable.
* Hardened schema output checks for NewsArticle, Article, page overrides and related schema entities.

PublishRank changelog

2.9.44
- Consolidated and hardened the real-time article SEO analyzer.
- Added TinyMCE, Gutenberg, and Classic Editor content extraction with debounced updates.
- Fixed score-card and analysis-panel synchronization and supported editorial post-type checks.
- Fixed PublishRank toolbar icon/label and sidebar icon alignment.
- Retained the expanded schema registry and type-specific schema handling.
- Corrected the root GPLv2-or-later license notice and attributed project rights to Muhammad Umar Jabbar.

2.9.43
- See docs/RELEASE-2.9.43.md for the prior sitemap and schema release notes.

Implementation provenance: PublishRank's publisher toolkit is a custom implementation; it contains No Rank Math source code.

2.9.56
- Preserved the existing Live Preview SERP and connected schema graph systems.
- Added validated Facebook publisher Page and per-author profile attribution.
- Added optional cached, non-destructive social-share image watermarking with position, opacity, size and margin controls.

2.9.57
- Fixed real-time SERP preview field serialization for unsaved SEO metadata.
- Improved Gutenberg content/meta change detection and reduced preview debounce latency.
- Added reliable retry and manual refresh behavior without page reloads.

2.9.58
- Added a visitor-facing Website View to Live Preview for visible heading, summary, URL, social image, and schema consistency.
- Added advanced GitHub README documentation.
