McCrossenSEO

Wopisanje

McCrossenSEO™ handles all standard on-page SEO requirements out of the box — meta titles and descriptions, robots meta, canonical URLs, Open Graph, Twitter/X cards, JSON-LD schema markup, XML sitemap generation, redirect management, and bulk editing.

Free features (no account required):

  • Meta title and description management per post, page, and custom post type
  • Term-level SEO: title and description fields for categories, tags, and WooCommerce product taxonomies, rendered on term archives and the shop page
  • Character count indicators (60 for titles, 160 for descriptions)
  • Global title pattern with configurable separator
  • Robots meta controls (noindex, nofollow, max-snippet, max-image-preview, max-video-preview)
  • Canonical URL management with paginated content support
  • Open Graph meta (title, description, image) with fallback chain
  • Twitter/X Card meta with card type selector
  • JSON-LD schema markup (Article, WebPage, BreadcrumbList, Organization, LocalBusiness)
  • XML sitemap with configurable post types and automatic noindex exclusion
  • llms.txt: a plain-text list of your public pages and posts for AI crawlers, written to the site root once a day. It can be turned off in Settings, and an llms.txt you created or edited yourself is never overwritten or removed
  • Redirect manager (301, 302, 307)
  • Bulk editor for titles and descriptions across all content
  • Internal link suggestions
  • Import from Yoast, RankMath, AIOSEO, and SEOPress (one-click migration, including Yoast taxonomy term data)
  • Analytics and tracking code injection (GA4, GTM, Facebook Pixel) — only loads when administrator configures IDs
  • Site verification codes (Google Search Console, Bing Webmaster)
  • robots.txt editor — edit a physical file or serve a managed virtual robots.txt through WordPress
  • Diagnostics panel with an environment summary and a Send Diagnostic Report button (a report is sent only when you click it)

Optional connected features (requires McCrossen Marketing account):

  • URL Optimization scoring across 59 ranking signals
  • AI-powered SEO recommendations
  • One-click Plugin Bridge: apply recommended meta titles, meta descriptions, Open Graph and Twitter/X card titles, descriptions and images, and robots directives directly from the platform to your published content. Heading text is applied too when Heading Rewrites is turned on in Settings (off by default; skipped on page-builder content). Schema recommendations appear in the Bridge for you to implement manually.
  • Platform-pushed llms.txt
  • Automatic error reporting, on connected sites only: the plugin reports its own fatal errors and sync failures to McCrossen Marketing, at most once per error type per hour (details under External Services)

Merchant policies (optional, for WooCommerce stores):

Off by default. Turn it on in the Merchant policies section of the Settings tab to add a return policy and shipping details to your product structured data:

  • Return policy: the countries it applies to, a return window (a number of days, unlimited, or returns not permitted), the return method and who pays for return shipping. Single products or whole product categories can be marked „returns not permitted“.
  • Shipping details: rates entered by hand or built from your WooCommerce shipping zones, with handling and transit times. Only rates that can be stated exactly are included; the Settings tab previews each destination and says why any is left out.

Search engines decide whether to use this markup and may ignore it for some kinds of products.

The free version is fully functional as a standalone SEO plugin. No account or external connection is required for free-tier features.

Admin icon graphics are from the Twemoji project, licensed CC-BY 4.0, and are bundled with the plugin (no external requests).

External Services

This plugin connects to external services depending on which features the site administrator enables. The plugin makes zero external connections by default. All listed services activate only after explicit administrator configuration or connection.

McCrossen Marketing Platform

