diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index 1157b56d94..1b5dde235c 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -622,7 +622,8 @@ function get_transient( $transient ) { $alloptions = wp_load_alloptions(); if ( !isset( $alloptions[$transient_option] ) ) { $transient_timeout = '_transient_timeout_' . $transient; - if ( get_option( $transient_timeout ) < time() ) { + $timeout = get_option( $transient_timeout ); + if ( false !== $timeout && $timeout < time() ) { delete_option( $transient_option ); delete_option( $transient_timeout ); $value = false; diff --git a/tests/phpunit/tests/option/transient.php b/tests/phpunit/tests/option/transient.php index 63c4b01080..7edcb72872 100644 --- a/tests/phpunit/tests/option/transient.php +++ b/tests/phpunit/tests/option/transient.php @@ -83,4 +83,75 @@ class Tests_Option_Transient extends WP_UnitTestCase { update_option( '_transient_timeout_' . $key, $now - 1 ); $this->assertFalse( get_transient( $key ) ); } + + /** + * If get_option( $transient_timeout ) returns false, don't bother trying to delete the transient. + * + * @ticket 30380 + */ + function test_nonexistent_key_dont_delete_if_false() { + // Create a bogus a transient + $key = 'test_transient'; + set_transient( $key, 'test', 60 * 10 ); + $this->assertEquals( 'test', get_transient( $key ) ); + + // Useful variables for tracking + $transient_timeout = '_transient_timeout_' . $key; + + // Mock an action for tracking action calls + $a = new MockAction(); + + // Make sure the timeout option returns false + add_filter( 'option_' . $transient_timeout, '__return_false' ); + + // Add some actions to make sure options are _not_ deleted + add_action( 'delete_option', array( $a, 'action' ) ); + + // Act + get_transient( $key ); + + // Make sure delete option was not called for both the transient and the timeout + $this->assertEquals( 0, $a->get_call_count() ); + } + + /** + * @ticket 30380 + */ + function test_nonexistent_key_old_timeout() { + // Create a transient + $key = 'test_transient'; + set_transient( $key, 'test', 60 * 10 ); + $this->assertEquals( 'test', get_transient( $key ) ); + + // Make sure the timeout option returns false + $timeout = '_transient_timeout_' . $key; + $transient_option = '_transient_' . $key; + add_filter( 'option_' . $timeout, '__return_zero' ); + + // Mock an action for tracking action calls + $a = new MockAction(); + + // Add some actions to make sure options are deleted + add_action( 'delete_option', array( $a, 'action' ) ); + + // Act + get_transient( $key ); + + // Make sure delete option was called for both the transient and the timeout + $this->assertEquals( 2, $a->get_call_count() ); + + $expected = array( + array( + 'action' => 'action', + 'tag' => 'delete_option', + 'args' => array( $transient_option ), + ), + array( + 'action' => 'action', + 'tag' => 'delete_option', + 'args' => array( $timeout ), + ), + ); + $this->assertEquals( $expected, $a->get_events() ); + } }