diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index 58c4113ffc..d2ffa675b1 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -859,11 +859,30 @@ function update_option( $option, $value, $autoload = null ) { } if ( ! wp_installing() ) { - $alloptions = wp_load_alloptions( true ); - if ( isset( $alloptions[ $option ] ) ) { + if ( ! isset( $update_args['autoload'] ) ) { + // Update the cached value based on where it is currently cached. + $alloptions = wp_load_alloptions( true ); + if ( isset( $alloptions[ $option ] ) ) { + $alloptions[ $option ] = $serialized_value; + wp_cache_set( 'alloptions', $alloptions, 'options' ); + } else { + wp_cache_set( $option, $serialized_value, 'options' ); + } + } elseif ( 'yes' === $update_args['autoload'] ) { + // Delete the individual cache, then set in alloptions cache. + wp_cache_delete( $option, 'options' ); + + $alloptions = wp_load_alloptions( true ); $alloptions[ $option ] = $serialized_value; wp_cache_set( 'alloptions', $alloptions, 'options' ); } else { + // Delete the alloptions cache, then set the individual cache. + $alloptions = wp_load_alloptions( true ); + if ( isset( $alloptions[ $option ] ) ) { + unset( $alloptions[ $option ] ); + wp_cache_set( 'alloptions', $alloptions, 'options' ); + } + wp_cache_set( $option, $serialized_value, 'options' ); } } diff --git a/tests/phpunit/tests/option/option.php b/tests/phpunit/tests/option/option.php index ae4b0e71f6..04b89c4429 100644 --- a/tests/phpunit/tests/option/option.php +++ b/tests/phpunit/tests/option/option.php @@ -777,4 +777,36 @@ class Tests_Option_Option extends WP_UnitTestCase { // Assert that the filter is still present. $this->assertSame( 10, has_filter( 'pre_option_foo', '__return_zero' ) ); } + + /** + * Tests that calling update_option() with changed autoload from 'no' to 'yes' updates the cache correctly. + * + * This ensures that no stale data is served in case the option is deleted after. + * + * @ticket 51352 + * + * @covers ::update_option + */ + public function test_update_option_with_autoload_change_no_to_yes() { + add_option( 'foo', 'value1', '', 'no' ); + update_option( 'foo', 'value2', 'yes' ); + delete_option( 'foo' ); + $this->assertFalse( get_option( 'foo' ) ); + } + + /** + * Tests that calling update_option() with changed autoload from 'yes' to 'no' updates the cache correctly. + * + * This ensures that no stale data is served in case the option is deleted after. + * + * @ticket 51352 + * + * @covers ::update_option + */ + public function test_update_option_with_autoload_change_yes_to_no() { + add_option( 'foo', 'value1', '', 'yes' ); + update_option( 'foo', 'value2', 'no' ); + delete_option( 'foo' ); + $this->assertFalse( get_option( 'foo' ) ); + } }