Skip to content

Add filter to control wpseo_taxonomy_meta option autoload#23138

Open
enricobattocchi wants to merge 1 commit into
trunkfrom
23121-taxonomy-meta-autoload-filter
Open

Add filter to control wpseo_taxonomy_meta option autoload#23138
enricobattocchi wants to merge 1 commit into
trunkfrom
23121-taxonomy-meta-autoload-filter

Conversation

@enricobattocchi
Copy link
Copy Markdown
Member

Context

Sites with many taxonomy terms can have a very large wpseo_taxonomy_meta option (users report 340 KB+) that gets autoloaded on every single request, negatively impacting performance — especially on hosts with limited object caching or DB cache size constraints.

This follows the same pattern as Yoast/wordpress-seo-premium#4000 which introduced a similar filter for redirect options.

Summary

This PR can be summarized in the following changelog entry:

  • Introduces the Yoast\WP\SEO\taxonomy_meta_option_autoload filter, which can be used to override the default setting of having the wpseo_taxonomy_meta option autoloaded.

Relevant technical choices:

  • The default behavior remains unchanged (autoload = true) to avoid affecting existing sites.
  • The filter is applied in save_tax_meta(), the central save path for taxonomy meta, which is called on every term save.
  • Other update_option calls (import, upgrade, split term) don't pass an explicit autoload param and thus preserve whatever value is currently set in the DB — this is the correct behavior since WordPress 6.6+.
  • The $include_in_all = false property already signals this option isn't expected on every request, making it a good candidate for optional autoload control.

Test instructions

Test instructions for the acceptance test before the PR gets merged

This PR can be acceptance tested by following these steps:

