/home/arranoyd/energyclinic/wp-content/plugins/docket-cache/includes/src/PostCache.php
<?php
/**
 * Docket Cache.
 *
 * @author  Nawawi Jamili
 * @license MIT
 *
 * @see    https://github.com/nawawi/docket-cache
 */

namespace Nawawi\DocketCache;

\defined('ABSPATH') || exit;

#[AllowDynamicProperties]
final class PostCache
{
    public $prefix = 'docketcache-post';
    public $group_prefix;
    public $cache_incr = 0;
    public $cache_group = '';
    public $cache_key = '';
    public $all_post_ids = false;
    public $cached_post_ids = [];
    public $cached_posts = [];
    public $found_posts = false;
    public $cache_func = 'wp_cache_add';
    public $cache_func_expiry = 86400; // 1d
    public $allow_posttype = [];
    public $blacklist_posttype = [];
    public $allow_posttype_all = false;

    public function __construct()
    {
        $this->group_prefix = $this->prefix.'-';
        $this->allow_posttype = [
            'post',
            'page',
            'attachment',
            'revision',
            'nav_menu_item',
            'custom_css',
            'customize_changeset',
            'oembed_cache',
            'user_request',
            'wp_block',
            'wp_template',
            'wp_template_part',
            'wp_global_styles',
            'wp_navigation',
        ];

        $this->blacklist_posttype = ['scheduled-action'];
    }

    public function register()
    {
        // already in core.
        // https://github.com/WordPress/wordpress-develop/commit/7f7d616d822b79c952cbd6a3046a6f6a8aa5a35e
        if (isset($GLOBALS['wp_version']) && version_compare($GLOBALS['wp_version'], '6.1', '<')) {
            $this->allow_posttype_all = nwdcx_construe('ADVCPOST_POSTTYPE_ALL');
            if (!$this->allow_posttype_all) {
                $types = nwdcx_constval('ADVCPOST_POSTTYPE');

                if (\is_string($types) && 'all' === $types || \in_array($types, $this->allow_posttype)) {
                    $this->allow_posttype = $types;
                } elseif (!empty($types) && \is_array($types)) {
                    $this->allow_posttype = array_merge($this->allow_posttype, $types);
                }
            }

            $this->setup_for_blog();

            add_action('switch_blog', [$this, 'setup_for_blog'], 10, 2);
            add_filter('posts_request', [&$this, 'posts_request'], 10, 2);
            add_filter('posts_results', [&$this, 'posts_results'], 10, 2);
            add_filter('post_limits_request', [&$this, 'post_limits_request'], 999, 2);
            add_filter('found_posts_query', [&$this, 'found_posts_query'], 10, 2);
            add_filter('found_posts', [&$this, 'found_posts'], 10, 2);

            add_action('clean_term_cache', [$this, 'invalidate_cache']);
            add_action('clean_post_cache', [$this, 'invalidate_cache']);

            add_action('added_post_meta', [$this, 'invalidate_cache']);
            add_action('updated_post_meta', [$this, 'invalidate_cache']);
            add_action('deleted_post_meta', [$this, 'invalidate_cache']);
        }
    }

    public function setup_for_blog($new_blog_id = false, $previous_blog_id = false)
    {
        if ($new_blog_id && $new_blog_id === $previous_blog_id) {
            return;
        }

        $this->cache_incr = wp_cache_get('cache_incr', $this->prefix);
        if (!is_numeric($this->cache_incr)) {
            $now = time();
            wp_cache_set('cache_incr', $now, $this->prefix);
            $this->cache_incr = $now;
        }
        $this->cache_group = $this->group_prefix.$this->cache_incr;
    }

    public function invalidate_cache()
    {
        if (is_admin() && isset($_POST['wp-preview']) && 'dopreview' === $_POST['wp-preview']) {
            return;
        }

        if (\defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }

        $this->cache_incr = wp_cache_incr('cache_incr', 1, $this->prefix);

        if (10 < \strlen($this->cache_incr)) {
            wp_cache_set('cache_incr', 0, $this->prefix);
            $this->cache_incr = 0;
        }
        $this->cache_group = $this->group_prefix.$this->cache_incr;
    }

