Skip to content

Commit

Permalink
Add transient validation methods and corresponding tests
Browse files Browse the repository at this point in the history
A new function named 'valid_transient' has been introduced to verify if a transient and its value are valid, also by checking if they have not expired. Sites with transient data can use the 'valid_site_transient' function to perform similar checks. Along with these functions, PHPUnit test cases have been added to ensure these functions perform as expected.
  • Loading branch information
paul bearne committed May 27, 2024
1 parent 43b51f5 commit 014cf5d
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 20 deletions.
90 changes: 70 additions & 20 deletions src/wp-includes/option.php
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,40 @@ function delete_transient( $transient ) {
return $result;
}

/**
* Determines if a transient is valid.
*
* If the transient does not exist, does not have a value, or has expired,
* then the return value will be false.
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
*
* @return bool
* @since 4.7.0
*
*/
function valid_transient( $transient ) {
$transient_option = '_transient_' . $transient;
$transient_timeout = '_transient_timeout_' . $transient;

wp_prime_option_caches( array( $transient_option, $transient_timeout ) );
$timeout = get_option( $transient_timeout );

// No transient found.
if ( false === $timeout ) {

return (bool) get_option( $transient_option );
} elseif ( $timeout < time() ) { // Expired transient detected.
delete_option('_transient_' . $transient);
delete_option($transient_timeout);

return false;
}

// Transient is valid.
return true;
}

/**
* Retrieves the value of a transient.
*
Expand Down Expand Up @@ -1428,15 +1462,8 @@ function get_transient( $transient ) {
// If option is not in alloptions, it is not autoloaded and thus has a timeout.
$alloptions = wp_load_alloptions();

if ( ! isset( $alloptions[ $transient_option ] ) ) {
$transient_timeout = '_transient_timeout_' . $transient;
wp_prime_option_caches( array( $transient_option, $transient_timeout ) );
$timeout = get_option( $transient_timeout );
if ( false !== $timeout && $timeout < time() ) {
delete_option( $transient_option );
delete_option( $transient_timeout );
$value = false;
}
if ( ! isset( $alloptions[ $transient_option ] ) && ! valid_transient( $transient ) ) {
$value = false;
}
}

Expand Down Expand Up @@ -2469,7 +2496,39 @@ function delete_site_transient( $transient ) {

return $result;
}
/**
* Determines if a site transient is valid.
*
* If the transient does not exist, does not have a value, or has expired,
* then the return value will be false.
*
* @since 4.7.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
*
* @return bool
*/
function valid_site_transient( $transient ) {
$transient_option = '_site_transient_' . $transient;
$transient_timeout = '_site_transient_timeout_' . $transient;

wp_prime_site_option_caches( array( $transient_option, $transient_timeout ) );
$timeout = get_site_option( $transient_timeout );

// No transient found.
if ( false === $timeout ) {

return (bool) get_option( $transient_option );
} elseif ( $timeout < time() ) { // Expired transient detected.
delete_site_option( '_site_transient_' . $transient );
delete_site_option( $transient_timeout );

return false;
}

// Transient is valid.
return true;
}
/**
* Retrieves the value of a site transient.
*
Expand Down Expand Up @@ -2512,21 +2571,12 @@ function get_site_transient( $transient ) {
} else {
// Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
$no_timeout = array( 'update_core', 'update_plugins', 'update_themes' );
$transient_option = '_site_transient_' . $transient;
if ( ! in_array( $transient, $no_timeout, true ) ) {
$transient_timeout = '_site_transient_timeout_' . $transient;
wp_prime_site_option_caches( array( $transient_option, $transient_timeout ) );

$timeout = get_site_option( $transient_timeout );
if ( false !== $timeout && $timeout < time() ) {
delete_site_option( $transient_option );
delete_site_option( $transient_timeout );
if ( ! in_array( $transient, $no_timeout, true ) && ! valid_site_transient( $transient ) ) {
$value = false;
}
}

if ( ! isset( $value ) ) {
$value = get_site_option( $transient_option );
$value = get_site_option( '_site_transient_' . $transient );
}
}

Expand Down
46 changes: 46 additions & 0 deletions tests/phpunit/tests/option/ValidTransient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/**
* @group option
* @group transient
*
* @covers ::valid_transient
*/
class Tests_Option_ValidTransient extends WP_UnitTestCase {

/**
* @ticket 37040
*/
public function test_valid_transient_with_expired_timeout() {
$transient_name = 'valid_transient_with_expired_timeout';
$transient_value = 'transient_value';

set_transient( $transient_name, $transient_value, 10 );

$this->assertTrue( valid_transient( $transient_name ) );

update_option( '_transient_timeout_' . $transient_name, time() - 10 );

$this->assertFalse( valid_transient( $transient_name ) );
}

/**
* @ticket 37040
*/
public function test_valid_transient_with_no_timeout() {
$transient_name = 'valid_transient_with_no_timeout';
$transient_value = 'transient_value';

set_transient( $transient_name, $transient_value );
$this->assertTrue( valid_transient( $transient_name ) );
}

/**
* @ticket 37040
*/
public function test_valid_transient_with_no_transient() {
$transient_name = 'valid_transient_with_no_transient';

$this->assertFalse( valid_transient( $transient_name ) );
}
}
59 changes: 59 additions & 0 deletions tests/phpunit/tests/option/validSiteTransient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/**
* @group option
* @group transient
*
* @covers ::valid_site_transient
*/
class Tests_Option_ValidSiteTransient extends WP_UnitTestCase {

/**
* @ticket 37040
*/
public function test_valid_site_transient_with_expired_timeout() {
$transient_name = 'valid_site_transient_with_expired_timeout';
$transient_value = 'transient_value';

set_site_transient( $transient_name, $transient_value, 10 );

$this->assertTrue( valid_site_transient( $transient_name ) );

update_option( '_site_transient_timeout_' . $transient_name, time() - 10 );

$this->assertFalse( valid_site_transient( $transient_name ) );
}

/**
* @ticket 37040
*/
public function test_valid_site_transient_with_no_timeout() {
$transient_name = 'valid_site_transient_with_no_timeout';
$transient_value = 'transient_value';

set_site_transient( $transient_name, $transient_value );

$this->assertTrue( valid_site_transient( $transient_name ) );
}

/**
* @ticket 37040
*/
public function test_valid_site_transient_with_no_transient() {
$transient_name = 'valid_site_transient_with_no_transient';

$this->assertFalse( valid_site_transient( $transient_name ) );
}

/**
* @ticket 37040
*/
public function test_valid_site_transient_with_no_site_transient() {
$transient_name = 'valid_site_transient_with_no_site_transient';
$transient_value = 'transient_value';

set_transient( $transient_name, $transient_value );

$this->assertFalse( valid_site_transient( $transient_name ) );
}
}

0 comments on commit 014cf5d

Please sign in to comment.