When: Only when the site is connected via the „Connect to McCrossen“ button under McCrossenSEO™ > Connect2McCrossen.
What is sent: each request below goes to mccrossenmarketing.com over HTTPS, except the page-draft image downloads in the last entry. Requests from a connected site identify it with the site’s connection key.

  • Connect (when an administrator clicks Connect to McCrossen): the browser opens mccrossenmarketing.com with the site’s domain, the site name, the plugin name and version, the address of the Connect2McCrossen page to return to, and a one-time security token. If the administrator pastes a connection key instead, the site sends that key and the site’s domain to be verified; the shared secret is not sent.
  • Disconnect (when an administrator clicks Disconnect): the connection key and a disconnect reason, so the platform can revoke the key.
  • Heartbeat (every 15 minutes while connected, as a WordPress scheduled task, and when an administrator clicks Sync Now on the Pending Optimizations page): the site URL, the plugin name and version, the WordPress and PHP versions, the post types included in the XML sitemap, and whether Heading Rewrites and Auto-Audit on First Publish are turned on. Once per plugin version, on the first admin page load while connected, a connection check sends only the site URL and the plugin version. The platform replies with recommendations for the Plugin Bridge, the account status, feature settings, and (where the account includes it) llms.txt content, which the plugin writes to the site root. The plugin applies a reply only when it carries a valid signature from the site’s connection; a reply without one is not applied.
  • Audit request (when a user who can edit posts clicks Audit This Page on a published post; connected sites only): the site URL, the plugin name, the post ID and its public URL, the audit level selected, a page type derived from the post type, and the post’s focus keyword if one is set.
  • Apply confirmation (each time the Plugin Bridge applies a recommendation; connected sites only): the site URL, the plugin name, the recommendation ID, the outcome and the time. A recommendation that was skipped or could not be applied is not reported.
  • Automatic error report (connected sites only, at most one per error type per hour): sent when a fatal PHP error occurs in the plugin’s own files, when a heartbeat reply fails or lacks its signature check, or when six or more heartbeats in a row have failed. Each report contains the site URL, the plugin name and version, the WordPress and PHP versions, the list of all active plugins on the site, the active theme’s folder name (for a child theme, its parent theme’s), the error type and message, the error details (for a fatal error, the file path on the server and the line number; for a failed signature check, the first 16 characters of the expected and received signatures, where a signature was present), and the time. Connecting the site turns automatic error reporting on; there is no separate setting to turn it off. Disconnecting the site stops it.
  • Diagnostic report (only when an administrator clicks Send Diagnostic Report on the Support & Diagnostics tab, whether or not the site is connected): the same site, plugin, WordPress, PHP, active-plugin and active-theme details as an error report, plus the last heartbeat time and status, the account status, whether Heading Rewrites and Auto-Audit on First Publish are turned on, detected page builders, the ten most recent entries of the plugin’s change history (post or term ID, change type, time and status), and the plugin’s database version.
  • Page-draft images (when the platform sends a page draft to a connected site): the site downloads each image listed in the draft from the web address the draft gives and adds it to the Media Library. These are standard WordPress downloads, which tell the server holding the image the site’s URL and WordPress version.

Why: Authenticated delivery of platform-generated SEO recommendations, account status and feature settings, page drafts and action-plan checklists that the platform sends to the site (saved as drafts for you to review), and (where the account permits) llms.txt content. Error and diagnostic reports send plugin problems to the maintainer.
Service URL: https://mccrossenmarketing.com
Privacy Policy: https://mccrossenmarketing.com/privacy-policy/
Terms of Service: https://mccrossenmarketing.com/terms-of-service/

Google Analytics 4

When: Only when an administrator configures a GA4 Measurement ID under McCrossenSEO™ Tracking & Verification.
What is loaded: The gtag.js script from https://www.googletagmanager.com/gtag/js.
Where: Site frontend, in <head> for site visitors, only on installs that have configured a GA4 Measurement ID. If a cookie-consent integration answers the mccm_seo_analytics_consent filter with false, the script is not requested until the visitor grants analytics consent.
Service: Google Analytics — https://policies.google.com/privacy and https://www.google.com/analytics/terms/

Google Tag Manager

When: Only when an administrator configures a GTM Container ID under McCrossenSEO™ Tracking & Verification.
What is loaded: The GTM script from https://www.googletagmanager.com/gtm.js, and a <noscript> iframe fallback to https://www.googletagmanager.com/ns.html.
Where: Site frontend, only on installs that have configured a GTM Container ID.
Service: Google Tag Manager — https://policies.google.com/privacy and https://www.google.com/analytics/terms/tag-manager/

Meta (Facebook) Pixel

When: Only when an administrator configures a Facebook Pixel ID under McCrossenSEO™ Tracking & Verification.
What is loaded: The pixel script from https://connect.facebook.net/en_US/fbevents.js and a tracking image from https://www.facebook.com/tr.
Where: Site frontend, only on installs that have configured a Pixel ID.
Service: Meta Platforms — https://www.facebook.com/policy.php and https://www.facebook.com/legal/terms/businesstools

