No description
  • PHP 81.2%
  • JavaScript 10.8%
  • CSS 8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-18 17:39:42 +00:00
assets v3.0.3 2026-07-18 17:39:42 +00:00
languages v3.0.3 2026-07-18 17:39:42 +00:00
changelog.txt v3.0.3 2026-07-18 17:39:42 +00:00
LICENSE v3.0.3 2026-07-18 17:39:42 +00:00
noindex-seo.php v3.0.3 2026-07-18 17:39:42 +00:00
readme.txt v3.0.3 2026-07-18 17:39:42 +00:00
uninstall.php v3.0.3 2026-07-18 17:39:42 +00:00

=== noindex SEO ===
Contributors: javiercasares
Tags: seo, noindex, nofollow, noarchive, robots
Requires at least: 5.7
Tested up to: 7.1
Stable tag: 3.0.3
Requires PHP: 7.2
Version: 3.0.3
License: GPL-3.0-or-later
License URI: https://www.gnu.org/licenses/gpl-3.0.txt

Control search engine indexing with robots directives using HTML meta tags or HTTP headers.

== Description ==

Fine-grained control over how search engines index and display your WordPress content. Apply 5 independent robots directives to 22 different page contexts with flexible implementation methods.

**5 Robots Directives:**

* **noindex**: Prevent search engines from indexing the page
* **nofollow**: Prevent search engines from following links on the page
* **noarchive**: Prevent search engines from showing cached versions
* **nosnippet**: Prevent search engines from showing text snippets in results
* **noimageindex**: Prevent search engines from indexing images on the page

**Implementation Methods:**

* HTML Meta Tags: Traditional method, easy to verify in page source (default)
* HTTP Headers: More robust, works with all content types including PDFs and images
* Both: Maximum compatibility for all scenarios

**Control Levels:**

* Global Settings: Apply directives to 22 different page contexts (posts, pages, archives, etc.)
* Granular Control (Optional): Override global settings for individual posts, pages, and custom post types via meta boxes in the editor

**Perfect for:**

* Blocking indexing of attachment pages while allowing link following
* Preventing duplicate content issues with flexible directive combinations
* Controlling archive page indexing with granular control
* Managing pagination SEO with independent settings
* Protecting private content from search engine caching
* Preventing snippet display while still indexing content

**Main pages**

* Front Page: Block the indexing of the site's front page.
* Home: Block the indexing of the site's home page.

**Pages and Posts**

* Page: Block the indexing of the site's pages.
* Privacy Policy: Block the indexing of the site's privacy policy page.
* Single: Block the indexing of a post on the site.
* Singular: Block the indexing of a post or a page of the site.

**Taxonomies**

* Category: Block the indexing of the site categories. The lists where the posts appear.
* Tag: Block the indexing of the site's tags. The lists where the posts appear.

**Dates**

* Date: Block the indexing when any date-based archive page (i.e. a monthly, yearly, daily or time-based archive) of the site. The lists where the posts appear.
* Day: Block the indexing when a daily archive of the site. The lists where the posts appear.
* Month: Block the indexing when a monthly archive of the site. The lists where the posts appear.
* Time: Block the indexing when an hourly, "minutely", or "secondly" archive of the site. The lists where the posts appear.
* Year: Block the indexing when a yearly archive of the site. The lists where the posts appear.

**Archives**

* Archive: Block the indexing of any type of Archive page. Category, Tag, Author and Date based pages are all types of Archives. The lists where the posts appear.
* Author: Block the indexing of the author's page, where the author's publications appear.
* Post Type Archive: Block the indexing of any post type page.

**Pagination**

* Pagination: Block the indexing of the pagination, i.e. all pages other than the main page of an archive.

**Search**

* Search: Block the indexing of the internal search result pages.

**Attachments**

* Attachment: Block the indexing of an attachment document to a post or page. An attachment is an image or other file uploaded through the post editor's upload utility. Attachments can be displayed on their own "page" or template. This will not cause the indexing of the image or file to be blocked.

**Previews**

* Customize Preview: Block the indexing when a content is being displayed in customize mode.
* Preview: Block the indexing when a single post is being displayed in draft mode.

**Error Page**

* Error 404: This will cause an error page to be blocked from being indexed. As it is an error page, it should not be indexed per se, but just in case.

