AutoSEO — AI Content Publisher

Description

AutoSEO connects your WordPress site to the AutoSEO content platform at autoseo.it.com. Articles you generate there are delivered to this site over an authenticated REST endpoint and created as posts, pages or a custom post type — as drafts, published immediately, or scheduled for a future date.

The plugin’s job is to make a delivered article land the way a careful editor would have published it by hand.

Fills your SEO plugin, not a second set of tags

AutoSEO detects which SEO plugin your site actually runs and writes to that one only:

  • Yoast SEO — SEO title, meta description, focus keyphrase, canonical, Open Graph and Twitter fields, primary category
  • Rank Math — title, description, focus keyword, canonical, Facebook and Twitter fields, robots directives, primary category
  • SEOPress — title, description, target keyword, canonical, social fields
  • The SEO Framework — title, description, canonical, Open Graph and Twitter fields

Only one plugin is ever written to. Filling two sets of fields is worse than filling none, because whichever plugin renders the <head> wins unpredictably. You can override the detection and pick a specific plugin, or turn the behaviour off entirely.

If no SEO plugin is installed, AutoSEO writes its own meta description, Open Graph and Twitter tags and BlogPosting schema — and stops the moment you install one, so your tags are never duplicated.

All in One SEO is deliberately not written to. AIOSEO stores post SEO in its own database table rather than in post meta, and this plugin does not write into another plugin’s table — a schema change on their side could corrupt it. AIOSEO is detected and the settings screen tells you plainly that titles and descriptions were not synced. Everything else still applies.

On-publish hygiene

  • Featured image downloaded from the article and set, with ALT text
  • Excerpt filled from the meta description or the article body when one is missing
  • Author assigned, so posts do not render an empty byline
  • Categories and tags mapped, reusing existing terms rather than creating near-duplicates
  • Re-delivering the same slug updates the existing post instead of creating a duplicate

Managed redirects

Redirect rules you configure in the AutoSEO dashboard are pulled hourly in the background and enforced on the front end. Rules are validated before they are stored: protocol-relative and plain-http:// destinations are rejected, so a bad rule cannot become an open redirect.

WooCommerce

When WooCommerce is active, products are treated as first-class content. AutoSEO can read and report product name, SKU, price, stock status, short and long description length, categories and tags, gallery images and how many of them have no ALT text, and it can fill product SEO fields through whichever SEO plugin is active — exactly as it does for posts.

AutoSEO never emits Product structured data. WooCommerce core already emits it, and Yoast WooCommerce SEO, Rank Math and SEOPress Pro each replace Woo’s with their own. A second Product entity on one URL is not a cosmetic duplicate; it is conflicting markup Google is willing to drop the rich result for. AutoSEO detects who owns it and stays out of the way.

Products that are out of stock and still indexable are reported, never changed. Whether the right answer is noindex, a redirect to the replacement, or leaving the page up because stock returns next week is a commercial decision, so AutoSEO surfaces it and stops.

No product fact is ever invented. AutoSEO does not generate a price, a SKU, an availability, a specification or a review.

Optional: fix the content you already have

Everything in this section is off until you turn it on, in AutoSEO Settings Autopilot, with a separate checkbox per action:

  • SEO title, meta description, focus keyword and canonical
  • Post excerpts
  • Image ALT text
  • Category and author assignment
  • Repointing internal links that lead to a 404
  • Serving an /llms.txt written by AutoSEO, so AI assistants can read a map of your site
  • FAQPage schema built only from question-and-answer pairs already present in the post
  • A visible byline and <time datetime> using the post’s real author and real dates

Three rules apply to all of them:

  1. Empty fields only. Unless you separately tick “allow AutoSEO to replace values that are already filled in”, AutoSEO fills blanks and never touches a description, title or ALT text you wrote.
  2. Everything is reversible. The previous value is stored before every write, and AutoSEO Log Changes lists every modification with a Revert button.
  3. Rate limited. A per-request cap and a daily cap, both clamped to hard ceilings no setting can raise, so nothing can rewrite a whole site in one go.