Screenshots

Instalacija

  1. Upload the mccrossenseo directory to /wp-content/plugins/
  2. Activate the plugin through the Plugins menu in WordPress
  3. Go to McCrossenSEO™ in the admin sidebar to configure settings

To enable connected features, click „Connect to McCrossen“ under McCrossenSEO™ > Connect2McCrossen.

FAQ

Do I need a McCrossen Marketing account to use this plugin?

No. All core SEO features work without an account or external connection. A McCrossen Marketing account is only required for URL Optimization scoring, AI recommendations, the Plugin Bridge, and platform-pushed llms.txt.

Will this conflict with Yoast, RankMath, or other SEO plugins?

McCrossenSEO™ uses its own meta keys and does not conflict at the database level. However, running two SEO plugins simultaneously will produce duplicate meta tags. Deactivate your previous SEO plugin after importing. McCrossenSEO™ includes a one-click importer for Yoast, RankMath, AIOSEO, and SEOPress.

Does the free version send any data externally?

The free version makes no external connections by default. External requests are only made when you explicitly act: connecting to McCrossen Marketing, clicking Send Diagnostic Report on the Diagnostics tab, or adding a Google Analytics / Google Tag Manager / Facebook Pixel ID. Automatic error reports are sent only from connected sites. See the External Services section below for details.

What post types are supported?

McCrossenSEO™ works with all public post types including pages, posts, and WooCommerce products. The meta box appears automatically on any public custom post type.

What PHP version is required?

PHP 8.0 or higher is required.

What happens when I uninstall the plugin?

Deleting the plugin removes its connection credentials, sync state, cached data, scheduled tasks, the 404 log and the llms.txt file it generated (an llms.txt you created or edited yourself is left in place). Your settings, SEO fields on posts and terms, redirects, apply history, media log and robots.txt are kept, so a reinstall picks up where you left off.

Reviews

There are no reviews for this plugin.

Sobustatkujuce a wuwijarje

„McCrossenSEO“ jo software wótwórjonego žrědła. Slědujuce luźe su pśinosowali k toś tomu tykacoju.

Sobustatkujuce

Translate “McCrossenSEO” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

3.2.2

Fixed

  • On MariaDB 12.3 and later, the Media log table was not created on new installs and the Media log list stayed empty. Sites missing the table get it when they update.
  • A site whose connection key has been revoked, or that was connected without a shared secret, no longer counts every sync attempt as a connection failure or sends hourly error reports about it. The Connect tab shows the state instead.
  • After the platform rejects a connection, the Pending Optimizations page no longer shows „Last synced: just now“.
  • The „another SEO plugin is active“ notice no longer appears on every admin screen for every user. The Overview tab still shows which plugin is active alongside McCrossenSEO.
  • The audit prices shown before an audit is queued now match what the platform charges: 300 credits for a Standard audit, 500 for On-Demand.

3.2.1

Security

  • The importer now cleans values from other SEO plugins before storing them, never unserializes their stored data, and page titles are escaped when printed.

Fixed

  • RankMath „noindex“ and „nofollow“ settings are now imported and shown in the import preview. Previously, pages set to noindex in RankMath became indexable after migrating.
  • Titles and descriptions that still contain RankMath, All in One SEO or SEOPress variables are marked „needs review“ and not imported, instead of being shown to visitors as written. Ordinary hashtags are imported as text.
  • A backslash in an imported title or description is kept.
  • Running an import again with „overwrite“ counts values that are already stored as skipped, not as errors.
  • Heading rewrites: a new heading that starts with a number or contains a dollar sign or a backslash is written correctly, including on rollback. A rewritten heading containing an ampersand together with a quotation mark or apostrophe can now be rolled back.
  • On sites with a static front page and a separate Posts page, the Posts page now uses its own address as its canonical link, og:url and structured-data URL, including on its later pages.
  • Pending Optimizations: Apply and Apply All report success, and remove a recommendation from the list, only when it was actually applied. When a recommendation can’t be applied, Apply shows the reason and the recommendation stays in the list, including after the next sync. A malformed recommendation no longer stops Apply All.
  • Open Graph and Twitter/X titles and descriptions containing variables such as {title} (for example after a Yoast import) now show the variables filled in.

