Add filter to control wpseo_taxonomy_meta option autoload#23138
Add filter to control wpseo_taxonomy_meta option autoload#23138enricobattocchi wants to merge 1 commit into
Conversation
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]>
Coverage Report for CI Build 543Coverage increased (+0.004%) to 52.848%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats💛 - Coveralls |
There was a problem hiding this comment.
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_autoloadfilter inWPSEO_Taxonomy_Meta::save_tax_meta()and passes the chosen value intoupdate_option(). - Adds WP tests asserting default autoload behavior and behavior when the filter disables/enables autoloading.
- Adds a test helper that reads the
autoloadflag 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.
| * 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 ); | ||
|
|
There was a problem hiding this comment.
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.
| * 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; | |
| } |
| * 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, | ||
| ), | ||
| ); |
There was a problem hiding this comment.
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.
| * 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; |
| $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' ); |
There was a problem hiding this comment.
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.
| $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' ); | |
| } |
| 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' ], | ||
| ); | ||
|
|
There was a problem hiding this comment.
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.
Context
Sites with many taxonomy terms can have a very large
wpseo_taxonomy_metaoption (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:
Yoast\WP\SEO\taxonomy_meta_option_autoloadfilter, which can be used to override the default setting of having thewpseo_taxonomy_metaoption autoloaded.Relevant technical choices:
true) to avoid affecting existing sites.save_tax_meta(), the central save path for taxonomy meta, which is called on every term save.update_optioncalls (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+.$include_in_all = falseproperty 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)
wp_optionstable:SELECT autoload FROM wp_options WHERE option_name = 'wpseo_taxonomy_meta'— should beon.wpseo_taxonomy_metais not queried separately (it's part of the autoloaded options batch).Test 2: Test the filter (autoload off)
functions.php:off.wpseo_taxonomy_metanow appears as a separate query when viewing a taxonomy archive.Test 3: Test filter removal (restores autoload on)
functions.php.on.Relevant test scenarios
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
Impact check
This PR affects the following parts of the plugin, which may require extra testing:
save_tax_meta()method inWPSEO_Taxonomy_Meta.Other environments
[shopify-seo], added test instructions for Shopify and attached theShopifylabel to this PR.[yoast-doc-extension], added test instructions for Yoast SEO for Google Docs and attached theGoogle Docs Add-onlabel to this PR.Documentation
The filter is documented via its PHPDoc block in the code.
Quality assurance
grunt build:imagesand commited the results, if my PR introduces new images or SVGs.Innovation
innovationlabel.Fixes #23121