External service disclosure

This plugin is a client for AutoSEO, a paid third-party service. It will not do anything useful without an AutoSEO account, and it communicates with autoseo.it.com and nowhere else.

What the plugin sends out, and when:

  1. When you click “Test connection”, and shortly after you save a new API key — a request to https://autoseo.it.com/api/wordpress/verify carrying your AutoSEO API key, your site URL, the plugin version and whether WooCommerce is active. This both checks the key and registers this site with your AutoSEO account as a publishing destination. No post content is sent.
  2. Hourly on WP-Cron, and shortly after you save a new API key — a request to https://autoseo.it.com/api/redirects carrying your API key, to fetch your redirect rules. Nothing about your posts is uploaded.
  3. Only if you enable Autopilot — an hourly request to https://autoseo.it.com/api/wordpress/tasks carrying your API key, your site URL and the list of actions you have permitted, to fetch pending fixes; followed by a request reporting what was applied or refused. With Autopilot off, neither request is ever made.
  4. Only if you leave IndexNow enabled — a request to https://autoseo.it.com/api/wordpress/indexnow listing URLs on your site that have just changed, so AutoSEO can submit them to IndexNow (Bing, Yandex, Seznam, Naver). URLs only — no content. The IndexNow key lives on the AutoSEO server and is never shipped inside this plugin.

As with any request WordPress makes, the default WordPress user-agent header includes your WordPress version and your site URL.

What AutoSEO can read back from your site: AutoSEO calls in to this site holding your API key. With that key it can create and update posts; read a status summary (site URL, configured post type and status, how many AutoSEO articles exist, which SEO plugin was detected, whether WooCommerce is active, and which actions you have permitted); read a queue of status changes and deletions for articles AutoSEO itself delivered; read a site inventory (per post: title, current SEO fields, excerpt, word count, images and missing ALT text, internal and external link counts, dates, author, categories and tags — and for products, SKU, price, stock status and description lengths); scan for internal links that 404; and apply the fixes you have permitted. Requests without a valid key are rejected with HTTP 401.

Cache safety. All AutoSEO REST responses are sent with Cache-Control: no-store, Vary: X-AutoSEO-Key, Authorization and the opt-out headers LiteSpeed, WP Rocket, W3TC and Varnish honour, so a page cache cannot store an authenticated response and replay it to the public.

The plugin loads no remote code, no remote scripts and no remote stylesheets. The AutoSEO API returns data only.

  • Privacy Policy: https://autoseo.it.com/privacy-policy
  • Terms of Service: https://autoseo.it.com/terms-of-service

Installation

  1. Upload the plugin through Plugins Add New Upload Plugin, or install it from the WordPress plugin directory.
  2. Activate it. AutoSEO appears in your admin sidebar.
  3. In the AutoSEO dashboard, open WordPress Plugin and generate a connection key.
  4. Paste the key into AutoSEO Settings and click Save settings.
  5. Click Test connection. The result line tells you exactly what passed or failed.

Saving only stores the key locally; it never contacts AutoSEO. The connection test is the step that proves the key works.

FAQ

Do I need a paid AutoSEO account?

Yes. The plugin is a client for the AutoSEO service at autoseo.it.com and does nothing on its own. See the external service disclosure in the Description.

Does it work with Yoast SEO?

Yes. AutoSEO detects Yoast and fills its SEO title, meta description, focus keyphrase, canonical and social fields.

What about Rank Math, SEOPress or The SEO Framework?

All three are detected and filled the same way. AutoSEO writes to exactly one SEO plugin — whichever is active — so you never end up with two competing sets of tags. You can override the choice under AutoSEO Settings SEO Plugin.

What about All in One SEO?

AIOSEO is detected, but AutoSEO does not sync titles and descriptions into it. AIOSEO stores post SEO in its own database table rather than in post meta, and writing directly into another plugin’s table risks corrupting it on their next schema change. Everything else — excerpt, image ALT text, categories, tags, author, scheduling — still applies, and the settings screen says so when AIOSEO is the active plugin.

