# thinkrank/1.0.0/includes/core/class-query-cache.php

ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console &amp; Local SEO, version 1.0.0. 211 lines.

- Page: https://pluginprobe.com/plugins/thinkrank/1.0.0/code/includes/core/class-query-cache.php
- Raw: https://pluginprobe.com/plugins/thinkrank/1.0.0/raw/includes/core/class-query-cache.php
- Modified: 2025-08-10T07:57:44+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/thinkrank/1.0.0/code/includes/core/class-query-cache.php#L10-L20`.

````php
<?php
/**
 * Query Cache Class
 *
 * Simple query result caching to reduce database load.
 * Follows existing caching patterns in the codebase.
 *
 * Usage Example:
 * ```php
 * use ThinkRank\Core\Query_Cache;
 *
 * $cache_key = Query_Cache::generate_key('settings', ['context_type' => 'post', 'context_id' => 123]);
 * $settings = Query_Cache::get_or_execute($cache_key, function() use ($wpdb) {
 *     return $wpdb->get_results("SELECT * FROM wp_thinkrank_seo_settings WHERE context_type = 'post'");
 * }, 600); // Cache for 10 minutes
 * ```
 *
 * @package ThinkRank
 * @subpackage Core
 * @since 1.0.0
 */

declare(strict_types=1);

namespace ThinkRank\Core;

/**
 * Query Cache Class
 *
 * @since 1.0.0
 */
class Query_Cache {

    /**
     * Memory cache for current request
     *
     * @since 1.0.0
     * @var array
     */
    private static array $memory_cache = [];

    /**
     * Cache group for WordPress object cache
     *
     * @since 1.0.0
     * @var string
     */
    private const CACHE_GROUP = 'thinkrank_queries';

    /**
     * Default cache duration in seconds
     *
     * @since 1.0.0
     * @var int
     */
    private const DEFAULT_DURATION = 300; // 5 minutes

    /**
     * Option name for cache group version
     *
     * @since 1.0.0
     * @var string
     */
    private const VERSION_OPTION = 'thinkrank_query_cache_version';

    /**
     * Get current cache group version
     *
     * @since 1.0.0
     * @return int Version number >= 1
     */
    private static function get_group_version(): int {
        $version = (int) get_option(self::VERSION_OPTION, 1);
        return $version > 0 ? $version : 1;
    }

    /**
     * Bump cache group version to invalidate all keys
     *
     * @since 1.0.0
     * @return bool Always true
     */
    private static function bump_group_version(): bool {
        $new = self::get_group_version() + 1;
        // Ensure option exists and does not autoload
        $existing = get_option(self::VERSION_OPTION, null);
        if ($existing === null) {
            add_option(self::VERSION_OPTION, $new, '', 'no');
        } else {
            update_option(self::VERSION_OPTION, $new, false);
        }
        return true;
    }


    /**
     * Apply current group version to a cache key
     *
     * @since 1.0.0
     * @param string $key Base key
     * @return string Versioned key
     */
    private static function apply_version(string $key): string {
        $v = self::get_group_version();
        return 'v' . $v . ':' . $key;
    }


    /**
     * Get cached result or execute callback
     *
     * @since 1.0.0
     *
     * @param string $key Cache key
     * @param callable $callback Function to execute if cache miss
     * @param int $duration Cache duration in seconds
     * @return mixed Query result
     */
    public static function get_or_execute(string $key, callable $callback, int $duration = self::DEFAULT_DURATION) {
        $versioned_key = self::apply_version($key);

        // Check memory cache first (fastest)
        if (isset(self::$memory_cache[$versioned_key])) {
            return self::$memory_cache[$versioned_key];
        }

        // Check persistent cache
        $cached = wp_cache_get($versioned_key, self::CACHE_GROUP);
        if ($cached !== false) {
            // Store in memory cache for this request
            self::$memory_cache[$versioned_key] = $cached;
            return $cached;
        }

        // Execute callback and cache result
        $result = call_user_func($callback);

        // Store in both caches
        self::$memory_cache[$versioned_key] = $result;
        wp_cache_set($versioned_key, $result, self::CACHE_GROUP, $duration);

        return $result;
    }

    /**
     * Generate cache key from query and parameters
     *
     * @since 1.0.0
     *
     * @param string $query_type Query type identifier
     * @param array $params Query parameters
     * @return string Cache key
     */
    public static function generate_key(string $query_type, array $params = []): string {
        // Use JSON encoding for stable cross-runtime key generation
        return 'query_' . $query_type . '_' . md5(wp_json_encode($params));
    }

    /**
     * Clear cache for specific key or pattern
     *
     * @since 1.0.0
     *
     * @param string $key_or_pattern Cache key or pattern
     * @return bool Success
     */
    public static function clear(string $key_or_pattern): bool {
        $versioned_key = self::apply_version($key_or_pattern);

        // Clear from memory cache
        if (isset(self::$memory_cache[$versioned_key])) {
            unset(self::$memory_cache[$versioned_key]);
        }

        // Clear from persistent cache
        return wp_cache_delete($versioned_key, self::CACHE_GROUP);
    }

    /**
     * Clear all query cache
     *
     * @since 1.0.0
     *
     * @return bool Success
     */
    public static function clear_all(): bool {
        // Clear memory cache
        self::$memory_cache = [];

        // Bump version to invalidate all keys logically
        return self::bump_group_version();
    }

    /**
     * Get cache statistics
     *
     * @since 1.0.0
     *
     * @return array Cache statistics
     */
    public static function get_stats(): array {
        return [
            'memory_cache_entries' => count(self::$memory_cache),
            'memory_usage_bytes' => strlen(serialize(self::$memory_cache)),
            'cache_group' => self::CACHE_GROUP,
            'group_version' => self::get_group_version(),
            'default_duration' => self::DEFAULT_DURATION
        ];
    }
}

````
