Indexability, and the two ways it goes wrong

Applies to seo.no-noindex-leak.

Covers seo.no-noindex-leak.

There are exactly two failures here and they are mirror images. Both are quiet, and both are found weeks later by someone other than the developer.

Failure one: staging gets indexed

A staging site with the same content as production competes with it, splits the signal, and can outrank it. Worse, it is public: unfinished copy, client names, placeholder pricing.

robots.txt does not fix this. Disallow asks a crawler not to fetch the page; it does not stop that URL being indexed if something links to it, and the result is a listing with no description. To keep a page out of an index you must let it be fetched and return noindex.

Failure two: production ships with noindex

The one that actually costs money. A site launches, nobody notices for a month, and the client asks why they are not in Google. In WordPress this is one checkbox in Settings, Reading, and it is checked by default on a fresh install.

It also arrives from the other direction: a database pulled from staging to production brings blog_public = 0 with it, and the site silently goes dark after a deploy that reported success.

The fix, which is not a checklist item

Do not make this something a human has to remember at the end of a project. Drive it from the environment:

// Staging: noindex everything, no exceptions, no setting to forget.
if (wps_env() !== 'production') {
    add_action('wp_head', fn() => print '<meta name="robots" content="noindex, nofollow">' . "\n", 1);
    add_filter('wp_robots', fn($r) => ['noindex' => true, 'nofollow' => true]);
}

Then the rule is not "remember to turn indexing on" but "production is production", and a database sync cannot break it because the environment decides, not a stored option.

Guard the sync in the same spirit: if a database push overwrites blog_public, fix it at the source rather than remembering to flip it after every deploy.

Verify after every deploy, not once at launch

curl -sI https://example.com | grep -i x-robots-tag        # expect nothing
curl -s  https://example.com | grep -i 'name="robots"'      # expect no noindex
curl -s  https://example.com/robots.txt                     # expect no blanket Disallow: /

Run it against production after launch and after any deploy that touched the database. It takes three seconds and it is the single highest-value check in this document, because everything else in the SEO section is worthless if this one is wrong.

Staging should also be private

noindex keeps staging out of search results. It does not keep people out. Put HTTP basic auth in front of the whole staging environment as well - the two protections answer different questions.

One caveat if performance is being measured on staging: a gate blocks the testing tools too. Either allow the tool through, or accept that the measured environment is not the gated one.