What happens if I have no SEO plugin at all?

AutoSEO writes its own meta description, Open Graph and Twitter tags and BlogPosting schema. It stops doing this as soon as an SEO plugin is active.

Will it overwrite meta I wrote by hand?

No. Empty values are skipped, so AutoSEO fills blanks rather than replacing your work.

Will re-sending an article create a duplicate post?

No. A delivery whose slug already exists updates that post in place.

Where do articles go?

Whatever post type and status you choose under AutoSEO Settings. The default is a draft, so nothing is published without your say-so until you change it.

Does saving settings contact AutoSEO?

No. Saving is entirely local and performs no network requests at all. Only the connection test and the hourly redirect sync talk to autoseo.it.com.

Something failed but I see no error. Where do I look?

AutoSEO Log Activity. Every delivery, connection test, autopilot run and applied fix is recorded there — including the ones that were rejected or failed, with the reason. Filter by type and date. The Support diagnostics tab gives you one copy-paste block containing your plugin, WordPress and PHP versions, connection state, permitted actions and the last 40 log lines; your API key is never included in it.

The plugin also writes failures to your PHP error log, prefixed with [AutoSEO], because by design it never takes your site down when it fails.

I pressed publish in AutoSEO and nothing arrived.

Check AutoSEO Log Activity and filter to “Article delivery”. A delivery that was rejected (missing title, empty content) or that WordPress refused to save is logged there with the reason.

Will AutoSEO change posts I wrote myself?

Not unless you ask it to. Every action that modifies existing content is off by default. When you do enable one, AutoSEO only fills fields that are empty — replacing a value you typed additionally requires ticking “allow AutoSEO to replace values that are already filled in”. Every change is listed in AutoSEO Log Changes with a Revert button.

Does the plugin create database tables?

No. It stores its configuration, its activity log and its change log in options, and marks delivered posts with post meta. The activity log is capped at 300 entries and 30 days and is never autoloaded.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“AutoSEO — AI Content Publisher” is open source software. The following people have contributed to this plugin.

Contributors

Changelog

3.2.2

Plugin Check

  • Resolved the two WordPress.DB.SlowDBQuery warnings Plugin Check raised on
    the pull-publishing duplicate guard. The lookup itself is unchanged — it is
    a single-row existence check on the plugin-owned _autoseo_article_id meta
    key, run once per pulled article inside the hourly cron and never on page
    views — and is now documented and annotated as such at the query site.

3.2.1

Namespace (WordPress.org plugin review)

  • Every function, constant, option, nonce, cron hook and AJAX action is now
    prefixed autoseopub_ / AUTOSEOPUB_ instead of the bare autoseo_.
    Another plugin in the directory uses the autoseo_ prefix — including the
    identical autoseo_api_key option name — so both plugins on one site would
    silently overwrite each other’s settings. Existing installations are
    migrated automatically: every legacy option value is copied to its new name
    once on upgrade (settings, permissions, activity log, change/undo history)
    and legacy cron events are cleared. Post meta keys (_autoseo_*), the REST
    namespace (autoseo/v1) and the admin page slugs are unchanged, so the
    AutoSEO service, existing bookmarks and delivered-post tracking keep working
    without any action.
  • Yoast term SEO fields are now written through Yoast’s own
    WPSEO_Taxonomy_Meta::set_values() API when it is available; the direct
    read-modify-write of wpseo_taxonomy_meta (Yoast’s storage for term meta —
    not an AutoSEO option) remains only as a fallback and still preserves every
    other value in that option untouched.

Fixed

  • The 3.1.11 “ALT text for unattached media” permission could never actually
    be switched on: the capability was missing from the option map every other
    surface derives from, so its checkbox saved nowhere and the permission
    always read as off (it also raised an “Undefined array key” warning on the
    settings screen under WP_DEBUG). The toggle now works.
  • The Activity log screen no longer raises “Undefined array key” warnings on
    a WP_DEBUG site when a log row in the database is missing fields — rows are
    normalised on read and render as blanks instead.