Important note: if you have any doubt about any of the following items it is best not to activate the option as you could lose results in the search engines.

== Installation ==

= Automatic download =

Visit the plugin section in your WordPress, search for [noindex-seo]; download and install the plugin.

= Manual download =

Extract the contents of the ZIP and upload the contents to the `/wp-content/plugins/noindex-seo/` directory. Once uploaded, it will appear in your plugin list.

== Compatibility ==

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5

== Changelog ==

= 3.0.3 [2026-07-18] =

**Added**

* **"Robots" column on taxonomy list tables.** When per-term granular control is on, the Categories / Tags / custom taxonomy list pages now show a "Robots" column with the same directive badges (🔍 noindex, 🔗 nofollow, 💾 noarchive, 📄 nosnippet, 🖼️ noimageindex) used on the post list. Makes it possible to scan at a glance which terms have an override and which directives are active — parity with the existing post-list UX.

**Compatibility**

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5

**Tests**

* Added 3 tests covering the term column renderer (no override, with override, passthrough for other columns).

= 3.0.2 [2026-07-18] =

**Fixed**

* Duplicate "Search Engine Visibility" panel in the block editor. The plugin previously registered both a classic PHP meta box (`add_meta_box`) AND a native Gutenberg sidebar panel (`PluginDocumentSettingPanel` via `assets/js/editor-sidebar.js`) with the same title — both showed up in the block editor sidebar as two panels with the same name. The classic meta box is now suppressed on block-editor screens (detected via `get_current_screen()->is_block_editor`, which respects the Classic Editor plugin's per-request override). Classic editor users still get the meta box.

**Added**

* **Per-term granular control for taxonomies.** Mirrors the existing per-post granular pattern: when "Enable per-term granular control" is on, every public taxonomy (`category`, `post_tag`, and any custom public taxonomy like WooCommerce's `product_cat` / `product_tag`) gets a "Search Engine Visibility" panel on the Edit Tag screen with an override checkbox and the five directive checkboxes. Term-level directives take precedence over the global `category` / `tag` / `post_type_archive` settings when the term has the override enabled. Backed by `register_term_meta()` with `show_in_rest=true` so headless consumers can read them.

**Compatibility**

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5

**Tests**

* Added `tests/test-term-meta.php` covering registration, save handler, front-end override precedence, and uninstall cleanup.

= 3.0.1 [2026-07-18] =

**Fixed**

* Self-healing v3 migration. If `noindex_seo_config_version` claims migration completed (version >= 3) but the consolidated `noindex_seo_settings` option is somehow missing, `noindex_seo_check_migration()` now re-runs the migration automatically. This recovers silently from partial failures: object-cache staleness after the write, request interrupted mid-migration, a third-party plugin clearing options, or DB write errors that did not raise a PHP error. Without this guard, the front-end would fall back to all-zero defaults (site fully indexable) until someone re-saved the settings page.

**Compatibility**

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5

**Tests**

* Added test for the self-healing migration path.

= 3.0.0 [2026-07-18] =

**Major release — storage consolidation.** Settings are now stored in a single autoloaded option (`noindex_seo_settings`) instead of ~110 individual options. Reduces `wp_options` autoload weight on every page load. Legacy options are preserved (marked non-autoloaded) for one major version to allow safe rollback to 2.x; they will be removed in 4.0.

**Added**

* **"Apply recommended defaults" button** on the settings page. One click enables all 12 contexts flagged as "Recommended" in the UI (privacy policy, date archives, pagination, search results, attachment pages, preview/customize-preview, and 404). Previously required ~60 individual checkbox toggles.
* **Filterable conflict-detection list.** The list of plugins that may conflict with noindex SEO is now passed through `apply_filters('noindex_seo_conflicting_plugins', ...)`. Third-party code can extend or replace the list without editing the plugin.

**Changed**

* **Storage consolidated**: 110 directive options (`{directive}_seo_{context}`) + 5 config options (`noindex_seo_config_*`) merged into one `noindex_seo_settings` array. Reads go through new accessors (`noindex_seo_get_settings()`, `noindex_seo_get_setting()`, `noindex_seo_get_config()`). The hourly transient cache is preserved on top.
* **Transient invalidation is now automatic**: any update to `noindex_seo_settings` clears the `noindex_seo_options` transient via the `update_option_noindex_seo_settings` hook. Previously only the admin form save cleared it, leaving WP-CLI / REST / programmatic edits stale for up to one hour.
* **Migration**: existing 2.x installs are migrated automatically on `plugins_loaded` (idempotent, version-gated by `noindex_seo_config_version`). Legacy options are kept and marked non-autoloaded so a rollback to 2.x restores the pre-3.0 state.
* **Uninstall retrocompatibility**: `uninstall.php` deletes both the new consolidated option and all legacy individual options (via wildcard SQL). Sites that upgrade from 2.x and later uninstall will be cleaned up completely regardless of whether migration ran.

**Compatibility**

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5

**Tests**

* Added PHPUnit test suite (previously the project shipped only a plugin-header smoke test). Coverage: contexts helper, settings accessors, v2→v3 migration, form save, bulk actions, meta box save, conflict-detection filter.

= 2.0.2 [2026-07-18] =

**Fixed**

* Bulk action "Enable Robots Override" no longer creates duplicate `postmeta` rows. The previous implementation used `INSERT ... ON DUPLICATE KEY UPDATE`, but WordPress's `postmeta` table has no unique key on `(post_id, meta_key)`, so the `ON DUPLICATE KEY UPDATE` branch never fired and every bulk run on a post that already had the meta inserted a duplicate row. The bulk handler now uses `update_post_meta()` and `delete_post_meta()` exclusively.
* Bulk action "Disable Robots Override" now removes the override meta entirely (previously set its value to `0`, leaving a redundant row).

**Changed**

* Removed three dead contexts (`feed`, `comment_feed`, `robots`) that were registered, migrated, and cleaned up but never evaluated at runtime and never exposed in the admin UI. The plugin now consistently registers and evaluates 22 page contexts (down from a nominal 25). Existing orphan options from earlier installs are cleaned by the uninstall routine's wildcard delete.
* Extracted `noindex_seo_get_contexts()` as the single source of truth for the context list shared by settings registration, v2 migration, form processing. `uninstall.php` retains its own copy (technical constraint: the main plugin file is not loaded during uninstall) with a sync warning comment.
* Corrected `phpcs.xml` `minimum_supported_wp_version` from `6.6` to `5.7` to match the plugin header. This setting was stale from before the 2.0.1 minimum-WP correction.
* Updated `readme.txt` description counts from 25 to 22 page contexts.
* **Bulk action performance characteristic changed**: the rewrite from a single batched SQL statement to per-post `update_post_meta()` / `delete_post_meta()` calls trades O(1) queries for O(N) queries on bulk selections, in exchange for correctness (no more duplicate rows) and proper WP meta-cache invalidation. Typical admin bulk selections (≤200 posts) are unaffected; very large selections (thousands of posts) may take noticeably longer.

**Deprecated**

* `noindex_seo_clear_transient()`: was hooked to `update_option_noindexseo`, a hook that never fires because `noindexseo` is the Settings API group name, not an option name. The function now emits a deprecation notice via `_deprecated_function()` and continues to clear the `noindex_seo_options` transient if called directly. The transient is cleared correctly inside `noindex_seo_process_form()` after every successful save. The function will be removed in a future release.

**Code Quality**

* `bin/preflight.sh`: hardened temp-file handling (mktemp moved to script top, `trap … EXIT` cleanup, no more predictable `/tmp/composer-audit.*` paths that were vulnerable to symlink overwrite on shared hosting); fixed `2>/null` typo; added rsync / `.distignore` / build-tree-non-empty guards so the forbidden-artefact scan cannot pass vacuously; replaced npm-audit subshell with `pushd`/`popd` so gate counters are not lost.
* Added `bin/preflight.sh`: automated pre-deploy verification covering PHPCS, PHPStan level 9, PHPCompatibility, PHPUnit, dependency audit, and candidate-ZIP artefact inspection. Prints a PASS/FAIL report per section and exits non-zero on any failure.
* Added `.claude/settings.json` deny rules for `deploy.sh`, `git push`, `git tag`, and `git merge`, enforcing the agent operating boundaries mandated by AGENTS.md mechanically rather than only in prose.

**Compatibility**

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5

**Tests**

* PHP Coding Standards: 3.13.5
* WordPress Coding Standards: 3.3.0
* PHPStan: 2.1.55
* PHPUnit: 9.6.34

= 2.0.1 [2026-05-25] =

**Added**

* New option "Delete all plugin data on uninstall" (Settings → noindex SEO → General Configuration). By default, all data is preserved when the plugin is uninstalled. Enable this option to remove all settings and per-post directives on uninstall.

**Changed**

* Lowered minimum WordPress requirement from 6.6 to 5.7.
* Custom post types registered by plugins or themes on the `init` hook now correctly receive the Robots column, bulk actions, and list filter in granular control mode.

**Code Quality**

* Added `NOINDEX_SEO_VERSION` constant for asset cache-busting.
* PHP type safety improvements; passes PHPStan level 9 on PHP 8.5 with zero errors.
* Extracted `noindex_seo_save_directives_from_post()` helper to eliminate duplicated save logic.
* Removed dead code and dead hook registration.

**Compatibility**

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5

**Tests**

* PHP Coding Standards: 3.13.5
* WordPress Coding Standards: 3.3.0
* PHPStan: 2.1.55
* PHPUnit: 9.6.34

= 2.0.0 [2026-01-20] =

**New Features**

* 5 independent robots directives: noindex, nofollow, noarchive, nosnippet, noimageindex
* Each directive can be enabled independently for any page context (125 total options)
* HTTP Headers support: Choose between HTML meta tags, HTTP headers, or both
* Granular per-post/page control (optional):
  - Override global settings for individual posts/pages
  - Meta boxes for Classic Editor
  - Native Gutenberg sidebar panel for Block Editor
  - Quick Edit support for fast inline editing
  - Bulk actions to enable/disable overrides
  - Custom "Robots" column in post lists
  - Filter posts by override status
* Modern checkbox-based interface with emoji icons and tooltips

**Security & Code Quality**

* Modernized code with PHP 7.2+ strict types and type declarations

**Compatibility & Migration**

* WordPress: 5.7 - 7.1
* PHP: 7.2 - 8.5
* Automatic migration from v1.x (your existing settings are preserved)
* No manual configuration needed - just update and go
* Fully backward compatible

= 1.2.0 [2025-04-08] =

**Changes**

* Improved functions documentation.

**Fixes**

* The way the options are saved.

**Compatibility**

* WordPress: 4.1 - 6.8
* PHP: 5.6 - 8.4

**Tests**

* PHP Coding Standards: 3.12.1
* WordPress Coding Standards: 3.1.0
* Plugin Check (PCP): 1.4.0

= 1.1.1 [2024-11-04] =

**Added**

* Configuration option to dismiss other SEO plugin incompatibilities.

**Compatibility**

* WordPress: 4.1 - 6.7
* PHP: 5.6 - 8.4

= 1.1.0 [2024-11-02] =

**Added**

* Detects other WordPress SEO plugins, and creates a notice about it, to avoid conflicts.
* Has filters, so other plugins can hack.

**Changed**

* Uses native wp_robots functions (since WP 5.7+)
* Big refactory.
* Less size, improved code quality.

**Compatibility**

* WordPress: 4.1 - 6.7
* PHP: 5.6 - 8.4

**Tests**

* PHP Coding Standards: 3.10.3
* WordPress Coding Standards: 3.1.0
* Plugin Check (PCP): 1.1.0

== Security ==

This plugin adheres to the following security measures and review protocols for each version:

* [WordPress Plugin Handbook](https://developer.wordpress.org/plugins/)
* [WordPress Plugin Security](https://developer.wordpress.org/plugins/wordpress-org/plugin-security/)
* [WordPress APIs Security](https://developer.wordpress.org/apis/security/)
* [WordPress Coding Standards](https://github.com/WordPress/WordPress-Coding-Standards)
* [Plugin Check (PCP)](https://wordpress.org/plugins/plugin-check/)

== Privacy ==

* This plugin does not collect any information about your site, your identity, the plugins, themes or content the site has.

== Vulnerabilities ==

* No vulnerabilities have been published up to version 2.0.1.
* Version 2.0.0 includes proactive security hardening based on comprehensive security audit (see docs/SECURITY-2026-01-20.md).

Found a security vulnerability? Please report it to us privately at the [noindex SEO GitHub repository](https://github.com/javiercasares/noindex-seo/security/advisories/new).