From b9e222fd6a7a2e9e5d00786b0e4f164d4204e859 Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Fri, 6 Mar 2015 13:56:44 +0000 Subject: [PATCH] Allow `$autoload` setting to be changed for existing options using `update_option()`. [31628] made it possible to pass an `$autoload` param to `update_option()` that applies when the option does not yet exist in the database. The current changeset introduces parity for existing options: the `$autoload` setting for existing options can be changed via the `$autoload` parameter. For internal simplicity, `$autoload` is ignored for existing options when `$value` is not also changed. This changeset also moves `update_option()` tests into their own class. Props dd32. Fixes #26394. git-svn-id: https://develop.svn.wordpress.org/trunk@31640 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/option.php | 23 ++- tests/phpunit/tests/option/option.php | 110 ----------- tests/phpunit/tests/option/updateOption.php | 202 ++++++++++++++++++++ 3 files changed, 221 insertions(+), 114 deletions(-) create mode 100644 tests/phpunit/tests/option/updateOption.php diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index 2f548e6151..b7725fc472 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -225,11 +225,13 @@ function wp_load_core_site_options( $site_id = null ) { * * @param string $option Option name. Expected to not be SQL-escaped. * @param mixed $value Option value. Must be serializable if non-scalar. Expected to not be SQL-escaped. - * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. Accepts 'yes' or true to - * enable, 'no' or false to disable. Default is enabled. + * @param string|bool $autoload Optional. Whether to load the option when WordPress starts up. For existing options, + * `$autoload` can only be updated using `update_option()` if `$value` is also changed. + * Accepts 'yes' or true to enable, 'no' or false to disable. For non-existent options, + * the default value is 'yes'. * @return bool False if value was not updated and true if value was updated. */ -function update_option( $option, $value, $autoload = 'yes' ) { +function update_option( $option, $value, $autoload = null ) { global $wpdb; $option = trim($option); @@ -273,6 +275,11 @@ function update_option( $option, $value, $autoload = 'yes' ) { /** This filter is documented in wp-includes/option.php */ if ( apply_filters( 'default_option_' . $option, false ) === $old_value ) { + // Default setting for new options is 'yes'. + if ( null === $autoload ) { + $autoload = 'yes'; + } + return add_option( $option, $value, '', $autoload ); } @@ -289,7 +296,15 @@ function update_option( $option, $value, $autoload = 'yes' ) { */ do_action( 'update_option', $option, $old_value, $value ); - $result = $wpdb->update( $wpdb->options, array( 'option_value' => $serialized_value ), array( 'option_name' => $option ) ); + $update_args = array( + 'option_value' => $serialized_value, + ); + + if ( null !== $autoload ) { + $update_args['autoload'] = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes'; + } + + $result = $wpdb->update( $wpdb->options, $update_args, array( 'option_name' => $option ) ); if ( ! $result ) return false; diff --git a/tests/phpunit/tests/option/option.php b/tests/phpunit/tests/option/option.php index 83456e0eb8..a02f8d1bcf 100644 --- a/tests/phpunit/tests/option/option.php +++ b/tests/phpunit/tests/option/option.php @@ -71,18 +71,6 @@ class Tests_Option_Option extends WP_UnitTestCase { $this->assertSame( 'bar', get_option( 'doesnotexist' ) ); } - /** - * @ticket 31047 - */ - public function test_update_option_should_respect_default_option_filter_when_option_does_not_yet_exist_in_database() { - add_filter( 'default_option_doesnotexist', array( $this, '__return_foo' ) ); - $added = update_option( 'doesnotexist', 'bar' ); - remove_filter( 'default_option_doesnotexist', array( $this, '__return_foo' ) ); - - $this->assertTrue( $added ); - $this->assertSame( 'bar', get_option( 'doesnotexist' ) ); - } - function test_serialized_data() { $key = rand_str(); $value = array( 'foo' => true, 'bar' => true ); @@ -149,102 +137,4 @@ class Tests_Option_Option extends WP_UnitTestCase { $actual = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s LIMIT 1", $name ) ); $this->assertEquals( $expected, $actual->autoload ); } - - /** - * @ticket 26394 - */ - public function test_update_option_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_missing() { - if ( is_multisite() ) { - $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); - } - - global $wpdb; - wp_cache_flush(); - update_option( 'test_update_option_default', 'value' ); - wp_cache_flush(); - - // Populate the alloptions cache, which includes autoload=yes options. - wp_load_alloptions(); - - $before = $wpdb->num_queries; - $value = get_option( 'test_update_option_default' ); - $after = $wpdb->num_queries; - - $this->assertEquals( $before, $after ); - $this->assertEquals( $value, 'value' ); - } - - /** - * @ticket 26394 - */ - public function test_update_option_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_yes() { - if ( is_multisite() ) { - $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); - } - - global $wpdb; - wp_cache_flush(); - update_option( 'test_update_option_default', 'value', 'yes' ); - wp_cache_flush(); - - // Populate the alloptions cache, which includes autoload=yes options. - wp_load_alloptions(); - - $before = $wpdb->num_queries; - $value = get_option( 'test_update_option_default' ); - $after = $wpdb->num_queries; - - $this->assertEquals( $before, $after ); - $this->assertEquals( $value, 'value' ); - } - - /** - * @ticket 26394 - */ - public function test_update_option_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_no() { - if ( is_multisite() ) { - $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); - } - - global $wpdb; - wp_cache_flush(); - update_option( 'test_update_option_default', 'value', 'no' ); - wp_cache_flush(); - - // Populate the alloptions cache, which does not include autoload=no options. - wp_load_alloptions(); - - $before = $wpdb->num_queries; - $value = get_option( 'test_update_option_default' ); - $after = $wpdb->num_queries; - - // Database has been hit. - $this->assertEquals( $before + 1, $after ); - $this->assertEquals( $value, 'value' ); - } - - /** - * @ticket 26394 - */ - public function test_update_option_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_false() { - if ( is_multisite() ) { - $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); - } - - global $wpdb; - wp_cache_flush(); - update_option( 'test_update_option_default', 'value', false ); - wp_cache_flush(); - - // Populate the alloptions cache, which does not include autoload=no options. - wp_load_alloptions(); - - $before = $wpdb->num_queries; - $value = get_option( 'test_update_option_default' ); - $after = $wpdb->num_queries; - - // Database has been hit. - $this->assertEquals( $before + 1, $after ); - $this->assertEquals( $value, 'value' ); - } } diff --git a/tests/phpunit/tests/option/updateOption.php b/tests/phpunit/tests/option/updateOption.php new file mode 100644 index 0000000000..208812de0b --- /dev/null +++ b/tests/phpunit/tests/option/updateOption.php @@ -0,0 +1,202 @@ +assertTrue( $added ); + $this->assertSame( 'bar', get_option( 'doesnotexist' ) ); + } + + /** + * @ticket 26394 + */ + public function test_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_missing() { + if ( is_multisite() ) { + $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); + } + + global $wpdb; + wp_cache_flush(); + update_option( 'test_update_option_default', 'value' ); + wp_cache_flush(); + + // Populate the alloptions cache, which includes autoload=yes options. + wp_load_alloptions(); + + $before = $wpdb->num_queries; + $value = get_option( 'test_update_option_default' ); + $after = $wpdb->num_queries; + + $this->assertEquals( $before, $after ); + $this->assertEquals( $value, 'value' ); + } + + /** + * @ticket 26394 + */ + public function test_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_yes() { + if ( is_multisite() ) { + $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); + } + + global $wpdb; + wp_cache_flush(); + update_option( 'test_update_option_default', 'value', 'yes' ); + wp_cache_flush(); + + // Populate the alloptions cache, which includes autoload=yes options. + wp_load_alloptions(); + + $before = $wpdb->num_queries; + $value = get_option( 'test_update_option_default' ); + $after = $wpdb->num_queries; + + $this->assertEquals( $before, $after ); + $this->assertEquals( $value, 'value' ); + } + + /** + * @ticket 26394 + */ + public function test_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_no() { + if ( is_multisite() ) { + $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); + } + + global $wpdb; + wp_cache_flush(); + update_option( 'test_update_option_default', 'value', 'no' ); + wp_cache_flush(); + + // Populate the alloptions cache, which does not include autoload=no options. + wp_load_alloptions(); + + $before = $wpdb->num_queries; + $value = get_option( 'test_update_option_default' ); + $after = $wpdb->num_queries; + + // Database has been hit. + $this->assertEquals( $before + 1, $after ); + $this->assertEquals( $value, 'value' ); + } + + /** + * @ticket 26394 + */ + public function test_should_set_autoload_yes_for_nonexistent_option_when_autoload_param_is_false() { + if ( is_multisite() ) { + $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); + } + + global $wpdb; + wp_cache_flush(); + update_option( 'test_update_option_default', 'value', false ); + wp_cache_flush(); + + // Populate the alloptions cache, which does not include autoload=no options. + wp_load_alloptions(); + + $before = $wpdb->num_queries; + $value = get_option( 'test_update_option_default' ); + $after = $wpdb->num_queries; + + // Database has been hit. + $this->assertEquals( $before + 1, $after ); + $this->assertEquals( $value, 'value' ); + } + + /** + * @group 26394 + */ + public function test_autoload_should_be_updated_for_existing_option_when_value_is_changed() { + if ( is_multisite() ) { + $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); + } + + global $wpdb; + add_option( 'foo', 'bar', '', 'no' ); + $updated = update_option( 'foo', 'bar2', true ); + $this->assertTrue( $updated ); + + wp_cache_flush(); + + // Populate the alloptions cache, which includes autoload=yes options. + wp_load_alloptions(); + + $before = $wpdb->num_queries; + $value = get_option( 'foo' ); + + $this->assertEquals( $before, $wpdb->num_queries ); + $this->assertEquals( $value, 'bar2' ); + } + + /** + * @group 26394 + */ + public function test_autoload_should_not_be_updated_for_existing_option_when_value_is_unchanged() { + if ( is_multisite() ) { + $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); + } + + global $wpdb; + add_option( 'foo', 'bar', '', 'yes' ); + $updated = update_option( 'foo', 'bar', false ); + $this->assertFalse( $updated ); + + wp_cache_flush(); + + // Populate the alloptions cache, which includes autoload=yes options. + wp_load_alloptions(); + + $before = $wpdb->num_queries; + $value = get_option( 'foo' ); + + // 'foo' should still be autoload=yes, so we should see no additional querios. + $this->assertEquals( $before, $wpdb->num_queries ); + $this->assertEquals( $value, 'bar' ); + } + + /** + * @group 26394 + */ + public function test_autoload_should_not_be_updated_for_existing_option_when_value_is_changed_but_no_value_of_autoload_is_provided() { + if ( is_multisite() ) { + $this->markTestSkipped( 'Not testable in MS: wpmu_create_blog() defines WP_INSTALLING, which causes cache misses.' ); + } + + global $wpdb; + add_option( 'foo', 'bar', '', 'yes' ); + + // Don't pass a value for `$autoload`. + $updated = update_option( 'foo', 'bar2' ); + $this->assertTrue( $updated ); + + wp_cache_flush(); + + // Populate the alloptions cache, which includes autoload=yes options. + wp_load_alloptions(); + + $before = $wpdb->num_queries; + $value = get_option( 'foo' ); + + // 'foo' should still be autoload=yes, so we should see no additional querios. + $this->assertEquals( $before, $wpdb->num_queries ); + $this->assertEquals( $value, 'bar2' ); + } + + /** + * `add_filter()` callback for test_should_respect_default_option_filter_when_option_does_not_yet_exist_in_database(). + */ + public function __return_foo() { + return 'foo'; + } +}