687 lines
15 KiB
PHP
Executable File
687 lines
15 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* $Desc$
|
|
*
|
|
* @version $Id$
|
|
* @package opalestate
|
|
* @author Opal Team <info@wpopal.com >
|
|
* @copyright Copyright (C) 2019 wpopal.com. All Rights Reserved.
|
|
* @license GNU/GPL v2 or later http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* @website http://www.wpopal.com
|
|
* @support http://www.wpopal.com/support/forum.html
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly
|
|
}
|
|
class Opalestate_Cache {
|
|
|
|
/**
|
|
* Instance.
|
|
*
|
|
* @since 1.8.7
|
|
* @access private
|
|
* @var Opalestate_Cache
|
|
*/
|
|
static private $instance;
|
|
|
|
/**
|
|
* Flag to check if caching enabled or not.
|
|
*
|
|
* @since 2.0
|
|
* @access private
|
|
* @var
|
|
*/
|
|
private $is_cache;
|
|
|
|
/**
|
|
* Singleton pattern.
|
|
*
|
|
* @since 1.8.7
|
|
* @access private
|
|
* Opalestate_Cache constructor.
|
|
*/
|
|
private function __construct() {
|
|
}
|
|
|
|
|
|
/**
|
|
* Get instance.
|
|
*
|
|
* @since 1.8.7
|
|
* @access public
|
|
* @return static
|
|
*/
|
|
public static function get_instance() {
|
|
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof Opalestate_Cache ) ) {
|
|
self::$instance = new Opalestate_Cache();
|
|
}
|
|
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Setup hooks.
|
|
*
|
|
* @since 1.8.7
|
|
* @access public
|
|
*/
|
|
public function setup() {
|
|
// Currently enable cache only for backend.
|
|
self::$instance->is_cache = ( defined( 'GIVE_CACHE' ) ? GIVE_CACHE : opalestate_is_setting_enabled( opalestate_get_option( 'cache', 'enabled' ) ) ) && is_admin();
|
|
|
|
// weekly delete all expired cache.
|
|
Give_Cron::add_weekly_event( array( $this, 'delete_all_expired' ) );
|
|
|
|
add_action( 'save_post_opalestate_forms', array( $this, 'delete_form_related_cache' ) );
|
|
add_action( 'save_post_opalestate_payment', array( $this, 'delete_payment_related_cache' ) );
|
|
add_action( 'opalestate_deleted_opalestate-donors_cache', array( $this, 'delete_donor_related_cache' ), 10, 3 );
|
|
add_action( 'opalestate_deleted_opalestate-donations_cache', array( $this, 'delete_donations_related_cache' ), 10, 3 );
|
|
|
|
add_action( 'opalestate_save_settings_opalestate_settings', array( __CLASS__, 'flush_cache' ) );
|
|
|
|
add_action( 'wp', array( __CLASS__, 'prevent_caching' ) );
|
|
add_action( 'admin_notices', array( $this, '__notices' ) );
|
|
}
|
|
|
|
/**
|
|
* Prevent caching on certain pages
|
|
*
|
|
* @since 2.0.5
|
|
* @access public
|
|
* @credit WooCommerce
|
|
*/
|
|
public static function prevent_caching() {
|
|
if ( ! is_blog_installed() ) {
|
|
return;
|
|
}
|
|
|
|
$page_ids = array_filter( array(
|
|
opalestate_get_option( 'success_page' ),
|
|
opalestate_get_option( 'failure_page' ),
|
|
opalestate_get_option( 'history_page' ),
|
|
) );
|
|
|
|
if (
|
|
is_page( $page_ids )
|
|
|| is_singular( 'opalestate_forms' )
|
|
) {
|
|
self::set_nocache_constants();
|
|
nocache_headers();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set constants to prevent caching by some plugins.
|
|
*
|
|
* @since 2.0.5
|
|
* @access public
|
|
* @credit WooCommerce
|
|
*
|
|
* @param mixed $return Value to return. Previously hooked into a filter.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function set_nocache_constants( $return = true ) {
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Notices function.
|
|
*
|
|
* @since 2.0.5
|
|
* @access public
|
|
* @credit WooCommerce
|
|
*/
|
|
public function __notices() {
|
|
if ( ! function_exists( 'w3tc_pgcache_flush' ) || ! function_exists( 'w3_instance' ) ) {
|
|
return;
|
|
}
|
|
|
|
$config = w3_instance( 'W3_Config' );
|
|
$enabled = $config->get_integer( 'dbcache.enabled' );
|
|
$settings = array_map( 'trim', $config->get_array( 'dbcache.reject.sql' ) );
|
|
|
|
if ( $enabled && ! in_array( 'opalestate-pro', $settings, true ) ) {
|
|
?>
|
|
<div class="error">
|
|
<p><?php echo wp_kses_post( sprintf( esc_html__( 'In order for <strong>database caching</strong> to work with Give you must add %1$s to the "Ignored query stems" option in <a href="%2$s">W3 Total Cache settings</a>.', 'opalestate-pro' ), '<code>opalestate</code>', esc_url( admin_url( 'admin.php?page=w3tc_dbcache#dbcache_reject_sql' ) ) ) ); ?></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get cache key.
|
|
*
|
|
* @since 1.8.7
|
|
*
|
|
* @param string $action Cache key prefix.
|
|
* @param array $query_args (optional) Query array.
|
|
* @param bool $is_prefix
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function get_key( $action, $query_args = null, $is_prefix = true ) {
|
|
// Bailout.
|
|
if ( empty( $action ) ) {
|
|
return new WP_Error( 'opalestate_invalid_cache_key_action', esc_html__( 'Do not pass empty action to generate cache key.', 'opalestate-pro' ) );
|
|
}
|
|
|
|
// Set cache key.
|
|
$cache_key = $is_prefix ? "opalestate_cache_{$action}" : $action;
|
|
|
|
// Bailout.
|
|
if ( ! empty( $query_args ) ) {
|
|
$cache_key = "{$cache_key}_" . substr( md5( serialize( $query_args ) ), 0, 15 );
|
|
}
|
|
|
|
/**
|
|
* Filter the cache key name.
|
|
*
|
|
* @since 2.0
|
|
*/
|
|
return apply_filters( 'opalestate_get_cache_key', $cache_key, $action, $query_args );
|
|
}
|
|
|
|
/**
|
|
* Get cache.
|
|
*
|
|
* @since 1.8.7
|
|
*
|
|
* @param string $cache_key
|
|
* @param bool $custom_key
|
|
* @param mixed $query_args
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function get( $cache_key, $custom_key = false, $query_args = array() ) {
|
|
if ( ! self::is_valid_cache_key( $cache_key ) ) {
|
|
if( empty( $cache_key ) ) {
|
|
return new WP_Error( 'opalestate_empty_cache_key', esc_html__( 'Do not pass invalid empty cache key', 'opalestate-pro' ) );
|
|
}elseif ( ! $custom_key ) {
|
|
return new WP_Error( 'opalestate_invalid_cache_key', esc_html__( 'Cache key format should be opalestate_cache_*', 'opalestate-pro' ) );
|
|
}
|
|
|
|
$cache_key = self::get_key( $cache_key, $query_args );
|
|
}
|
|
|
|
$option = get_option( $cache_key );
|
|
|
|
// Backward compatibility (<1.8.7).
|
|
if ( ! is_array( $option ) || empty( $option ) || ! array_key_exists( 'expiration', $option ) ) {
|
|
return $option;
|
|
}
|
|
|
|
// Get current time.
|
|
$current_time = current_time( 'timestamp', 1 );
|
|
|
|
if ( empty( $option['expiration'] ) || ( $current_time < $option['expiration'] ) ) {
|
|
$option = $option['data'];
|
|
} else {
|
|
$option = false;
|
|
}
|
|
|
|
return $option;
|
|
}
|
|
|
|
/**
|
|
* Set cache.
|
|
*
|
|
* @since 1.8.7
|
|
*
|
|
* @param string $cache_key
|
|
* @param mixed $data
|
|
* @param int|null $expiration Timestamp should be in GMT format.
|
|
* @param bool $custom_key
|
|
* @param mixed $query_args
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function set( $cache_key, $data, $expiration = null, $custom_key = false, $query_args = array() ) {
|
|
if ( ! self::is_valid_cache_key( $cache_key ) ) {
|
|
if ( ! $custom_key ) {
|
|
return new WP_Error( 'opalestate_invalid_cache_key', esc_html__( 'Cache key format should be opalestate_cache_*', 'opalestate-pro' ) );
|
|
}
|
|
|
|
$cache_key = self::get_key( $cache_key, $query_args );
|
|
}
|
|
|
|
$option_value = array(
|
|
'data' => $data,
|
|
'expiration' => ! is_null( $expiration )
|
|
? ( $expiration + current_time( 'timestamp', 1 ) )
|
|
: null,
|
|
);
|
|
|
|
$result = update_option( $cache_key, $option_value, false );
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Delete cache.
|
|
*
|
|
* Note: only for internal use
|
|
*
|
|
* @since 1.8.7
|
|
*
|
|
* @param string|array $cache_keys
|
|
*
|
|
* @return bool|WP_Error
|
|
*/
|
|
public static function delete( $cache_keys ) {
|
|
$result = true;
|
|
$invalid_keys = array();
|
|
|
|
if ( ! empty( $cache_keys ) ) {
|
|
$cache_keys = is_array( $cache_keys ) ? $cache_keys : array( $cache_keys );
|
|
|
|
foreach ( $cache_keys as $cache_key ) {
|
|
if ( ! self::is_valid_cache_key( $cache_key ) ) {
|
|
$invalid_keys[] = $cache_key;
|
|
$result = false;
|
|
}
|
|
|
|
delete_option( $cache_key );
|
|
}
|
|
}
|
|
|
|
if ( ! $result ) {
|
|
$result = new WP_Error(
|
|
'opalestate_invalid_cache_key',
|
|
__( 'Cache key format should be opalestate_cache_*', 'opalestate-pro' ),
|
|
$invalid_keys
|
|
);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Delete all logging cache.
|
|
*
|
|
* Note: only for internal use
|
|
*
|
|
* @since 1.8.7
|
|
* @access public
|
|
* @global wpdb $wpdb
|
|
*
|
|
* @param bool $force If set to true then all cached values will be delete instead of only expired
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function delete_all_expired( $force = false ) {
|
|
global $wpdb;
|
|
$options = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT option_name, option_value
|
|
FROM {$wpdb->options}
|
|
Where option_name
|
|
LIKE '%%%s%%'",
|
|
'opalestate_cache'
|
|
),
|
|
ARRAY_A
|
|
);
|
|
|
|
// Bailout.
|
|
if ( empty( $options ) ) {
|
|
return false;
|
|
}
|
|
|
|
$current_time = current_time( 'timestamp', 1 );
|
|
|
|
// Delete log cache.
|
|
foreach ( $options as $option ) {
|
|
$option['option_value'] = maybe_unserialize( $option['option_value'] );
|
|
|
|
if (
|
|
(
|
|
! self::is_valid_cache_key( $option['option_name'] )
|
|
|| ! is_array( $option['option_value'] ) // Backward compatibility (<1.8.7).
|
|
|| ! array_key_exists( 'expiration', $option['option_value'] ) // Backward compatibility (<1.8.7).
|
|
|| empty( $option['option_value']['expiration'] )
|
|
|| ( $current_time < $option['option_value']['expiration'] )
|
|
)
|
|
&& ! $force
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
self::delete( $option['option_name'] );
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get list of options like.
|
|
*
|
|
* Note: only for internal use
|
|
*
|
|
* @since 1.8.7
|
|
* @access public
|
|
*
|
|
* @param string $option_name
|
|
* @param bool $fields
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function get_options_like( $option_name, $fields = false ) {
|
|
global $wpdb;
|
|
|
|
$field_names = $fields ? 'option_name, option_value' : 'option_name';
|
|
|
|
if ( $fields ) {
|
|
$options = $wpdb->get_results(
|
|
$wpdb->prepare(
|
|
"SELECT {$field_names }
|
|
FROM {$wpdb->options}
|
|
Where option_name
|
|
LIKE '%%%s%%'",
|
|
"opalestate_cache_{$option_name}"
|
|
),
|
|
ARRAY_A
|
|
);
|
|
} else {
|
|
$options = $wpdb->get_col(
|
|
$wpdb->prepare(
|
|
"SELECT *
|
|
FROM {$wpdb->options}
|
|
Where option_name
|
|
LIKE '%%%s%%'",
|
|
"opalestate_cache_{$option_name}"
|
|
),
|
|
1
|
|
);
|
|
}
|
|
|
|
if ( ! empty( $options ) && $fields ) {
|
|
foreach ( $options as $index => $option ) {
|
|
$option['option_value'] = maybe_unserialize( $option['option_value'] );
|
|
$options[ $index ] = $option;
|
|
}
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* Check cache key validity.
|
|
*
|
|
* @since 1.8.7
|
|
* @access public
|
|
*
|
|
* @param $cache_key
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_valid_cache_key( $cache_key ) {
|
|
$is_valid = ( false !== strpos( $cache_key, 'opalestate_cache_' ) );
|
|
|
|
|
|
/**
|
|
* Filter the flag which tell about cache key valid or not
|
|
*
|
|
* @since 2.0
|
|
*/
|
|
return apply_filters( 'opalestate_is_valid_cache_key', $is_valid, $cache_key );
|
|
}
|
|
|
|
|
|
/**
|
|
* Get cache from group
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*
|
|
* @param int $id
|
|
* @param string $group
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function get_group( $id, $group = '' ) {
|
|
$cached_data = null;
|
|
|
|
// Bailout.
|
|
if ( self::$instance->is_cache && ! empty( $id ) ) {
|
|
$group = self::$instance->filter_group_name( $group );
|
|
|
|
$cached_data = wp_cache_get( $id, $group );
|
|
$cached_data = false !== $cached_data ? $cached_data : null;
|
|
}
|
|
|
|
return $cached_data;
|
|
}
|
|
|
|
/**
|
|
* Cache small chunks inside group
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*
|
|
* @param int $id
|
|
* @param mixed $data
|
|
* @param string $group
|
|
* @param int $expire
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function set_group( $id, $data, $group = '', $expire = 0 ) {
|
|
$status = false;
|
|
|
|
// Bailout.
|
|
if ( ! self::$instance->is_cache || empty( $id ) ) {
|
|
return $status;
|
|
}
|
|
|
|
$group = self::$instance->filter_group_name( $group );
|
|
|
|
$status = wp_cache_set( $id, $data, $group, $expire );
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Cache small db query chunks inside group
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*
|
|
* @param int $id
|
|
* @param mixed $data
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function set_db_query( $id, $data ) {
|
|
$status = false;
|
|
|
|
// Bailout.
|
|
if ( ! self::$instance->is_cache || empty( $id ) ) {
|
|
return $status;
|
|
}
|
|
|
|
return self::set_group( $id, $data, 'opalestate-db-queries', 0 );
|
|
}
|
|
|
|
/**
|
|
* Get cache from group
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*
|
|
* @param string $id
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function get_db_query( $id ) {
|
|
return self::get_group( $id, 'opalestate-db-queries' );
|
|
}
|
|
|
|
/**
|
|
* Delete group cache
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*
|
|
* @param int|array $ids
|
|
* @param string $group
|
|
* @param int $expire
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function delete_group( $ids, $group = '', $expire = 0 ) {
|
|
$status = false;
|
|
|
|
// Bailout.
|
|
if ( ! self::$instance->is_cache || empty( $ids ) ) {
|
|
return $status;
|
|
}
|
|
|
|
$group_prefix = $group;
|
|
$group = self::$instance->filter_group_name( $group );
|
|
|
|
// Delete single or multiple cache items from cache.
|
|
if ( ! is_array( $ids ) ) {
|
|
$status = wp_cache_delete( $ids, $group );
|
|
self::$instance->get_incrementer( true );
|
|
|
|
/**
|
|
* Fire action when cache deleted for specific id.
|
|
*
|
|
* @since 2.0
|
|
*
|
|
* @param string $ids
|
|
* @param string $group
|
|
* @param int $expire
|
|
*/
|
|
do_action( "opalestate_deleted_{$group_prefix}_cache", $ids, $group, $expire, $status );
|
|
|
|
} else {
|
|
foreach ( $ids as $id ) {
|
|
$status = wp_cache_delete( $id, $group );
|
|
self::$instance->get_incrementer( true );
|
|
|
|
/**
|
|
* Fire action when cache deleted for specific id .
|
|
*
|
|
* @since 2.0
|
|
*
|
|
* @param string $ids
|
|
* @param string $group
|
|
* @param int $expire
|
|
*/
|
|
do_action( "opalestate_deleted_{$group_prefix}_cache", $id, $group, $expire, $status );
|
|
}
|
|
}
|
|
|
|
return $status;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get unique incrementer.
|
|
*
|
|
* @see https://core.trac.wordpress.org/ticket/4476
|
|
* @see https://www.tollmanz.com/invalidation-schemes/
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*
|
|
* @param bool $refresh
|
|
* @param string $incrementer_key
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_incrementer( $refresh = false, $incrementer_key = 'opalestate-cache-incrementer-db-queries' ) {
|
|
$incrementer_value = wp_cache_get( $incrementer_key );
|
|
|
|
if ( false === $incrementer_value || true === $refresh ) {
|
|
$incrementer_value = (string) microtime( true );
|
|
wp_cache_set( $incrementer_key, $incrementer_value );
|
|
}
|
|
|
|
return $incrementer_value;
|
|
}
|
|
|
|
|
|
/**
|
|
* Flush cache on cache setting enable/disable
|
|
* Note: only for internal use
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*
|
|
* @param bool $force Delete cache forcefully.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function flush_cache( $force = false ) {
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Filter the group name
|
|
*
|
|
* @since 2.0
|
|
* @access private
|
|
*
|
|
* @param $group
|
|
*
|
|
* @return mixed
|
|
*/
|
|
private function filter_group_name( $group ) {
|
|
/**
|
|
* Filter the group name
|
|
*
|
|
* @since 2.1.0
|
|
*/
|
|
$filtered_group = apply_filters( 'opalestate_cache_filter_group_name', '', $group );
|
|
|
|
if ( empty( $filtered_group ) ) {
|
|
|
|
switch ( $group ) {
|
|
case 'opalestate-db-queries':
|
|
$incrementer = self::$instance->get_incrementer();
|
|
break;
|
|
|
|
default:
|
|
$incrementer = self::$instance->get_incrementer( false, 'opalestate-cache-incrementer' );
|
|
|
|
}
|
|
|
|
$current_blog_id = get_current_blog_id();
|
|
$filtered_group = "{$group}_{$current_blog_id}_{$incrementer}";
|
|
}
|
|
|
|
return $filtered_group;
|
|
}
|
|
|
|
|
|
/**
|
|
* Disable cache.
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*/
|
|
public static function disable() {
|
|
self::get_instance()->is_cache = false;
|
|
}
|
|
|
|
/**
|
|
* Enable cache.
|
|
*
|
|
* @since 2.0
|
|
* @access public
|
|
*/
|
|
public static function enable() {
|
|
self::get_instance()->is_cache = true;
|
|
}
|
|
}
|
|
|
|
// Initialize
|
|
Opalestate_Cache::get_instance()->setup();
|