Test 1: Verify default behavior (autoload on)

  1. Edit a taxonomy term (e.g., a category) and set an SEO title via Yoast.
  2. Save the term.
  3. Check the wp_options table: SELECT autoload FROM wp_options WHERE option_name = 'wpseo_taxonomy_meta' — should be on.
  4. Verify with Query Monitor that wpseo_taxonomy_meta is not queried separately (it's part of the autoloaded options batch).

Test 2: Test the filter (autoload off)

  1. Add the following snippet to functions.php:
    add_filter( 'Yoast\WP\SEO\taxonomy_meta_option_autoload', '__return_false' );
  2. Edit a taxonomy term and save.
  3. Check the DB: autoload should now be off.
  4. Verify with Query Monitor that wpseo_taxonomy_meta now appears as a separate query when viewing a taxonomy archive.

Test 3: Test filter removal (restores autoload on)

  1. Remove the snippet from functions.php.
  2. Edit a taxonomy term and save.
  3. Check the DB: autoload should be back to on.

Relevant test scenarios

  • Changes should be tested with the browser console open
  • Changes should be tested on different posts/pages/taxonomies/custom post types/custom taxonomies
  • Changes should be tested on different editors (Default Block/Gutenberg/Classic/Elementor/other)
  • Changes should be tested on different browsers
  • Changes should be tested on multisite

Different taxonomy types should be tested to ensure the filter works for categories, tags, and custom taxonomies alike.

Test instructions for QA when the code is in the RC

  • QA should use the same steps as above.

Impact check

This PR affects the following parts of the plugin, which may require extra testing:

  • Taxonomy meta saving — the save_tax_meta() method in WPSEO_Taxonomy_Meta.
  • No other functionality is affected. The option continues to work identically; only the DB-level autoload flag changes when the filter is used.

Other environments

  • This PR also affects Shopify. I have added a changelog entry starting with [shopify-seo], added test instructions for Shopify and attached the Shopify label to this PR.
  • This PR also affects Yoast SEO for Google Docs. I have added a changelog entry starting with [yoast-doc-extension], added test instructions for Yoast SEO for Google Docs and attached the Google Docs Add-on label to this PR.

Documentation

  • I have written documentation for this change. For example, comments in the Relevant technical choices, comments in the code, documentation on Confluence / shared Google Drive / Yoast developer portal, or other.

The filter is documented via its PHPDoc block in the code.

Quality assurance

  • I have tested this code to the best of my abilities.
  • During testing, I had activated all plugins that Yoast SEO provides integrations for.
  • I have added unit tests to verify the code works as intended.
  • If any part of the code is behind a feature flag, my test instructions also cover cases where the feature flag is switched off.
  • I have written this PR in accordance with my team's definition of done.
  • I have checked that the base branch is correctly set.
  • I have run grunt build:images and commited the results, if my PR introduces new images or SVGs.

Innovation

  • No innovation project is applicable for this PR.
  • This PR falls under an innovation project. I have attached the innovation label.
  • I have added my hours to the WBSO document.

Fixes #23121

Introduces the `Yoast\WP\SEO\taxonomy_meta_option_autoload` filter,
which can be used to override the default setting of having the
taxonomy meta option autoloaded. Sites with many taxonomy terms may
have a large option that negatively impacts performance when autoloaded
on every request.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@enricobattocchi enricobattocchi added the changelog: enhancement Needs to be included in the 'Enhancements' category in the changelog label Apr 7, 2026
@coveralls
Copy link
Copy Markdown

Coverage Report for CI Build 543

Coverage increased (+0.004%) to 52.848%

Details

  • Coverage increased (+0.004%) from the base build.
  • Patch coverage: 2 uncovered changes across 1 file (0 of 2 lines covered, 0.0%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
inc/options/class-wpseo-taxonomy-meta.php 2 0 0.0%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 64137
Covered Lines: 33832
Line Coverage: 52.75%
Relevant Branches: 16093
Covered Branches: 8568
Branch Coverage: 53.24%
Branches in Coverage %: Yes
Coverage Strength: 46900.72 hits per line

💛 - Coveralls

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a new filter hook to control whether the wpseo_taxonomy_meta option is saved with autoload enabled, addressing performance concerns on sites with large taxonomy meta.

Changes:

  • Adds the Yoast\WP\SEO\taxonomy_meta_option_autoload filter in WPSEO_Taxonomy_Meta::save_tax_meta() and passes the chosen value into update_option().
  • Adds WP tests asserting default autoload behavior and behavior when the filter disables/enables autoloading.
  • Adds a test helper that reads the autoload flag directly from the options table.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
inc/options/class-wpseo-taxonomy-meta.php Applies a new filter to control the autoload flag when persisting taxonomy meta.
tests/WP/Inc/Options/Taxonomy_Meta_Test.php Adds tests for the new autoload behavior and a DB helper to verify the autoload column value.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +552 to +557
* Return false to disable autoloading.
*
* @param bool $autoload Whether to autoload the option. Default true.
*/
$autoload = (bool) apply_filters( 'Yoast\WP\SEO\taxonomy_meta_option_autoload', true );

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

save_tax_meta() now always passes an explicit boolean $autoload to update_option(). This changes behavior for sites where wpseo_taxonomy_meta was already set to non-autoload (e.g., manually flipped to off): saving any term will force it back to autoload=true unless the filter is added. Consider defaulting the filter value to null (so WordPress preserves the existing autoload setting) and only forcing on/off when the filter returns a valid override. Also avoid casting the filtered value to bool so values like null or 'auto' (WP 6.6+ autoload modes) can be supported or at least not misinterpreted.

Suggested change
* Return false to disable autoloading.
*
* @param bool $autoload Whether to autoload the option. Default true.
*/
$autoload = (bool) apply_filters( 'Yoast\WP\SEO\taxonomy_meta_option_autoload', true );
*
* Return `false` to disable autoloading, `true` to enable it, a supported string
* autoload mode to explicitly set that mode, or `null` to preserve the existing
* autoload setting for the option.
*
* @param bool|string|null $autoload Whether to autoload the option, an explicit
* autoload mode, or null to preserve the
* existing setting. Default null.
*/
$autoload = apply_filters( 'Yoast\WP\SEO\taxonomy_meta_option_autoload', null );
if ( ! is_bool( $autoload ) && ! is_string( $autoload ) && $autoload !== null ) {
$autoload = null;
}
if ( $autoload === null ) {
update_option( self::$name, $tax_meta );
return;
}

Copilot uses AI. Check for mistakes.
Comment on lines +177 to +191
* Gets the autoload value for an option directly from the database.
*
* @param string $option_name The option name.
*
* @return string The autoload value ('on' or 'off').
*/
private function get_autoload_value( $option_name ) {
global $wpdb;

return $wpdb->get_var(
$wpdb->prepare(
"SELECT autoload FROM {$wpdb->options} WHERE option_name = %s",
$option_name,
),
);
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These assertions and helper assume the wp_options.autoload column stores 'on'/'off', but some WordPress versions/environments still store 'yes'/'no' (or other values like 'auto'). To make the test suite robust across the WP version matrix, consider normalizing the DB value (e.g., accept both 'on'+'yes' for enabled and 'off'+'no' for disabled) and update the PHPDoc accordingly.

Suggested change
* Gets the autoload value for an option directly from the database.
*
* @param string $option_name The option name.
*
* @return string The autoload value ('on' or 'off').
*/
private function get_autoload_value( $option_name ) {
global $wpdb;
return $wpdb->get_var(
$wpdb->prepare(
"SELECT autoload FROM {$wpdb->options} WHERE option_name = %s",
$option_name,
),
);
* Gets the normalized autoload value for an option directly from the database.
*
* Normalizes equivalent WordPress autoload representations so tests remain
* stable across WordPress versions and environments.
*
* @param string $option_name The option name.
*
* @return string|null The normalized autoload value ('on' or 'off') when recognized,
* otherwise the raw database value.
*/
private function get_autoload_value( $option_name ) {
global $wpdb;
$autoload_value = $wpdb->get_var(
$wpdb->prepare(
"SELECT autoload FROM {$wpdb->options} WHERE option_name = %s",
$option_name,
),
);
if ( $autoload_value === null ) {
return null;
}
$autoload_value = (string) $autoload_value;
if ( \in_array( $autoload_value, [ 'on', 'yes', 'auto', 'auto-on', 'auto-once' ], true ) ) {
return 'on';
}
if ( \in_array( $autoload_value, [ 'off', 'no', 'auto-off' ], true ) ) {
return 'off';
}
return $autoload_value;

Copilot uses AI. Check for mistakes.
Comment on lines +130 to +140
$term = self::factory()->term->create_and_get( [ 'taxonomy' => 'category' ] );

WPSEO_Taxonomy_Meta::set_values(
$term->term_id,
'category',
[ 'wpseo_title' => 'Test title' ],
);

$this->assertSame( 'off', $this->get_autoload_value( 'wpseo_taxonomy_meta' ) );

\remove_filter( 'Yoast\WP\SEO\taxonomy_meta_option_autoload', '__return_false' );
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove_filter() is called at the end of the test, but it won’t run if an assertion throws earlier, which can leak the filter into subsequent tests and cause cascading failures. Wrap the body in try { ... } finally { remove_filter(...) } (or remove the filter in tear_down()) to guarantee cleanup.

Suggested change
$term = self::factory()->term->create_and_get( [ 'taxonomy' => 'category' ] );
WPSEO_Taxonomy_Meta::set_values(
$term->term_id,
'category',
[ 'wpseo_title' => 'Test title' ],
);
$this->assertSame( 'off', $this->get_autoload_value( 'wpseo_taxonomy_meta' ) );
\remove_filter( 'Yoast\WP\SEO\taxonomy_meta_option_autoload', '__return_false' );
try {
$term = self::factory()->term->create_and_get( [ 'taxonomy' => 'category' ] );
WPSEO_Taxonomy_Meta::set_values(
$term->term_id,
'category',
[ 'wpseo_title' => 'Test title' ],
);
$this->assertSame( 'off', $this->get_autoload_value( 'wpseo_taxonomy_meta' ) );
}
finally {
\remove_filter( 'Yoast\WP\SEO\taxonomy_meta_option_autoload', '__return_false' );
}

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +116
public function test_save_tax_meta_autoloads_by_default() {
$term = self::factory()->term->create_and_get( [ 'taxonomy' => 'category' ] );

WPSEO_Taxonomy_Meta::set_values(
$term->term_id,
'category',
[ 'wpseo_title' => 'Test title' ],
);

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests rely on the existing DB state of wpseo_taxonomy_meta. To keep them order-independent (and to still pass if the implementation changes to preserve an existing autoload value by default), reset state at the start of each test (e.g., delete_option( 'wpseo_taxonomy_meta' )) before calling set_values() so the test always exercises the intended add/update path.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog: enhancement Needs to be included in the 'Enhancements' category in the changelog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Audit wpseo_taxonomy_meta option usage and consider setting autload to "off"

3 participants