diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index ac17c2f501..66fb6e4fd1 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -295,9 +295,18 @@ function update_option( $option, $value, $autoload = null ) { */ $value = apply_filters( 'pre_update_option', $value, $option, $old_value ); - // If the new and old values are the same, no need to update. - if ( $value === $old_value ) + /* + * If the new and old values are the same, no need to update. + * + * Unserialized values will be adequate in most cases. If the unserialized + * data differs, the (maybe) serialized data is checked to avoid + * unnecessary database calls for otherwise identical object instances. + * + * See https://core.trac.wordpress.org/ticket/38903 + */ + if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) { return false; + } /** This filter is documented in wp-includes/option.php */ if ( apply_filters( 'default_option_' . $option, false, $option, false ) === $old_value ) { diff --git a/tests/phpunit/tests/option/updateOption.php b/tests/phpunit/tests/option/updateOption.php index 32ae5e5b4e..eb85b1203a 100644 --- a/tests/phpunit/tests/option/updateOption.php +++ b/tests/phpunit/tests/option/updateOption.php @@ -165,6 +165,31 @@ class Tests_Option_UpdateOption extends WP_UnitTestCase { $this->assertEquals( $value, 'bar2' ); } + /** + * @ticket 38903 + */ + public function test_update_option_array_with_object() { + $array_w_object = array( + 'url' => 'http://src.wordpress-develop.dev/wp-content/uploads/2016/10/cropped-Blurry-Lights.jpg', + 'meta_data' => (object) array( + 'attachment_id' => 292, + 'height' => 708, + 'width' => 1260, + ), + ); + + // Add the option, it did not exist before this. + add_option( 'array_w_object', $array_w_object ); + + $num_queries_pre_update = get_num_queries(); + + // Update the option using the same array with an object for the value. + $this->assertFalse( update_option( 'array_w_object', $array_w_object ) ); + + // Check that no new database queries were performed. + $this->assertEquals( $num_queries_pre_update, get_num_queries() ); + } + /** * `add_filter()` callback for test_should_respect_default_option_filter_when_option_does_not_yet_exist_in_database(). */