=== Schemafy ===
Contributors: schemafy
Tags: schema, structured data, seo, json-ld, rich snippets
Requires at least: 5.8
Tested up to: 7.1
Stable tag: 1.9.28
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Build Schema.org JSON-LD without code, manage SEO meta tags and social previews, and keep every rich snippet in one library.

== Description ==

**Schemafy** is a powerful WordPress plugin that generates structured data (Schema.org JSON-LD) for your content, helping search engines better understand your site and improving your chances of earning rich snippets in Google Search results.

= What's Included in the Free Plugin =

* **Smart Builder** – Visual, field-by-field builder for Article, Product and Organization schemas (including their Schema.org subtypes such as NewsArticle and BlogPosting)
* **Rich Snippets Manager** – One library for every schema on your site: search, filter, edit, activate/pause, duplicate and delete, individually or in bulk
* **Schema Validation** – Check any schema against Schema.org requirements and see exactly what is missing
* **CSV Import & Export** – Move schemas in and out of the plugin in bulk
* **SEO Meta Tags** – Manage title, description, canonical and robots meta tags from a single panel, one page at a time or by CSV import
* **Social Media Previews** – Open Graph and Twitter Card support for Facebook, Twitter/X and LinkedIn
* **SEO Health Dashboard** – Audit your site's SEO health with actionable recommendations
* **Sitemap Generator** – XML sitemap index with duplicate sitemap conflict control
* **Gutenberg Sidebar** – Native block editor sidebar for per-post schema management
* **Manual JSON editor** – write or paste raw JSON-LD with dynamic variables like {post_title}

= Available in the Paid Plans =

These features are **not part of this free download**. They are listed so you know what an upgrade adds:

* **AI Generator** – generate schema from a page's content automatically
* **AutoGenerator** – scan the whole site and apply the right schema type in bulk
* **13 more Smart Builder types** – LocalBusiness, Person, Event, Recipe, Review, FAQ, WebPage, Course, HowTo, JobPosting, Service, Video and BreadcrumbList
* **Bulk maintenance tools** – Fix Errors, Clean Orphans, Remove Duplicates and Clean Embedded Schemas

== Installation ==

1. Upload the `schemafy` folder to the `/wp-content/plugins/` directory
2. Activate the plugin through the **Plugins** menu in WordPress
3. Navigate to **Schemafy** in the WordPress admin sidebar
4. Configure your default settings and start building schemas

== External Services ==

The AI Generator is a paid feature and its code is not included in this free download, so this plugin makes no request to the service below unless you upgrade. Documented here for transparency: when present, the AI Generator sends the current page's URL and content to the Schemafy AI generation API to produce structured data, and only when the user explicitly starts a generation request.

* Service: Schemafy AI generation API
* Endpoint: https://endpoint-schemafy.vercel.app/api/generate
* What is sent: target page URL, scraped page content, requested schema type
* When: only when the user clicks "Generate Schema with AI"
* Privacy policy: https://schemafy.net/privacy-policy/

This plugin also integrates the Freemius SDK for licensing and updates. See https://freemius.com/privacy/ for its data practices.

No data is collected passively or without explicit user action.

== Frequently Asked Questions ==

= Does Schemafy work with the block editor (Gutenberg)? =

Yes. Schemafy includes a native Gutenberg sidebar panel so you can manage schemas directly from the post editor.

= Which schema types are supported? =

The free plugin builds Article, Product and Organization schemas (plus their Schema.org subtypes) and stores, validates and injects any schema type you import by CSV. Thirteen further builder types — LocalBusiness, Person, Event, Recipe, Review, FAQ, WebPage, Course, HowTo, JobPosting, Service, Video and BreadcrumbList — are part of the paid plans.

= Does it affect my site's performance? =

Schemafy injects lightweight JSON-LD in the `<head>` and has no impact on your page rendering. All admin scripts load only on plugin pages.

= Is it compatible with other SEO plugins? =