3.2.0

New

  • Merchant return policy markup for WooCommerce stores. Off by default; set it up in the new Merchant policies section of the Settings tab.
  • Shipping policy markup, entered by hand or built from your WooCommerce shipping zones. Off by default. Only rates that can be stated exactly are included.
  • A preview on the Settings tab lists each shipping destination, whether it is included in the markup, and why if not.
  • Products and product categories can be marked „returns not permitted“, or set back to the standard return policy.
  • A setting to turn llms.txt generation off.

Structured data

  • Product prices match the price shoppers see, following your store’s tax display setting.
  • Products on sale show the regular price as the original price, plus the sale dates when the sale is scheduled.
  • The automatic „price valid until“ date one year ahead is no longer added to products that are not on a scheduled sale.
  • Names, headlines and descriptions show real characters instead of HTML codes such as &amp;.
  • Template variables such as {title} in an SEO title or description are now filled in for social tags and structured data too, not only the page title. A title that itself contains a variable name is no longer substituted twice.

Titles and descriptions

  • Descriptions built from an excerpt no longer end mid-word or with a broken character code.
  • Text such as {title} written inside an excerpt is kept as written.
  • Invalid characters added by another plugin no longer leave titles, meta descriptions or social tags empty.

Sitemaps

  • New public post types are included automatically unless you have customized the „Included Post Types“ list. Once customized, the sitemap lists exactly the ticked types, so unticking a type now removes it; ticking the default selection again returns to automatic. Your sitemap lists the same types after upgrading.
  • Sitemaps for post types with digits or hyphens in their name now load.
  • Only sitemaps listed in the sitemap index are served.
  • Post types named „index“ or „home“ are not listed, and the Sitemap tab explains why.
  • URLs appear in the same order on every request.
  • Sitemaps keep working after the plugin is deactivated and activated again.

Settings

  • Saving one settings tab no longer clears settings on another tab.
  • The Sitemap and WooCommerce tabs now confirm when settings are saved.
  • Settings you deliberately leave blank are no longer refilled with defaults on activation or upgrade.
  • One-time repair: if an earlier version’s Sitemap tab save emptied the title separator, title pattern, social card type, or organization name, URL or type, they get their defaults once when you upgrade. That save may also have emptied the logo, local business details and the 404 log switch, which have no default to restore; please check them.

Product images

  • WebP and AVIF conversion now uses an image library that can actually write the chosen format, so AVIF works on more servers. Formats your server cannot write are shown as unavailable.
  • A failed conversion leaves the original image untouched, removes any partial files, and is recorded as failed in the Media log.
  • If your saved image format becomes unavailable, saving the WooCommerce tab keeps your choice and explains what is used meanwhile.
  • Product titles containing {sitename} are no longer substituted twice in image file names.

llms.txt

  • An llms.txt file you created or edited is never overwritten, and deleting the plugin removes only the file it created.
  • On multisite, only the main site writes llms.txt.

Permissions

  • Bulk Edit only loads content the current user is allowed to edit.
  • Content analysis and audit requests check that the user can edit the post; audit requests also require permission to publish.

Other

  • Stored shipping data is refreshed daily in the background.
  • Fixed a „translation loading was triggered too early“ notice on activation with WooCommerce and debug mode on.
  • Network deactivation removes the plugin’s scheduled tasks and stored shipping data on every site.
  • Connecting your site now starts the 15-minute sync immediately.

3.1.2

  • New: mccm_seo_analytics_consent filter for cookie-consent integrations. When an integration answers false, the Google Analytics 4 script is not requested; a small listener loads it once the visitor grants analytics consent, signalled by a mccm-consent document event whose detail.analytics is true. With no consent integration present, GA4 loads exactly as before. Google Tag Manager and Meta Pixel output are unchanged.
  • Change: no robots meta tag is emitted while „Discourage search engines from indexing this site“ is enabled, so the site-wide noindex set by WordPress is never contradicted.
  • Change: automatic error reports are sent only from sites connected to the McCrossen platform. Unconnected installs make no requests unless an administrator clicks Send Diagnostic Report.
  • New: deleting the plugin now removes its credentials, sync state, caches, scheduled tasks and the 404 log; settings, SEO fields, redirects, apply history, media log and robots.txt are kept.