3.2.1

Added

  • Pull publishing. The site now also collects its own queued articles from
    AutoSEO once an hour, instead of only waiting to be pushed to. Publishing used
    to fail outright whenever something sat in front of WordPress and refused us —
    a firewall, a WAF, a Cloudflare challenge, a login wall on a staging host, or
    a server not reachable from outside. An outbound request has none of those
    failure modes. Push remains the default because it is immediate; this is the
    safety net that catches whatever push could not deliver, and for a firewalled
    site it is the only path that works. Articles collected this way appear in the
    Activity log under “Collected from AutoSEO”, and an article can never be
    published twice.

Hardening (WordPress.org plugin review)

  • Every text field arriving from the AutoSEO API is now passed through
    sanitize_text_field() before it is written to post meta. The review flagged
    focus_keyword, and the fix was applied at the shared accessor those values
    all pass through, so title, description, og_title, og_description,
    twitter_title and twitter_description are covered by the same change
    rather than left for a later report. URL fields keep esc_url_raw() and the
    primary-category id keeps its integer sanitiser — each field now uses the
    sanitiser appropriate to its own type.

3.1.12

Hardening (WordPress.org plugin review)

  • The FAQPage and BlogPosting JSON-LD blocks are now encoded with
    JSON_HEX_TAG and JSON_HEX_AMP and without JSON_UNESCAPED_SLASHES, so
    no post title, description, question or answer can ever contain a character
    sequence the HTML parser would read as markup inside the script element.
  • The optional heading-order fix no longer leaves its output buffer to be
    flushed implicitly at the end of the request. The buffer is opened with a
    recorded stack depth and explicitly closed by the plugin’s own shutdown
    handler (priority 0, ahead of WordPress core’s buffer flush), which also
    folds in — in the correct order — any inner buffer another component opened
    on top and abandoned.
  • The WordPress.org directory icon is no longer bundled inside the plugin zip;
    directory assets ship separately via SVN.
  • Text domain changed to autoseo-publisher to match the plugin’s directory
    slug. The plugin folder name is unchanged, so existing installations are
    unaffected.

3.1.11

Images

  • New capability: ALT text for unattached media. Bulk importers (car
    inventory, product feeds) create thousands of media items that belong to no
    post — on one live site 262 of the first 300 images had no ALT text and no
    parent. The existing Image ALT action could never reach them: it verifies the
    image is actually used by the post it is applied from, which an orphaned
    attachment can never satisfy. This is the same write with the one rule that
    cannot apply replaced by a narrower one — it refuses any attachment that DOES
    have a parent, so it never becomes a way around the stricter check. It is a
    separate toggle, off unless you enable it, and it never replaces ALT text you
    already wrote.

3.1.10

Plugin review

  • Cleared the last four Plugin Check warnings. Three were already meant to be
    suppressed, but the phpcs:ignore comments sat above the if ( ! defined( ... ) )
    guard rather than the define() on the next line, and the annotation only ever
    applies to the line directly after it — so all three were still reported. The
    constants themselves are unchanged: DONOTCACHEPAGE, DONOTCACHEOBJECT and
    DONOTCACHEDB are fixed names read by W3 Total Cache, WP Super Cache and
    LiteSpeed, and prefixing them would stop page caches honouring the no-cache
    request on an authenticated REST route.
  • The pagination parameter on the Activity Log now goes through absint() instead
    of a cast inside a helper. The value was never unsafe — an integer cast cannot
    carry an injection — but the sniff recognises sanitizing functions rather than
    casts, so it read as unsanitized input in review.

3.1.0