Yes, and it stays out of their way by default. Schemafy never disables another plugin's schema output on its own. If you want Schemafy to be the only source of structured data, go to **Plugin Compatibility** and switch on what you want suppressed (Yoast SEO, Rank Math, All in One SEO, SEOPress, The SEO Framework, WooCommerce, and JSON-LD embedded in post content by themes or blocks). Every toggle is off until you turn it on.

== License ==

This plugin is licensed under the GPLv2 or later. See the LICENSE file for details.

Schemafy includes the Freemius SDK (https://freemius.com/) for licensing and update notifications. The Freemius SDK is also licensed under GPLv2 or later.

== Changelog ==

= 1.9.28 =
* Declared compatibility with WordPress 7.1, released this week — the automated WordPress.org scan requires "Tested up to" to name the current version

= 1.9.27 =
* Updated the bundled Freemius SDK from 2.13.1 to 2.13.4, the current stable release. Maintenance fixes from upstream: a configurable API timeout, additional payment-history currencies, an updated pricing page, and PHP compatibility corrections. No file was added or removed, and the plugin had never modified the SDK, so the upgrade is the vendor's release verbatim

= 1.9.26 =
* Fixed Validate in the Manual JSON tab always reporting "Missing @type". It looked for @type on the top level of the document only, so an `@graph` container — the shape Yoast, Rank Math and most markup copied off a live page use — and a plain array of schemas were both reported as untyped whatever they actually held. It now walks the same three document shapes the save handler already walked, and says how many schemas are missing a type rather than just that one is
* Two more faults in the same check: an `@context` written as an object (`{"@vocab": "..."}`) or an array threw an error that reached the user as a bogus "Invalid JSON" syntax message, and an `@context` array containing schema.org was flagged with a warning saying it did not
* The Validate button had two handlers bound to it and ran both on a single click. One only re-parsed the JSON, so it announced success while the structural check announced an error about the very same content
* Validate now checks what a schema type actually requires, not just that it has a type. It reads the same field definitions the Smart Builder is generated from, so an Article missing its headline or a Product missing its name is reported by name, properties that are present but empty count as missing, values over the recommended length are flagged, and nested objects with no `@type` are pointed out. Types this package ships no definition for are checked for structure only and say so, rather than inventing requirements
* The bulk schema validator used a separate hand-written list that knew only Product, Article and FAQPage, so everything else passed unchecked. Both validators now run the same check
* Security: notification and confirmation dialogs built their markup around the message text, so a schema name, URL or error quoting user-supplied content could inject markup into the admin screen. Messages are now inserted as text, and the bulk validation report escapes the values it displays
* Fixed paid plans being treated as unlicensed. Tier checks asked Freemius with a method that lowercases the plan name it is handed but not the one it compares against, so a plan whose name carried any uppercase matched no tier and every paid feature stayed locked for a customer who had paid for it. Tiers are now matched case-insensitively, and a plan name the plugin does not recognise is written to the debug log instead of silently locking the interface
* SEO title and meta description are now genuinely shared with your SEO plugin in both directions. Saving from Schemafy already wrote Rank Math's, Yoast's, SEOPress' or The SEO Framework's own field, but the Meta Tags panel filled its inputs from a separate URL-keyed store that those plugins cannot write — so an edit made in their panel never showed up in Schemafy. The panel now reads the shared field for any URL that is a post
* The SEO Health dashboard was scoring titles and descriptions against a pair of meta keys nothing has written since 1.9.24, and recognised only Yoast and Rank Math. It reads the same shared field as the rest of the plugin now, so SEOPress and The SEO Framework values count too
* Fixed the "source" label beside each meta tag: it re-tested for every SEO plugin on its own and looked for Rank Math by class name only, so it could credit WordPress for a value Rank Math owned
* Removed the classic-editor meta box. It had been unreachable since v1.6.8 — its hooks were commented out, so its save handler could never receive the nonce it required — and it was the last holder of a third, orphaned set of meta keys
* WordPress.org compliance: every function, class, constant, global, hook, AJAX action, option, meta key and database table now carries the plugin's own `schemafy` prefix. The code had grown up under an older working name and still used a prefix unrelated to Schemafy, in two inconsistent flavours — a conflict risk with any other plugin that happened to pick the same short word
* Existing installs are migrated automatically on the first load after updating: options, post meta, user meta and the schemas table are renamed in place before anything reads them, so no setting, meta tag or saved schema is lost. Stale caches written under the old prefix are dropped so fresh output is not shadowed
* The purge calls for LiteSpeed Cache, SiteGround Optimizer and Cache Enabler now run through one guarded loop instead of three near-identical blocks. Those hook names belong to those plugins and cannot carry our prefix; each still fires only when its owner registered it
* Security: a schema value could break out of the JSON-LD `<script>` block it is printed in. The encoder neutralised the exact text `</script>`, but HTML also ends a script element at `</script` followed by a space, tab, newline or slash — so a value containing `</script >` became live markup on the frontend for every visitor. All schema output now goes through one encoder that escapes every `<`, which closes the whole class of breakout rather than the one spelling. The escape is standard JSON, so Google reads the schema back unchanged
* Removed a second, unused copy of that encoder that carried the same flaw and was one call away from reintroducing it
* Per-post SEO meta written from the block editor now authorises against the specific post being edited instead of the generic "can edit posts" capability, so the plugin's own gate no longer depends on WordPress checking the post first
* Admin pages moved from `admin.php?page=baseo-custom-schema` to `admin.php?page=schemafy-custom-schema`. Update any bookmark you kept to the old address

= 1.9.25 =
* Fixed PHP 8 "Undefined array key" warnings when a schema save, bulk save or update request arrived without every field. The handlers validated for missing fields, but only after reading them, so the warning was emitted first. Request fields now go through one guarded reader that returns an empty value instead
* A row ID posted as a negative number is now refused rather than silently turned into a different, real row
* Sanitized $_SERVER['REQUEST_URI'] before parsing it in the sitemap request router
* Documented, rather than changed, the places Plugin Check flags that are correct as written: raw JSON-LD payloads must not go through sanitize_text_field() (they are decoded, sanitized recursively and re-encoded instead), the schema_id read is read-only UI state with no action to protect, and litespeed_purge_all is a third-party hook name that must match LiteSpeed's exactly

= 1.9.24 =
* The Manual JSON editor is now a free feature. It was previously gated behind a paid plan while the free package still shipped the editor module and the same raw-JSON code mode in the snippet editor — the tab now simply works for everyone, and the gate, the upgrade teaser and the "not in your plan" states are gone
* Removed the frontend output buffer entirely. Schemafy no longer calls ob_start() to rewrite the finished page: duplicate JSON-LD is prevented through each SEO plugin's own filters, so the buffer stack is never touched and cannot misalign with another plugin's buffers
* Third-party schema suppression is now opt-in and actually reads the setting. The Plugin Compatibility toggles were saved to the database but never applied — Schemafy suppressed Yoast, Rank Math, AIOSEO, SEOPress, The SEO Framework and WooCommerce unconditionally. Every suppression now requires its toggle to be on, and all toggles default to off. SEOPress and The SEO Framework gained the toggles they were missing
* WooCommerce structured data in order emails is no longer removed. Schemafy only ever replaces frontend schema, so the email hook is left alone; the frontend removal is opt-in like the rest
* Stripping JSON-LD that themes and blocks render inside post content is now opt-in too. It ran on every page and deleted other components' structured data with no way to switch it off; it has its own Plugin Compatibility toggle now, off by default
* Fixed duplicate title and social tags. With a custom meta title and no SEO plugin installed, Schemafy emitted a second <title> alongside WordPress's own, plus a duplicate set of og: and twitter: tags. The title now goes through the pre_get_document_title filter that WordPress provides, so core renders exactly one <title> and Schemafy no longer removes core's title rendering
* Fixed titles that changed depending on which plugins were installed. Two code paths resolved the same page's title and description from different sources — one read post meta and the options table, the other read the SEO detector and the schema table. They are one resolver now, so the <title>, the meta description and the social preview always agree
* Fixed placeholder text leaking into titles, social previews and schemas. Rank Math and Yoast store meta titles as templates such as "%title% %sep% %sitename%" and expand the variables themselves; Schemafy read those stored values and re-emitted them raw, so a visitor could see the literal placeholders. Schemafy now only ever overrides with a value you entered in Schemafy, and where it needs the page's real title it asks WordPress for the rendered one
* Meta title and description now live in ONE place. If the site runs Yoast SEO, Rank Math, SEOPress or The SEO Framework, Schemafy reads and writes that plugin's own post meta instead of keeping a second copy — so a title typed in Rank Math shows up in Schemafy, a title typed in Schemafy shows up in Rank Math, and that plugin's snippet preview and content score finally reflect the value that actually ships. Schemafy no longer overrides their frontend output on posts either, because there is nothing left to override: they are rendering the user's own value
* Fixed a case where the meta description could silently disappear. Each part of the plugin detected the active SEO plugin its own way — Slim SEO by one function in one place and a different constant in another, Rank Math by class in one place and constant in another — so a plugin could count as "active, it will render the tag" for one decision and "absent, no filter needed" for the next, leaving the tag rendered by nobody. Detection now comes from a single list
* Schemafy's Gutenberg panel no longer draws a duplicate SEO title / meta description field when another SEO plugin owns them. Its own panel is in the same editor; Schemafy shows the shared value in its preview and points you there
* Turning off Yoast SEO and Rank Math sitemaps is now opt-in. Enabling Schemafy's sitemap used to disable theirs with no way to say no; it now has a Plugin Compatibility toggle like every other override, off by default. WordPress core's own sitemap is still stood down automatically, since Schemafy's sitemap is itself opt-in and core's is only a default
* Rank Math's sitemap caching is no longer disabled. It slowed that plugin down without resolving any conflict
* Removed an unused Freemius plans endpoint that shipped in the free package. Nothing called it, and it referenced an external API that the readme's External Services section did not document
* Fixed half-escaped values in the admin. Schema names, URLs and types were escaped with an idiom that encodes angle brackets but not quotes, then interpolated into HTML attributes — a value containing a double quote could break out of the attribute and inject markup into the Snippets Manager, dashboard, sitemap and builder screens. All 25 sites now use one shared helper that escapes quotes as well
* Replaced a raw ini_set() memory bump with wp_raise_memory_limit(), the WordPress API for it: it respects WP_MAX_MEMORY_LIMIT, hosts can filter it, and it never lowers a limit that is already higher
* Removed a deprecated, uncalled schema-variable method that still used json_encode() instead of wp_json_encode()
* Escaped brand name, colour and URL output in the plugin row, help tab and action links
* The build guard now asserts the guideline rules rather than a list of past mistakes: it fails if shipped code opens an output buffer, gates a free feature behind a plan, overrides another component without a compatibility toggle, or contacts a host the readme does not document

= 1.9.23 =
* readme: the Contributors list now names the plugin owner's WordPress.org account, schemafy
* Fixed the Author URI in the plugin header, which pointed at a profile that does not exist and therefore 404'd from the plugins directory listing

= 1.9.22 =
* Hardening: the Freemius SDK instance is now null-checked everywhere. schemafy_fs() returns null if the SDK fails to initialise, and four call sites chained onto it directly to build the upgrade link — any of them would have taken down a whole admin page over a URL. They now share one schemafy_upgrade_url() helper that falls back to the bundled pricing screen, the bootstrap binds the instance once instead of chaining, and the paid build's plan check denies access instead of fatalling on a null instance

= 1.9.21 =
* WordPress.org compliance: the free package no longer contains any paid-feature code. The AI Generator, AutoGenerator and bulk maintenance tools (Fix Errors, Clean Orphans, Remove Duplicates, Clean Embedded Schemas) had their JavaScript, admin markup, button wiring and AJAX handlers moved into premium-only files that are stripped from the free build — the free plugin now shows a plain upgrade link where those tools would be, instead of disabled controls backed by shipped code
* WordPress.org compliance: removed every plan check from the free package. schemafy_can_access(), the per-tier flags (can_basic / can_mid / can_full), the paid schema-type list and all lock badges now live in the paid build only. The free plugin decides what to render from what it actually ships, never from a payment state
* Smart Builder type cards are now generated from the field configs present in the build, so the free package lists the three types it can build instead of sixteen cards with thirteen padlocks
* The admin script loader now enqueues a module only when its file exists and prunes missing modules from other modules' dependencies, so a stripped build loads a correct, complete dependency graph
* Security: the AI proxy endpoint and its service token moved to the paid build — the free package ships no service credential
* Security: sanitized the last unsanitized request reads (schema toggle status, admin menu page parameter) and escaped ternary attribute output in the sitemap and meta box templates
* Security: bound the table-existence check through $wpdb->prepare() and documented every remaining direct query on the plugin's own table
* Removed 69 leftover console.log statements from the shipped JavaScript
* readme: added the plugin owner to the Contributors list
* Regenerated languages/schemafy.pot from source with a proper header; no .po/.mo files are bundled (translations come from translate.wordpress.org)
* Added scripts/check-free-build.php, which reproduces the Freemius strip and fails the build if any paid endpoint, module or credential is still referenced by a shipped file

= 1.9.20 =
* WordPress.org compliance: the 13 paid Smart Builder schema types (LocalBusiness, Person, Event, Recipe, Review, FAQ, WebPage, Course, HowTo, JobPosting, Service, Video, BreadcrumbList) now ship their field-config data only as premium-only files stripped from the free build; the builder enforces plan access server-side so locked types cannot be generated by bypassing the UI
* WordPress.org compliance: paid bulk maintenance tools (Fix Errors, Clean Orphans, Remove Duplicates, Clean Embedded Schemas) moved to a premium-only file — their functional code is no longer shipped in the free build, only an upgrade prompt; premium build now also enforces plan access server-side
* Security: added schemafy_sanitize_json_recursive() and applied it to every request-derived JSON payload (schema import, save/update, Smart Builder) so decoded data is sanitized before storage
* Fixed leftover onboarding JavaScript that rendered as plain text at the bottom of admin tabs — the entire tour is now loaded via wp_enqueue_script from an external file with no inline code
* Removed bundled .po/.mo translation files (WordPress.org generates translations via translate.wordpress.org); kept the .pot template
* Renamed the Freemius accessor helper away from its 3-character prefix; documented third-party cache-purge hooks

= 1.9.19 =
* WordPress.org security: sanitize all schema_data and field_config JSON payloads via wp_json_encode after validation
* Fixed 8 instances of raw JSON input not being sanitized before storage in database
* Updated Contributors list with correct WordPress.org username

= 1.9.18 =
* WordPress.org compliance: removed all inline <script> tags from templates; onboarding tour system now loaded via wp_enqueue_script with wp_localize_script
* WordPress.org compliance: renamed the generic hook sch_fs_loaded to a plugin-specific name to ensure unique prefixing
* Verified all 39 plugin functions share a single prefix for conflict prevention

= 1.9.17 =
* WordPress.org compliance: explicitly closed output buffer on wp_footer to prevent buffer stack misalignment (ob_start/ob_end_flush paired in same logical flow)
* WordPress.org compliance: extracted all 10 inline <style> blocks from templates into inline-styles-admin.css and enqueued via wp_enqueue_style()
* Verified all external services (Schemafy AI API, Freemius SDK) are documented in readme with full T&S and privacy policy links

= 1.9.16 =
* Removed the .distignore build helper so it is never bundled in the distributed package (WordPress.org does not permit hidden files)

= 1.9.15 =
* Plugin Check: removed the last interpolated SQL fragment by inlining the block-detection LIKE clauses (values bound via prepare) — zero security findings

= 1.9.14 =
* WordPress.org Plugin Check pass: prepared all remaining LIKE query parameters
* Unified premium upgrade labels across the Smart Builder and Bulk tabs

= 1.9.13 =
* Full WordPress.org Plugin Check compliance pass: output escaping, i18n translators comments and ordered placeholders, prepared SQL parameters, and recommended WordPress functions
* Hardened request handling: unslashing/sanitization of all admin form input
* Tested up to WordPress 7.0

= 1.9.12 =
* Third-party schema suppression (incl. WooCommerce) is now filterable for compatibility
* REST endpoint for schemas-by-url verifies edit rights on the specific post
* Text domain now loads on the init hook

= 1.9.11 =
* Security hardening: all nonce checks now sanitize input; fixed text domain mismatch; updated deprecated wp_count_terms() call
* Moved uninstall cleanup to the Freemius after_uninstall hook (a physical uninstall.php is incompatible with Freemius deployment)
* readme: Tested up to 6.9, corrected external-service URLs

= 1.9.10 =
* Plugin Check fix: removed __() calls on dynamic field-config strings; translations now resolve through the loaded textdomain without flagged template tags

= 1.9.9 =
* Plugin Check fix: Plugin URI and Author URI are now distinct (Author URI points to the WordPress.org author profile)

= 1.9.8 =
* WordPress.org compliance: debug logging gated behind WP_DEBUG, hardened input sanitization on bulk handlers, added LICENSE and uninstall cleanup, accurate external-services disclosure

= 1.9.7 =
* Apple-style admin redesign: lighter chrome, hairline borders, pill controls, soft status pills, airier tables

= 1.9.5 =
* Fixed stale schema cache on sites using an object cache (Redis/Memcached) or a page-cache plugin — schema changes now reflect immediately
* Schema mutations now purge WP Rocket, LiteSpeed, W3TC, WP Super Cache, WP Fastest Cache, SiteGround and Cache Enabler

= 1.9.4 =
* Bulk CSV import is now tolerant of unescaped double quotes in values
* Rich snippets export writes single-line JSON with a UTF-8 BOM (no more multi-line cells or mojibake in Excel)
* Portuguese and regional Spanish locales now load correctly (pt_PT to pt_BR, es_MX/es_CO to es_ES)

= 1.9.3 =
* Smart Builder validation blocks Google-rejected schemas (required fields, rating ranges, Service rating host, Recipe video completeness)
* Fixed dot-notation property leaks and removed unsupported aggregateRating from Service

= 1.9.2 =
* Sitemap is served path-first so it works with stale rewrite rules and plain permalinks; no more blank 404 pages
* Smart Builder: Schema.org compliance — currency/duration widgets, ISO 8601 dates, numeric input guards, gtin/mpn

= 1.9.0 =
* Schema type registry and improved subtype handling

= 1.8.9 =
* Bulk meta tags robustness and language updates

= 1.8.8 =
* Redesigned the Sitemap tab with a modern autosaving power toggle
* Added resilient sitemap autosave handling with request locking, revisions, queued retries, and structured errors
* Improved sitemap source selection UI with automatic save feedback and stale request protection

= 1.8.7 =
* Added Schemafy Sitemap tab with /sitemap-index.xml output and duplicate sitemap conflict control
* Added sitemap source selection, XML lastmod support, legacy sitemap redirects, and Rank Math compatibility handling
* Removed legacy Robots/LLM feature references from the public feature list

= 1.8.0 =
* Auto-Generator: heading-based detection (H2/H3 analysis for FAQ, HowTo, Recipe)
* Auto-Generator: category/tag taxonomy boosting — categories now confirm and boost schema types
* Auto-Generator: article detection extended to custom post types with author+editor support
* Auto-Generator: word threshold reduced to 150 for titled guides, tutorials, and listicles
* Auto-Generator: Course detector now uses title signals (masterclass, bootcamp, certification)
* Auto-Generator: Video detection expanded to Wistia, Loom, TikTok, Dailymotion, Rumble
* Auto-Generator: expanded keyword arrays for Recipe (cooking verbs + units), Event (RSVP, expo, meetup), Course (lessons, modules, learning objectives), Product (sale, warranty, specs), Job (remote, responsibilities, qualifications)

= 1.7.3 =
* Improved AI Generator: multi-page context support, richer schema output requirements
* Fix: SEO Health checks use user-provided OpenAI API key instead of shared key

= 1.2.12 =
* Fix: Remove target="_blank" from all upgrade links — Freemius checkout requires same-tab navigation to load its in-dashboard pricing context correctly

= 1.2.11 =
* Fix: Restore get_upgrade_url() to keep Freemius in-dashboard checkout popup working
* Fix: Smart Builder no longer blocks Freemius upgrade popup for locked schema types
* Fix: waitForFormAndPopulate timeout silently exits when card is locked (Freemius already handled upgrade flow), preventing false success toast

= 1.2.10 =
* Fix: Hotfix — replace get_pricing_url() (nonexistent) with _get_admin_page_url('pricing') to restore site

= 1.2.9 =
* Fix: All "Upgrade now" links open in a new tab instead of navigating away from the current page
* Fix: upgrade_url now points to the pricing/plans page instead of direct checkout

= 1.2.8 =
* Fix: Edit mode modal now shows locked options with upgrade CTA when schema type or Manual JSON requires a higher plan
* Fix: Removed false "Schema loaded successfully" notification when editor could not be opened due to plan restrictions
* Fix: Smart Builder and Manual JSON loaders now validate plan access before switching tabs or showing success messages

= 1.1.93 =
* Improved schema auto-detection accuracy for FAQ, Event, and Product types
* Fixed layout issue when WordPress admin menu is collapsed
* Updated design system to blue-only color palette
* Added Gutenberg sidebar integration
* Added Sitemap manager
* Performance improvements and code cleanup

= 1.0.1 =
* Initial public release

== Upgrade Notice ==

= 1.9.28 =
Declares compatibility with WordPress 7.1. No functional change.

= 1.9.27 =
Updates the bundled Freemius licensing SDK to the current stable release. No change to your settings, schemas or meta tags.

= 1.9.26 =
Contains a security fix for JSON-LD output — update promptly. Also an internal renaming release for WordPress.org compliance: your settings, meta tags and schemas are migrated automatically on the first page load after updating. The admin page address changes to admin.php?page=schemafy-custom-schema, so replace any old bookmark.

= 1.9.25 =
Housekeeping release: removes PHP 8 warnings on incomplete AJAX requests. No behaviour changes.

= 1.9.24 =
Manual JSON is now free. Schema suppression for other SEO plugins is now opt-in — if you relied on it, enable the toggles under Plugin Compatibility after updating.

= 1.9.23 =
Corrects the Contributors list and the Author profile link.

= 1.9.22 =
Hardening release: the admin no longer depends on the Freemius SDK having initialised successfully.

= 1.9.21 =
Compliance and security release: the free plugin no longer bundles any paid-feature code or credentials, and all remaining input/output handling was hardened.

= 1.2.10 =
Hotfix for fatal error introduced in 1.2.9. Upgrade now links correctly open the plans page in a new tab.

= 1.2.9 =
Upgrade links now open in a new tab and point to the plans page instead of direct checkout.

= 1.2.8 =
Fixes misleading success notifications when editing schemas on restricted plans. Upgrade CTAs now display inline in the edit modal.

= 1.1.93 =
Recommended update. Includes improved auto-detection, Gutenberg sidebar, and SEO health dashboard.