3.1.1

  • Fixed: FAQ Schema builder was non-functional — the Add Question control did nothing and FAQ pairs could not be entered. The builder’s script now initialises on post and product edit screens.
  • Change: the review request now links to the plain reviews page with no pre-filled rating.
  • Compatibility: tested up to WordPress 7.1.

3.1.0

  • New: WooCommerce product image optimization — an „Optimize with McCrossenSEO“ button on the product edit screen renames the featured and gallery images to an SEO slug built from the product title (template-based, default {sitename}-{title}) and converts them to WebP (default, quality 82), AVIF (where the server supports it), or keeps the original format. The rename covers the original file and every generated thumbnail size, rewrites the attachment metadata, and never changes the attachment ID or URL history. The ideal moment to run it is before first publish, when a freshly uploaded image has no external references.
  • New: WooCommerce tab in the McCrossenSEO admin housing the image-optimization settings plus the existing out-of-stock sitemap/noindex toggles (moved from the Settings tab).
  • New: Media log — a third panel on the Redirects page recording every image rename (original name, new name, conversion, product, source, date) with per-row Rollback. Rollback restores the original file names and metadata and reverses any auto-created redirects.
  • New: published-product safety — renaming images on a published product warns first and requires confirmation, then automatically registers 301 redirects from every old file name (original + each size) to its new name. Images used by other posts or products are never renamed silently: choose duplicate-then-rename or skip.
  • New: CSV import integration — images downloaded by the WooCommerce product CSV importer are optimized in the background (one job per product, via Action Scheduler). Only newly downloaded images are touched; re-imports never rename images that already existed, and WooCommerce’s image de-duplication meta is preserved so re-imports don’t re-download files.
  • New: optional „delete original after conversion“ toggle (default OFF). When enabled, the source JPG/PNG files are removed after a successful conversion and the Media log marks the entry redirect-only.
  • Change: admin icon glyphs are now rendered from SVG assets bundled with the plugin (Twemoji, CC-BY 4.0) instead of raw emoji characters that WordPress rewrites to images loaded from an external CDN. Plugin admin pages no longer trigger any external asset requests.

3.0.17

  • Internal: moved the review-request admin script to an enqueued asset (coding-standards housekeeping). No functional or user-facing changes.

3.0.16

  • New: archive SEO rendering — meta titles and descriptions now render on the WooCommerce shop page (read from the shop page’s own SEO fields) and on category, tag, and taxonomy term archives. Previously they only rendered on single posts and pages, so values stored for archives were never output.
  • New: term-level SEO — SEO Title and SEO Description fields on the add/edit screens of every public taxonomy, plus WooCommerce product attribute taxonomies. Stored in term meta; the archive pages render them.
  • New: Yoast taxonomy term import — the importer now migrates Yoast’s term titles and descriptions. Template variables convert the same way as the post importer; values that can’t be converted are flagged „needs review“ and never imported raw. Term imports appear in Apply History and can be rolled back for 30 days, like post imports.
  • New: virtual robots.txt ownership — when no physical robots.txt exists, the editor saves a managed ruleset that McCrossenSEO serves through WordPress. A physical file, when present, always bypasses WordPress and wins; the editor says so instead of pretending otherwise.
  • Bug fix: „Create Physical File“ now seeds the new file from the live virtual robots.txt output — including rules added by other plugins such as WooCommerce — instead of a generic template, and no longer inserts the obsolete wp-includes disallow line.
  • Bug fix: when WordPress core or WooCommerce has already marked a page noindex (cart, my account), the plugin no longer emits its own „index, follow“ robots tag alongside it. The more restrictive directive now holds structurally instead of by browser-side precedence.
  • Bug fix: bare ampersands in meta titles are now emitted as the proper HTML entity; existing entities are left untouched.
  • Bug fix: sitemap hygiene — post types with zero published items no longer appear in the sitemap index, WPBakery internal post types are excluded, and sitemap URLs are served directly without a trailing-slash redirect hop.
  • Change: titles and descriptions are no longer texturized on output. Product titles like „5.56×45“ or a 16-inch measurement written with a straight quote emit exactly as stored instead of being converted to typographic characters. Stored values were never modified — this only changes the rendered output.