Security

  • Fixed a real cache-poisoning leak. On a site behind LiteSpeed Cache, GET /wp-json/autoseo/v1/status with no API key returned HTTP 200 and the full response body, with x-litespeed-cache: hit; the same URL with a cache-buster correctly returned 401. The key check was never wrong — the page cache had stored a response generated for an authenticated request and was replaying it publicly, exposing the site’s WordPress and PHP versions and its AutoSEO configuration. Every AutoSEO REST response now carries Cache-Control: no-store, Pragma: no-cache, Vary: X-AutoSEO-Key, Authorization, X-LiteSpeed-Cache-Control: no-cache and X-Accel-Expires: 0, and sets DONOTCACHEPAGE plus the LiteSpeed and WP Rocket opt-out hooks. Any page cache does this by default; the authenticating header is not part of its cache key.
  • Removed wp_version and php_version from the /status response. AutoSEO never used either one, and the least data is the best mitigation.

Connection

  • The plugin now registers itself. Previously “Test connection” proved your key was valid and nothing more — so it was possible to see “Connected” here while AutoSEO had no record of your site at all, and every article in the app still said “Connect a CMS to publish”. The connection test now also registers this site as a publishing destination and reports whether that succeeded. It works from behind firewalls, staging authentication, Cloudflare challenges and WooCommerce coming-soon mode, none of which allow AutoSEO to call in to your site.

WooCommerce

  • WooCommerce is detected and products are treated as first-class content: reported in the site inventory with SKU, price, stock status, description lengths, categories, tags and gallery ALT coverage, and writable through the active SEO plugin.
  • AutoSEO never emits Product structured data, and reports which plugin owns it on your site, so you can never end up with two conflicting Product entities on one URL.
  • Products that are out of stock and still indexable are reported, never changed.

New: fix existing content (all opt-in, all reversible)

  • Site inventory endpoint — reports the real SEO state from the database, not from scraped HTML.
  • Apply-fixes endpoint — SEO title, meta description, focus keyword, canonical, excerpt, image ALT, category, author, term/archive meta. Supports dry_run and reports exactly what would change.
  • Autopilot — an hourly WP-Cron job that applies approved fixes with no dashboard needed. Off by default.
  • Broken internal link detection, with in-place repointing when a redirect target is known.
  • IndexNow — the plugin tells AutoSEO which URLs changed; the key stays on the server.
  • GEO / AI-Overview support: reports whether GPTBot, ClaudeBot, PerplexityBot, Google-Extended and bingbot (which Copilot rides on) are allowed by robots.txt; can serve an AutoSEO-authored /llms.txt; can mark up FAQPage schema only from Q&A already in the post; can add a visible byline and <time datetime> from the post’s real author and dates.
  • Safety throughout: one checkbox per action type, all defaulting to off; empty fields only unless overwriting is separately enabled; the previous value stored before every write with a per-change Revert button; per-request and per-day change caps clamped to hard ceilings; and a dry-run mode.

Logging

  • AutoSEO Log is now a real diagnostic surface: an Activity tab recording every delivery, connection test, autopilot run and applied fix — including rejections and failures, with the reason — filterable by type and date; a Changes tab with before/after values and per-change Revert; the delivered-articles list; and a Support diagnostics tab with a one-click copy block that never includes your API key. Previously a rejected delivery left no trace anywhere you could see it.
  • The activity log is capped at 300 entries and 30 days, stored non-autoloaded, and can be cleared from the screen.

Compatibility

  • Tested up to WordPress 7.0.
  • Text domain corrected to autoseo-publisher to match the plugin name. The plugin folder name is unchanged, so existing installations are unaffected.

3.0.1

