You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

347 lines
7.8 KiB

<?php
/**
* WPSEO plugin file.
*
* @package WPSEO\XML_Sitemaps
*/
/**
* Handles sitemaps caching and invalidation.
*
* @since 3.2
*/
class WPSEO_Sitemaps_Cache {
/**
* Holds the options that, when updated, should cause the cache to clear.
*
* @var array
*/
protected static $cache_clear = array();
/**
* Mirror of enabled status for static calls.
*
* @var bool
*/
protected static $is_enabled = false;
/**
* Holds the flag to clear all cache.
*
* @var bool
*/
protected static $clear_all = false;
/**
* Holds the array of types to clear.
*
* @var array
*/
protected static $clear_types = array();
/**
* Hook methods for invalidation on necessary events.
*/
public function __construct() {
add_action( 'init', array( $this, 'init' ) );
add_action( 'deleted_term_relationships', array( __CLASS__, 'invalidate' ) );
add_action( 'update_option', array( __CLASS__, 'clear_on_option_update' ) );
add_action( 'edited_terms', array( __CLASS__, 'invalidate_helper' ), 10, 2 );
add_action( 'clean_term_cache', array( __CLASS__, 'invalidate_helper' ), 10, 2 );
add_action( 'clean_object_term_cache', array( __CLASS__, 'invalidate_helper' ), 10, 2 );
add_action( 'user_register', array( __CLASS__, 'invalidate_author' ) );
add_action( 'delete_user', array( __CLASS__, 'invalidate_author' ) );
add_action( 'shutdown', array( __CLASS__, 'clear_queued' ) );
}
/**
* Setup context for static calls.
*/
public function init() {
self::$is_enabled = $this->is_enabled();
}
/**
* If cache is enabled.
*
* @since 3.2
*
* @return boolean
*/
public function is_enabled() {
/**
* Filter if XML sitemap transient cache is enabled.
*
* @param bool $unsigned Enable cache or not, defaults to true.
*/
return apply_filters( 'wpseo_enable_xml_sitemap_transient_caching', false );
}
/**
* Retrieve the sitemap page from cache.
*
* @since 3.2
*
* @param string $type Sitemap type.
* @param int $page Page number to retrieve.
*
* @return string|boolean
*/
public function get_sitemap( $type, $page ) {
$transient_key = WPSEO_Sitemaps_Cache_Validator::get_storage_key( $type, $page );
if ( false === $transient_key ) {
return false;
}
return get_transient( $transient_key );
}
/**
* Get the sitemap that is cached.
*
* @param string $type Sitemap type.
* @param int $page Page number to retrieve.
*
* @return null|WPSEO_Sitemap_Cache_Data Null on no cache found otherwise object containing sitemap and meta data.
*/
public function get_sitemap_data( $type, $page ) {
$sitemap = $this->get_sitemap( $type, $page );
if ( empty( $sitemap ) ) {
return null;
}
// Unserialize Cache Data object (is_serialized doesn't recognize classes).
if ( is_string( $sitemap ) && 0 === strpos( $sitemap, 'C:24:"WPSEO_Sitemap_Cache_Data"' ) ) {
$sitemap = unserialize( $sitemap );
}
// What we expect it to be if it is set.
if ( $sitemap instanceof WPSEO_Sitemap_Cache_Data_Interface ) {
return $sitemap;
}
return null;
}
/**
* Store the sitemap page from cache.
*
* @since 3.2
*
* @param string $type Sitemap type.
* @param int $page Page number to store.
* @param string $sitemap Sitemap body to store.
* @param bool $usable Is this a valid sitemap or a cache of an invalid sitemap.
*
* @return bool
*/
public function store_sitemap( $type, $page, $sitemap, $usable = true ) {
$transient_key = WPSEO_Sitemaps_Cache_Validator::get_storage_key( $type, $page );
if ( false === $transient_key ) {
return false;
}
$status = ( $usable ) ? WPSEO_Sitemap_Cache_Data::OK : WPSEO_Sitemap_Cache_Data::ERROR;
$sitemap_data = new WPSEO_Sitemap_Cache_Data();
$sitemap_data->set_sitemap( $sitemap );
$sitemap_data->set_status( $status );
return set_transient( $transient_key, $sitemap_data, DAY_IN_SECONDS );
}
/**
* Delete cache transients for index and specific type.
*
* Always deletes the main index sitemaps cache, as that's always invalidated by any other change.
*
* @since 1.5.4
* @since 3.2 Changed from function wpseo_invalidate_sitemap_cache() to method in this class.
*
* @param string $type Sitemap type to invalidate.
*
* @return void
*/
public static function invalidate( $type ) {
self::clear( array( $type ) );
}
/**
* Helper to invalidate in hooks where type is passed as second argument.
*
* @since 3.2
*
* @param int $unused Unused term ID value.
* @param string $type Taxonomy to invalidate.
*
* @return void
*/
public static function invalidate_helper( $unused, $type ) {
if (
WPSEO_Options::get( 'noindex-' . $type ) === false ||
WPSEO_Options::get( 'noindex-tax-' . $type ) === false
) {
self::invalidate( $type );
}
}
/**
* Invalidate sitemap cache for authors.
*
* @param int $user_id User ID.
*
* @return bool True if the sitemap was properly invalidated. False otherwise.
*/
public static function invalidate_author( $user_id ) {
$user = get_user_by( 'id', $user_id );
if ( $user === false ) {
return false;
}
if ( 'user_register' === current_action() ) {
update_user_meta( $user_id, '_yoast_wpseo_profile_updated', time() );
}
if ( empty( $user->roles ) || in_array( 'subscriber', $user->roles, true ) ) {
return false;
}
self::invalidate( 'author' );
return true;
}
/**
* Invalidate sitemap cache for the post type of a post.
*
* Don't invalidate for revisions.
*
* @since 1.5.4
* @since 3.2 Changed from function wpseo_invalidate_sitemap_cache_on_save_post() to method in this class.
*
* @param int $post_id Post ID to invalidate type for.
*
* @return void
*/
public static function invalidate_post( $post_id ) {
if ( wp_is_post_revision( $post_id ) ) {
return;
}
self::invalidate( get_post_type( $post_id ) );
}
/**
* Delete cache transients for given sitemaps types or all by default.
*
* @since 1.8.0
* @since 3.2 Moved from WPSEO_Utils to this class.
*
* @param array $types Set of sitemap types to delete cache transients for.
*
* @return void
*/
public static function clear( $types = array() ) {
if ( ! self::$is_enabled ) {
return;
}
// No types provided, clear all.
if ( empty( $types ) ) {
self::$clear_all = true;
return;
}
// Always invalidate the index sitemap as well.
if ( ! in_array( WPSEO_Sitemaps::SITEMAP_INDEX_TYPE, $types ) ) {
array_unshift( $types, WPSEO_Sitemaps::SITEMAP_INDEX_TYPE );
}
foreach ( $types as $type ) {
if ( ! in_array( $type, self::$clear_types ) ) {
self::$clear_types[] = $type;
}
}
}
/**
* Invalidate storage for cache types queued to clear.
*/
public static function clear_queued() {
if ( self::$clear_all ) {
WPSEO_Sitemaps_Cache_Validator::invalidate_storage();
self::$clear_all = false;
self::$clear_types = array();
return;
}
foreach ( self::$clear_types as $type ) {
WPSEO_Sitemaps_Cache_Validator::invalidate_storage( $type );
}
self::$clear_types = array();
}
/**
* Adds a hook that when given option is updated, the cache is cleared.
*
* @since 3.2
*
* @param string $option Option name.
* @param string $type Sitemap type.
*/
public static function register_clear_on_option_update( $option, $type = '' ) {
self::$cache_clear[ $option ] = $type;
}
/**
* Clears the transient cache when a given option is updated, if that option has been registered before.
*
* @since 3.2
*
* @param string $option The option name that's being updated.
*
* @return void
*/
public static function clear_on_option_update( $option ) {
if ( array_key_exists( $option, self::$cache_clear ) ) {
if ( empty( self::$cache_clear[ $option ] ) ) {
// Clear all caches.
self::clear();
}
else {
// Clear specific provided type(s).
$types = (array) self::$cache_clear[ $option ];
self::clear( $types );
}
}
}
}