3.0.15

  • Improvement: the SEO data importer now converts Yoast template variables instead of copying them verbatim. %%title%% and %%sitename%% become their McCrossenSEO equivalents ({title}, {sitename}), %%sep%% becomes the literal separator character configured in Yoast, and %%page%% is dropped (Yoast renders it empty outside paginated views). Literal text — like a brand name written out in the template — always passes through unchanged. Previously these templates were imported as-is, which would have put raw %% text in your page titles.
  • Safety: any Yoast value containing a template variable the importer can’t convert is flagged „needs review“ and left un-imported — never silently stripped or imported raw. The preview and the final summary both show the needs-review count and affected post IDs.
  • New: every field written by the importer is now recorded in Apply History, so individual imported values can be rolled back for 30 days from the History tab. This applies to imports from all four supported plugins (Yoast, RankMath, AIOSEO, SEOPress).

3.0.14

  • Bug fix: the redirect manager now rejects redirects that would create a loop — a URL pointing to itself, or a chain that cycles back (A->B->A). Previously these could be saved and would send visitors into an endless redirect. A safeguard at serve time also breaks any self-redirect from rules created in earlier versions.
  • Bug fix: editing an existing redirect no longer silently re-enables it. Previously, changing any field (such as the note) on a disabled redirect forced it back to active. Disabled redirects now stay disabled, and you can also create a redirect in the disabled state.
  • Improvement: saving on the Settings and Tracking & Verification tabs now shows a „Settings saved“ confirmation. Your settings were always saved correctly; this adds the visible confirmation that was missing.
  • Accessibility: the Local Business address fields (street, city, state, ZIP, country) now have proper accessible labels for screen readers.

3.0.13

  • Compatibility: bumped Tested up to to WordPress 7.0 (released May 20, 2026). No code changes — all features verified to work unchanged on WP 7.0. The Plugin Bridge, 404 Monitor, redirect manager, sitemap generator, schema output, and tracking pixel injection were all sanity-checked against 7.0’s new admin UI and the WP AI Client API surface (which the plugin does not consume).
  • Internal: trimmed the 3.0.11 upgrade notice for WordPress.org compliance (the upgrade-notice line is shown on the Plugins update screen and must stay short).

3.0.12

  • New: 404 Monitor now suggests redirect targets by matching broken URLs against your published pages and posts. Up to three suggestions per broken URL with one-click redirect creation directly from the suggestions.
  • New: Optional WordPress.org review prompt appears after the plugin has been installed for three weeks. Easy to dismiss permanently, snooze for fourteen days, or open the reviews page.
  • Internal: top-3 suggestions are stored as a compact JSON list in the existing suggested_url column (no schema change). Legacy single-URL values from earlier versions continue to render as a single button and are rewritten to JSON the next time the suggester runs.
  • Internal: added MCCM_SEO_Review_Nudge class. The install-age clock starts on first activation; existing installs upgrading to 3.0.12 receive a fresh 21-day countdown rather than seeing the prompt immediately.

3.0.11

  • Bug fix: the McCrossenSEO™ meta box now renders in its canonical position below the content on the post editor for all post types. On some sites it had been appearing in the sidebar due to leftover state from an earlier preview version — that position is now restored automatically.
  • All SEO features and platform-connected features (where enabled) continue to work exactly as before; no settings or workflows changed.
  • Removed an unused internal background process that was logging PHP debug warnings on sites running with WP_DEBUG enabled. If you saw those warnings in your error log, they will stop after this update.
  • Cleanup runs automatically on update: a leftover scheduled task and cached options from the removed layer are cleared with no action required.
  • Internal: the McCrossen_SDK and McCrossen_CrossSell classes were removed (neither was wired to any user-facing code path). The 15-minute heartbeat (MCCM_SEO_Heartbeat) is unaffected and remains the sole platform sync channel for connected installs. Connection state is read directly from the stored API key. The sdk_version field was dropped from heartbeat and diagnostic payloads (it was always reporting the 'unknown' fallback). All other payload fields are unchanged.

3.0.10

  • Plugin Check: added missing Squiz.PHP.DiscouragedFunctions.Discouraged to the existing phpcs:ignore annotation on class-mccm-seo-admin.php:727 (@set_time_limit( 60 ) in ajax_404_purge_noise). The WordPress.PHP.* rules were already covered; the Squiz-flavor rule was missed when alpha.40 originally annotated this line. The sibling call at line 876 (rollback batch) already had the Squiz rule covered, which is why Plugin Check flagged only one of them. Plugin Check now returns zero ERRORs / zero WARNINGs.