This release changes no features. It exists so that a broken AutoSEO can never take a site offline.

  • Hardened: the plugin’s bootstrap now checks that every one of its own module files is present and readable before requiring it. A require on a missing file is an uncatchable PHP fatal that fires on every request — front end included — so a file removed by a host’s malware scanner, or never written by an interrupted upload, could previously take a whole site to HTTP 500 with no way to reach wp-admin and deactivate. AutoSEO now switches itself off, logs the missing filename, and shows an admin notice. The site keeps serving.
  • Hardened: the module loading and all hook registration run inside try { } catch ( Throwable ). A failure disables AutoSEO’s features instead of ending the request.
  • Hardened: a PHP version floor is checked before any of the plugin’s code loads. WordPress enforces “Requires PHP” at activation but does not re-check afterwards, so a host that moves a site to an older PHP could previously fatal every page. AutoSEO now switches itself off with a notice instead.
  • Hardened: activation now aborts with a readable message and leaves the site untouched if anything throws, rather than reporting success and leaving a half-migrated install.
  • Hardened: admin-only hooks are no longer registered on front-end requests. On a page view AutoSEO now touches template_redirect, wp_head and the canonical filter, and nothing else.
  • Hardened: the redirect handler skips AJAX, cron, REST, WP-CLI and XML-RPC requests, only acts on GET/HEAD so a POST body can never be dropped, and refuses to act before init has fired.
  • Fixed: a redirect rule pointing a path at itself is now rejected when stored and skipped when applied. An infinite redirect on / takes a site off the internet as effectively as a fatal does.
  • Fixed: a missing admin page template renders a notice on that one screen instead of fataling wp-admin.

3.0.0

  • Fixed: “There has been a critical error on this website” when saving settings. 2.5.0 and 2.6.0 used the WordPress Settings API, so the save was executed by wp-admin/options.php inside core’s own loop — where any error in a sanitize callback becomes a white screen the plugin cannot intercept or explain. 3.0.0 removes register_setting() entirely; the form now posts to a handler this plugin owns end to end (capability check, nonce check, its own sanitisers, then a redirect with a notice). A failure is now a red admin notice, never a fatal.
  • Fixed: PHP 8 TypeError in the REST permission check — hash_equals() could receive NULL when the API key header was absent.
  • Added: AutoSEO is now a top-level item in the admin sidebar with Settings, Publish Log and Help screens, instead of being buried under Settings. Old options-general.php bookmarks are forwarded to the new location.
  • Added: SEO plugin auto-detection. Rank Math, SEOPress and The SEO Framework are supported alongside Yoast, and only the active one is written to. Rank Math’s robots field is correctly stored as an array.
  • Added: All in One SEO is detected and reported but deliberately not written to, because it stores post SEO in its own database table.
  • Added: a “Settings” link on the plugin’s row on the Plugins screen.
  • Added: post status and deletion tracking, so AutoSEO’s view of what is published stays accurate.
  • Added: on-publish hygiene — automatic excerpt, featured-image ALT text, author assignment, canonical support, and BlogPosting schema when no SEO plugin owns the head.
  • Changed: the single-file plugin is now a bootstrap plus six focused modules.
  • Changed: re-publishing the same slug updates the existing post instead of creating a duplicate.
  • Hardened: redirect rules from the dashboard are validated before being stored; protocol-relative and plain-http destinations are rejected so a bad rule cannot become an open redirect.
  • Hardened: every hooked callback is wrapped so no exception can reach WordPress. Failures go to the PHP error log instead of fataling the page.
  • Unchanged: option names, so existing installs keep their configuration. The old autoseo_yoast_enabled boolean is migrated to the new SEO plugin setting.

2.6.0

  • Fixed: saving the API key triggered a blocking 15-second outbound request inside the save request itself; any failure surfaced as a fatal admin error. The redirect sync is now deferred to WP-Cron and the save path does no network I/O.
  • Reduced outbound HTTP timeout from 15s to 8s.
  • Fixed: the “— None —” category no longer saves as category #1.
  • Fixed: front-end redirect matching no longer passes strtok()‘s FALSE into untrailingslashit().
  • Added: the REST routes also accept Authorization: Bearer <key>.
  • Added: the connection test reports a specific reason instead of a bare failure.

2.4.1

  • Security: constant-time API key comparison, nonce verification on AJAX handlers, capability checks on admin actions, input sanitization and output escaping throughout.
  • Added: SSL verification enabled by default on outbound requests.
  • Added: post status validation against an allowlist.