    private function allow_post_type($post_type)
    {
        if ($this->allow_posttype_all && !\in_array($post_type, $this->blacklist_posttype)) {
            return true;
        }

        $this->allow_posttype = apply_filters('docketcache/filter/postcache/posttype', $this->allow_posttype);
        if (\is_string($this->allow_posttype) && ('all' === $this->allow_posttype || $post_type === $this->allow_posttype)) {
            return true;
        }

        if (\in_array($post_type, $this->allow_posttype) || \in_array('all', $this->allow_posttype)) {
            return true;
        }

        return false;
    }

    public function posts_request($sql, $query)
    {
        if (!nwdcx_wpdb($wpdb)) {
            return $sql;
        }

        $post_type = $query->get('post_type');
        if (!$this->allow_post_type($post_type)) {
            return $sql;
        }

        $this->cache_key = 'query-'.$post_type.'-'.md5($sql);
        $this->all_post_ids = wp_cache_get($this->cache_key, $this->cache_group);

        if ('NA' !== $this->found_posts) {
            $cache_key = $this->cache_key.'-found';
            $this->found_posts = wp_cache_get($cache_key, $this->cache_group);
        }

        if ($this->all_post_ids xor $this->found_posts) {
            $this->cache_func = 'wp_cache_set';
        } else {
            $this->cache_func = 'wp_cache_add';
        }

        $this->cached_post_ids = [];
        $this->cached_posts = [];

        if ($this->found_posts && \is_array($this->all_post_ids)) {
            if (\function_exists('wp_cache_get_multi')) {
                $this->cached_posts = wp_cache_get_multi(['posts' => $this->all_post_ids]);
            } else {
                $this->cached_posts = [];
                foreach ($this->all_post_ids as $key) {
                    $this->cached_posts[$key] = wp_cache_get($key, 'posts');
                }
            }

            // array_filter = remove "empty" array
            $this->cached_posts = array_filter($this->cached_posts);

            foreach ($this->cached_posts as $post) {
                if (!empty($post)) {
                    $this->cached_post_ids[] = $post->ID;
                }
            }
            $uncached_post_ids = array_diff($this->all_post_ids, $this->cached_post_ids);

            if ($uncached_post_ids) {
                return "SELECT * FROM `{$wpdb->posts}` WHERE ID IN(".implode(',', array_map('absint', $uncached_post_ids)).')';
            }

            return '';
        }

        return $sql;
    }

    public function posts_results($posts, $query)
    {
        if (!$this->allow_post_type($query->get('post_type'))) {
            return $posts;
        }

        if ($this->found_posts && \is_array($this->all_post_ids)) {
            $collated_posts = [];
            foreach ($this->cached_posts as $post) {
                $posts[] = $post;
            }

            foreach ($posts as $post) {
                $loc = array_search($post->ID, $this->all_post_ids);
                if (is_numeric($loc) && -1 < $loc) {
                    $collated_posts[$loc] = $post;
                }
            }
            ksort($collated_posts);

            return array_map('get_post', array_values($collated_posts));
        }

        $post_ids = [];
        foreach ((array) $posts as $post) {
            $post_ids[] = $post->ID;
        }

        if (!$post_ids) {
            return [];
        }

        \call_user_func($this->cache_func, $this->cache_key, $post_ids, $this->cache_group, $this->cache_func_expiry);

        return array_map('get_post', $posts);
    }

    public function post_limits_request($limits, $query)
    {
        if (!$this->allow_post_type($query->get('post_type'))) {
            return $limits;
        }

        if (empty($limits) || (isset($query->query_vars['no_found_rows']) && $query->query_vars['no_found_rows'])) {
            $this->found_posts = 'NA';
        } else {
            $this->found_posts = false;
        }

        return $limits;
    }

    public function found_posts_query($sql, $query)
    {
        if (!$this->allow_post_type($query->get('post_type'))) {
            return $sql;
        }

        if ($this->found_posts && \is_array($this->all_post_ids)) {
            return '';
        }

        return $sql;
    }

    public function found_posts($found_posts, $query)
    {
        if (!$this->allow_post_type($query->get('post_type'))) {
            return $found_posts;
        }

        if ($this->found_posts && \is_array($this->all_post_ids)) {
            return (int) $this->found_posts;
        }

        $cache_key = $this->cache_key.'-found';
        \call_user_func($this->cache_func, $cache_key, (int) $found_posts, $this->cache_group, $this->cache_func_expiry);

        return $found_posts;
    }
}