* WP Object Cache wrapper for LiteSpeed Cache.
* Provides a drop-in-compatible object cache implementation that proxies to
* LiteSpeed's persistent cache while keeping a local runtime cache.
* Implements the WordPress object cache for LiteSpeed Cache.
* @var WP_Object_Cache|null
protected static $_instance;
* @var \LiteSpeed\Object_Cache
private $_cache_404 = [];
private $cache_total = 0;
private $count_hit_incall = 0;
* Cache misses within call
private $count_miss_incall = 0;
protected $global_groups = [];
* Blog prefix for cache keys
* Initializes the object cache with LiteSpeed settings.
public function __construct() {
$this->_object_cache = \LiteSpeed\Object_Cache::cls();
$this->multisite = is_multisite();
$this->blog_prefix = $this->multisite ? get_current_blog_id() . ':' : '';
* Fix multiple instance using same oc issue
if ( ! defined( 'LSOC_PREFIX' ) ) {
define( 'LSOC_PREFIX', substr( md5( __FILE__ ), -5 ) );
* Makes private properties readable for backward compatibility.
* @param string $name Property to get.
* @return mixed Property.
public function __get( $name ) {
* Makes private properties settable for backward compatibility.
* @param string $name Property to set.
* @param mixed $value Property value.
* @return mixed Newly-set property.
public function __set( $name, $value ) {
* Makes private properties checkable for backward compatibility.
* @param string $name Property to check if set.
* @return bool Whether the property is set.
public function __isset( $name ) {
return isset( $this->$name );
* Makes private properties un-settable for backward compatibility.
* @param string $name Property to unset.
public function __unset( $name ) {
* Serves as a utility function to determine whether a key is valid.
* @param int|string $key Cache key to check for validity.
* @return bool Whether the key is valid.
protected function is_valid_key( $key ) {
if ( is_string( $key ) && '' !== trim( $key ) ) {
if ( ! function_exists( '__' ) ) {
wp_load_translations_early();
$message = is_string( $key )
? __( 'Cache key must not be an empty string.' )
/* translators: %s: The type of the given cache key. */
__( 'Cache key must be integer or non-empty string, %s given.' ),
* Generates a unique cache key based on group and prefix.
* @param int|string $key Cache key.
* @param string $group Optional. Cache group. Default 'default'.
* @return string The final cache key.
private function _key( $key, $group = 'default' ) {
$prefix = $this->_object_cache->is_global( $group ) ? '' : $this->blog_prefix;
return LSOC_PREFIX . $prefix . $group . '.' . $key;
* Returns cache statistics for debugging purposes.
* @return string Cache statistics.
public function debug() {
$this->count_hit_incall .
$this->count_miss_incall .
* Adds data to the cache if it doesn't already exist.
* @see WP_Object_Cache::set()
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool True on success, false if cache key and group already exist.
public function add( $key, $data, $group = 'default', $expire = 0 ) {
if ( wp_suspend_cache_addition() ) {
if ( ! $this->is_valid_key( $key ) ) {
$id = $this->_key( $key, $group );
if ( array_key_exists( $id, $this->_cache ) ) {
return $this->set( $key, $data, $group, (int) $expire );
* Adds multiple values to the cache in one call.
* @param array $data Array of keys and values to be added.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool[] Array of return values, grouped by key. Each value is either
* true on success, or false if cache key and group already exist.
public function add_multiple( array $data, $group = '', $expire = 0 ) {
foreach ( $data as $key => $value ) {
$values[ $key ] = $this->add( $key, $value, $group, $expire );
* Replaces the contents in the cache, if contents already exist.
* @see WP_Object_Cache::set()
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool True if contents were replaced, false if original value does not exist.
public function replace( $key, $data, $group = 'default', $expire = 0 ) {
if ( ! $this->is_valid_key( $key ) ) {
$id = $this->_key( $key, $group );
if ( ! array_key_exists( $id, $this->_cache ) ) {
return $this->set( $key, $data, $group, (int) $expire );
* Sets the data contents into the cache.
* The cache contents are grouped by the $group parameter followed by the
* $key. This allows for duplicate IDs in unique groups. Therefore, naming of
* the group should be used with care and should follow normal function
* naming guidelines outside of core WordPress usage.
* The $expire parameter is not used, because the cache will automatically
* expire for each time a page is accessed and PHP finishes. The method is
* more for cache plugins which use files.
* @since 5.4 Returns false if cache key is invalid.
* @param int|string $key What to call the contents in the cache.
* @param mixed $data The contents to store in the cache.
* @param string $group Optional. Where to group the cache contents. Default 'default'.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool True if contents were set, false if key is invalid.
public function set( $key, $data, $group = 'default', $expire = 0 ) {
if ( ! $this->is_valid_key( $key ) ) {
$id = $this->_key( $key, $group );
if ( is_object( $data ) ) {
$this->_cache[ $id ] = $data;
if ( array_key_exists( $id, $this->_cache_404 ) ) {
unset( $this->_cache_404[ $id ] );
if ( ! $this->_object_cache->is_non_persistent( $group ) ) {
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
$this->_object_cache->set( $id, serialize( array( 'data' => $data ) ), (int) $expire );
if ( $this->_object_cache->store_transients( $group ) ) {
$this->_transient_set( $key, $data, $group, (int) $expire );
* Sets multiple values to the cache in one call.
* @param array $data Array of key and value to be set.
* @param string $group Optional. Where the cache contents are grouped. Default empty.
* @param int $expire Optional. When to expire the cache contents, in seconds.
* Default 0 (no expiration).
* @return bool[] Array of return values, grouped by key. Each value is always true.
public function set_multiple( array $data, $group = '', $expire = 0 ) {
foreach ( $data as $key => $value ) {
$values[ $key ] = $this->set( $key, $value, $group, $expire );
* Retrieves the cache contents, if it exists.
* The contents will be first attempted to be retrieved by searching by the
* key in the cache group. If the cache is hit (success) then the contents
* On failure, the number of cache misses will be incremented.
* @param int|string $key The key under which the cache contents are stored.
* @param string $group Optional. Where the cache contents are grouped. Default 'default'.
* @param bool $force Optional. Unused. Whether to force an update of the local cache
* from the persistent cache. Default false.
* @param bool $found Optional. Whether the key was found in the cache (passed by reference).
* Disambiguates a return of false, a storable value. Default null.
* @return mixed|false The cache contents on success, false on failure to retrieve contents.
public function get( $key, $group = 'default', $force = false, &$found = null ) {
if ( ! $this->is_valid_key( $key ) ) {