Current File : /home/honehdyv/readbtooom.com/wp-content/plugins/autodescription/inc/classes/cache.class.php |
<?php
/**
* @package The_SEO_Framework\Classes\Facade\Cache
* @subpackage The_SEO_Framework\Cache
*/
namespace The_SEO_Framework;
\defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die;
/**
* The SEO Framework plugin
* Copyright (C) 2015 - 2023 Sybre Waaijer, CyberWire B.V. (https://cyberwire.nl/)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Class The_SEO_Framework\Cache
*
* Generates, stores and deletes common transients.
*
* @since 2.8.0
*/
class Cache extends Site_Options {
/**
* Initializes admin caching actions.
*
* @since 2.8.0
* @action init priority 1
* @see $this->init_admin_actions();
*/
public function init_admin_caching_actions() {
$this->init_post_cache_actions();
// Delete Sitemap transient on permalink structure change.
\add_action( 'load-options-permalink.php', [ $this, 'delete_sitemap_transient_permalink_updated' ], 20 );
\add_action( 'activated_plugin', [ $this, 'set_plugin_check_caches' ] );
}
/**
* Deletes Sitemap and Description transients on post publish/delete.
*
* @see WP Core wp_transition_post_status()
* @since 2.8.2
* @action init priority 1
* @see $this->init_admin_actions();
* @see $this->init_cron_actions();
*
* @return void Early if already called.
*/
public function init_post_cache_actions() {
if ( has_run( __METHOD__ ) ) return;
// Can-be cron actions.
\add_action( 'publish_post', [ $this, 'delete_post_cache' ] );
\add_action( 'publish_page', [ $this, 'delete_post_cache' ] );
// Other actions.
\add_action( 'deleted_post', [ $this, 'delete_post_cache' ] );
\add_action( 'deleted_page', [ $this, 'delete_post_cache' ] );
\add_action( 'post_updated', [ $this, 'delete_post_cache' ] );
\add_action( 'page_updated', [ $this, 'delete_post_cache' ] );
// Excluded IDs cache.
\add_action( 'save_post', [ $this, 'delete_excluded_ids_cache' ] );
\add_action( 'edit_attachment', [ $this, 'delete_excluded_ids_cache' ] );
}
/**
* Registers plugin cache checks on plugin activation.
*
* @since 3.1.0
*/
public function set_plugin_check_caches() {
$this->update_static_cache( 'check_seo_plugin_conflicts', 1 );
}
/**
* Flushes front-page and global transients that can be affected by options.
*
* @since 2.8.0
* @since 3.1.0 Added excluded post ids flush.
* @since 3.1.4 Now flushes object cache.
* @since 4.1.4 No longer flushes 'front', 'robots', or 'object' cache.
*/
public function delete_main_cache() {
$this->delete_cache( 'sitemap' );
$this->delete_cache( 'excluded_post_ids' );
}
/**
* Deletes transient on post save.
*
* @since 2.8.0
* @since 3.0.0 Process is halted when no valid $post_id is supplied.
* @since 4.1.3 Now flushes the sitemap cache (and instigates pinging thereof)
* even when TSF sitemaps are disabled.
* @since 4.1.4 No longer deletes object cache for post.
*
* @param int $post_id The Post ID that has been updated.
* @return bool True on success, false on failure.
*/
public function delete_post_cache( $post_id ) {
if ( ! $post_id ) return false;
$success = false;
// Don't flush sitemap on revision.
if ( ! \wp_is_post_revision( $post_id ) )
$success = $this->delete_cache( 'sitemap' );
return $success;
}
/**
* Deletes excluded post IDs cache.
*
* @since 3.0.0
*
* @return bool True on success, false on failure.
*/
public function delete_excluded_ids_cache() {
return $this->delete_cache( 'excluded_post_ids' );
}
/**
* Deletes excluded post IDs transient cache.
*
* @since 3.0.0
* @see $this->delete_excluded_ids_cache()
*
* @return bool True
*/
public function delete_excluded_post_ids_transient() {
$transient = $this->get_exclusion_transient_name();
$transient and \delete_transient( $transient );
return true;
}
/**
* Handles all kinds of cache for removal.
* Main cache deletion function handler.
*
* @since 2.8.0
* @since 2.9.3 $type = 'front' now also returns true.
* @since 3.1.0 1. Added action.
* 2. Removed support for $type 'detection'.
* @since 4.0.5 Removed all JSON-LD transient clear calls.
* @since 4.1.4 The following $type's are no longer supported: 'front', 'post', 'term', 'author', 'robots', 'object'.
*
* @param string $type The type
* @param int $id The post, page or TT ID. Defaults to $this->get_the_real_ID().
* @param array $args Additional arguments. They can overwrite $type and $id.
* @return bool true on success, false on failure.
*/
public function delete_cache( $type, $id = 0, $args = [] ) {
$args = array_merge(
[
'type' => $type,
// Don't use cache when fetching ID.
'id' => $id ?: $this->get_the_real_ID( false ),
'term' => '',
],
/**
* @since 2.8.0
* @NOTE Careful: Altering this might infinitely loop method delete_cache() if not done strictly.
* Don't blindly overwrite index key 'type'.
* @param array $args All caching arguments, with indexes 'type', 'id', and 'term'.
* @param string $type The cache type.
* @param int $id The post or term ID.
*/
(array) \apply_filters_ref_array(
'the_seo_framework_delete_cache_args',
[
$args,
$type,
$id,
]
)
);
$type = $args['type'];
$id = $args['id'];
$success = false;
switch ( $type ) :
case 'sitemap':
$success = $this->delete_sitemap_transient();
break;
case 'excluded_post_ids':
$success = $this->delete_excluded_post_ids_transient();
break;
default:
break;
endswitch;
/**
* @since 3.1.0
*
* @param string $type The flush type. Comes in handy when you use a catch-all function.
* @param int $id The post, page or TT ID. Defaults to tsf()->get_the_real_ID().
* @param array $args Additional arguments. They can overwrite $type and $id.
* @param bool $success Whether the action cleared.
*/
\do_action( "the_seo_framework_delete_cache_{$type}", $type, $id, $args, $success );
return $success;
}
/**
* Set the value of the transient.
*
* Prevents setting of transients when they're disabled.
*
* @since 2.6.0
* @uses $this->the_seo_framework_use_transients
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @param string $value Transient value. Expected to not be SQL-escaped.
* @param int $expiration Transient expiration date, optional. Expected to not be SQL-escaped.
*/
public function set_transient( $transient, $value, $expiration = 0 ) {
$this->the_seo_framework_use_transients and \set_transient( $transient, $value, $expiration );
}
/**
* Get the value of the transient.
*
* If the transient does not exists, does not have a value or has expired,
* or transients have been disabled through a constant, then the transient
* will be false.
*
* N.B. not all transient settings make use of this function, bypassing the constant check.
*
* @since 2.6.0
* @uses $this->the_seo_framework_use_transients
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return mixed|bool Value of the transient. False on failure or non existing transient.
*/
public function get_transient( $transient ) {
if ( $this->the_seo_framework_use_transients )
return \get_transient( $transient );
return false;
}
/**
* Returns the post ID exclusion transient name.
*
* @since 3.1.0
* @NOTE When changing the revision, we MUST delete the old revision key manually.
* Otherwise, the transient will stay indefinitely.
*
* @return string The current post exclusion transient name. Can be empty.
*/
public function get_exclusion_transient_name() {
$exclude_revision = '1'; // WARNING: SEE NOTE
return $this->add_cache_key_suffix( "tsf_exclude_{$exclude_revision}" );
}
/**
* Returns the sitemap transient name.
*
* @since 3.1.0
*
* @return string The current sitemap transient name. Can be empty.
*/
public function get_sitemap_transient_name() {
$sitemap_revision = '5';
return $this->get_option( 'cache_sitemap' ) ? $this->add_cache_key_suffix( "tsf_sitemap_{$sitemap_revision}" ) : '';
}
/**
* Generate transient key based on query vars or input variables.
*
* Warning: This can generate errors when used too early if no type has been set.
*
* @since 2.3.3
* @since 2.6.0 Refactored.
* @since 2.9.1 1. Added early singular type detection.
* 2. Moved generation into another method (v4.1.4: removed method).
* @since 3.1.1 The first parameter is now optional.
* @since 4.1.4 No longer generates a cache key when no `$type` is supplied.
* @TODO since we only support by type, it'd be best to rework this into something simple.
*
* @param int|string|bool $id The Taxonomy or Post ID.
* @param string $taxonomy The taxonomy name.
* @param string $type The Post Type.
* @return string The generated cache key by query or type.
*/
public function generate_cache_key( $id = 0, $taxonomy = '', $type = null ) {
return isset( $type ) ? $this->generate_cache_key_by_type( $id, $taxonomy, $type ) : '';
}
/**
* Generate transient key based on input.
*
* Use this method if you wish to evade the query usage.
*
* @since 2.9.1
* @since 2.9.2 Now returns false when an incorrect $type is supplied.
* @since 4.1.2 Now accepts $type 'sitemap_lock'.
* @since 4.1.4 Removed support for 'author', 'frontpage', 'page', 'post', 'attachment', 'singular', and 'term'.
* @see $this->generate_cache_key().
* @TODO since we only support a few, it'd be best to rework this into something simple.
*
* @param int|string|bool $page_id The Taxonomy or Post ID.
* @param string $taxonomy The term taxonomy.
* @param string $type The Post Type.
* @return string|bool String the generated cache key. Bool false on failure.
*/
public function generate_cache_key_by_type( $page_id, $taxonomy = '', $type = '' ) {
switch ( $type ) :
case 'ping':
return $this->add_cache_key_suffix( 'tsf_throttle_ping' );
case 'sitemap_lock':
return $this->add_cache_key_suffix( 'tsf_sitemap_lock' );
default:
$this->_doing_it_wrong( __METHOD__, 'Third parameter must be a known type.', '2.6.5' );
return $this->add_cache_key_suffix( \esc_sql( "{$type}_{$page_id}_{$taxonomy}" ) );
endswitch;
}
/**
* Adds cache key suffix based on blog id and locale.
*
* @since 2.7.0
* @since 2.8.0 1. $locale is now static.
* 2. $key may now be empty.
* @since 4.0.0 Removed caching, so to support translation plugin loops.
* @global string $blog_id
*
* @param string $key The cache key.
* @return string
*/
protected function add_cache_key_suffix( $key = '' ) {
$locale = strtolower( \get_locale() );
return "{$key}_{$GLOBALS['blog_id']}_{$locale}";
}
/**
* Checks whether the permalink structure is updated.
*
* @since 2.3.0
* @since 2.7.0 Added admin referer check.
* @securitycheck 3.0.0 OK.
*
* @return bool Whether if sitemap transient is deleted.
*/
public function delete_sitemap_transient_permalink_updated() {
if ( isset( $_POST['permalink_structure'] ) || isset( $_POST['category_base'] ) ) {
if ( \check_admin_referer( 'update-permalink' ) )
return $this->delete_cache( 'sitemap' );
}
return false;
}
/**
* Delete transient for sitemap on requests.
* Also ping search engines.
*
* Can only run once per request.
*
* @since 2.2.9
* @since 2.8.0 Now listens to option 'cache_sitemap' before deleting transient.
* @since 2.8.2 Added cache to prevent duplicated flushes.
* @since 4.1.1 Now fires an action.
*
* @return bool True on success, false on failure.
*/
public function delete_sitemap_transient() {
if ( has_run( __METHOD__ ) ) return false;
$transient = $this->get_sitemap_transient_name();
$transient and \delete_transient( $transient );
$ping_use_cron = $this->get_option( 'ping_use_cron' );
$ping_use_cron_prerender = $this->get_option( 'ping_use_cron_prerender' );
/**
* @since 4.1.1
* @since 4.1.2 Added index `ping_use_cron_prerender` to the first parameter.
* @param array $params Any useful environment parameters.
*/
\do_action(
'the_seo_framework_sitemap_transient_cleared',
[
'ping_use_cron' => $ping_use_cron,
'ping_use_cron_prerender' => $ping_use_cron_prerender, // TODO migrate this so it can run regardless of pinging?
]
);
if ( $ping_use_cron ) {
// This name is wrong. It's not exclusively used for pinging.
\The_SEO_Framework\Bridges\Ping::engage_pinging_cron();
} else {
\The_SEO_Framework\Bridges\Ping::ping_search_engines();
}
return true;
}
/**
* Builds and returns the excluded post IDs transient.
* The transients are autoloaded, as no expiration is set.
*
* Memoizes the database request.
*
* @since 3.0.0
* @since 3.1.0 Now no longer crashes on database errors.
* @since 4.1.4 1. Now tests against post type exclusions.
* 2. Now considers headlessness. This method runs only on the front-end.
*
* @return array : { 'archive', 'search' }
*/
public function get_excluded_ids_from_cache() {
if ( $this->is_headless['meta'] )
return [
'archive' => '',
'search' => '',
];
$cache = memo() ?? memo( $this->get_transient( $this->get_exclusion_transient_name() ) );
if ( false !== $cache ) return $cache;
global $wpdb;
$supported_post_types = $this->get_supported_post_types();
$public_post_types = $this->get_public_post_types();
$join = '';
$where = '';
if ( $supported_post_types !== $public_post_types ) {
// Post types can be registered arbitrarily through other plugins, even manually by non-super-admins. Prepare!
$post_type__in = "'" . implode( "','", array_map( 'esc_sql', $supported_post_types ) ) . "'";
// This is as fast as I could make it. Yes, it uses IN, but only on a (tiny) subset of data.
$join = "LEFT JOIN {$wpdb->posts} ON {$wpdb->postmeta}.post_id = {$wpdb->posts}.ID";
$where = "AND {$wpdb->posts}.post_type IN ($post_type__in)";
}
// Two separated equals queries are faster than a single IN with 'meta_key'.
// phpcs:disable, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We prepared our whole lives.
$cache = [
'archive' => $wpdb->get_results(
"SELECT post_id, meta_value FROM $wpdb->postmeta $join WHERE meta_key = 'exclude_from_archive' $where"
),
'search' => $wpdb->get_results(
"SELECT post_id, meta_value FROM $wpdb->postmeta $join WHERE meta_key = 'exclude_local_search' $where"
),
];
// phpcs:enable, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
foreach ( [ 'archive', 'search' ] as $type ) {
array_walk(
$cache[ $type ],
static function( &$v ) {
if ( isset( $v->meta_value, $v->post_id ) && $v->meta_value ) {
$v = (int) $v->post_id;
} else {
$v = false;
}
}
);
$cache[ $type ] = array_filter( $cache[ $type ] );
}
$this->set_transient( $this->get_exclusion_transient_name(), $cache, 0 );
return memo( $cache );
}
}