3.0.9

  • Hotfix: 3.0.8 contained a parse error in includes/helpers.php introduced when adding the new mccm_seo_custom_head_allowed_html() and mccm_seo_sanitize_custom_head() helpers — the existing if ( ! function_exists( 'mccm_seo_show_in_dev' ) ) : opener was inadvertently removed, leaving a stranded endif; and a fatal syntax error, unexpected token "endif". Restored the opener. Plugin now activates cleanly on a debug-enabled WordPress install. Verified via php -l across all PHP files.

3.0.8

  • Bug fix: button labels in the Elementor preview-draft meta box („Replacing…“, „Replaced ✓“, „Discarding…“, „Discarded ✓“) were displaying their literal escape sequences (e.g. Replacing\u2026) because PHP single-quoted strings do not interpret \u escapes. Replaced with the actual UTF-8 characters.

3.0.7

  • WordPress.org review round 2 fixes:
  • Replaced broken Google Tag Manager terms URL in readme.txt (marketingplatform.google.com/about/analytics/tag-manager-terms/ www.google.com/analytics/terms/tag-manager/).
  • Removed inline <script> block from the Connect tab; the manual-setup toggle handler is now in the already-enqueued mccm-seo-admin.js.
  • Removed inline <script> block from the Replace-Original meta box on Elementor preview drafts; logic moved to a new mccm-seo-preview-draft.js enqueued via admin_enqueue_scripts only on screens that render that meta box.
  • Replaced direct ABSPATH references in class-mccm-seo-llms.php and class-mccm-seo-robots.php with get_home_path() so site root path is computed via a WordPress function.
  • Replaced direct WP_PLUGIN_DIR reference in class-mccm-seo-migrator.php with a path derived from the plugin’s own location (MCCM_SEO_DIR).
  • Replaced raw is_writable() probe in class-mccm-seo-robots.php with the WP_Filesystem API.
  • Custom <head> code option (mccm_seo_custom_head) is now escape-on-output via wp_kses with a head-content allowlist, matching the same allowlist applied at save time. Removes reliance on save-time-only sanitization.
  • Removed JSON_UNESCAPED_SLASHES flag from JSON-LD output in class-mccm-seo-schema.php. JSON_HEX_TAG is preserved as the security-relevant flag.

3.0.0-alpha.1

  • Plugin slug renamed from mccrossen-seo to mccrossenseo to match the McCrossenSEO™ trademark form. Existing installs migrate automatically on activation.
  • WordPress.org compliance pass: removed dead watchdog references, removed deprecated Google/Bing sitemap pings (deprecated 2023), fixed sanitization gaps in nonce and content readers, hardened REST endpoint permission_callbacks (action-plan, webpage-draft) so authentication runs in the permission_callback rather than the handler, added JSON_HEX_TAG to JSON-LD output, removed the dead MCCM_PLATFORM_VERSION conditional in the tracking tab.
  • Inline <script> and <style> blocks across admin views converted to enqueued assets per WP.org guidelines. Affected pages: Pending Optimizations, Redirects + 404 Monitor, Import, robots.txt editor.
  • Frontend tracking pixel injection (GA4, GTM, Facebook Pixel) now uses wp_print_script_tag() and wp_print_inline_script_tag() per WordPress 5.7+ guidelines.
  • External Services section in this readme rewritten to accurately disclose all conditionally-loaded third-party scripts.
  • Cross-sell module’s inline JS converted to use wp_print_inline_script_tag().
  • Diagnostics file-scope filter updated to recognize the renamed plugin folder.

2.1.7

  • WordPress.org submission release
  • License updated to GPL-2.0-or-later
  • Added comprehensive readme.txt with external services documentation
  • Added sanitize callbacks to all register_setting calls
  • Code compliance review for WordPress.org guidelines

2.1.6

  • SDK stale update fix

2.1.5

  • Plugin Bridge one-click apply for meta, headings, alt text, and schema
  • Bulk editor with post type filtering

2.1.4

  • LLMs.txt generator
  • Internal link suggestions
  • Redirect manager