HEX
Server: nginx/1.26.1
System: Linux main-vm 5.15.0-153-generic #163-Ubuntu SMP Thu Aug 7 16:37:18 UTC 2025 x86_64
User: root (0)
PHP: 8.2.19
Disabled: NONE
Upload Files
File: /var/www/bellecouture/wp-content/plugins/lastudio/includes/class-lastudio-cache-wp-query.php
<?php
/**
 * Fired during plugin activation.
 *
 * This class supports
 * ElasticPress
 * Pods - If active, Cache WP_Query will utilize Pods caches
 * Pods Alternative Cache - through Pods support, you can cache your query results to the filesystem which is handy for those hosting situations with small (or no) object cache setups
 *
 * @since      1.0.0
 * @package    LaStudio
 * @subpackage LaStudio/includes
 * @author     Duy Pham <[email protected]>
 */
class LaStudio_Cache_WP_Query {

    /**
     * @var array Allowed post types to cache
     */
    private $post_types = array();

    /**
     * @var array Current query
     */
    private $query_vars = array();

    /**
     * @var null|string Cache key
     */
    private $cache_key = null;

    /**
     * @var array|null Cached posts
     */
    private $cached_posts = null;

    /**
     * @var int|null Found posts
     */
    private $found_posts = null;

    /**
     * @var int|null Max num pages
     */
    private $max_num_pages = null;

    /**
     * Placeholder method
     */
    private function __construct() {
        // Nope
    }

    /**
     * Hook into filters
     */
    public function setup() {

        // Get supported post types
        $this->get_supported_post_types();

        // Skip EP integration if we have cache
        add_filter( 'ep_skip_query_integration', array( $this, 'filter_ep_skip_query_integration' ), 10, 2 );

        // Reset data
        add_action( 'pre_get_posts', array( $this, 'action_pre_get_posts' ), 4 );

        // Make sure we return nothing for MySQL posts query
        add_filter( 'posts_request', array( $this, 'filter_posts_request' ), 9, 2 );

        // Nukes the FOUND_ROWS() database query
        add_filter( 'found_posts_query', array( $this, 'filter_found_posts_query' ), 6, 2 );

        // Search and filter in EP_Posts to WP_Query
        add_filter( 'the_posts', array( $this, 'filter_the_posts' ), 11, 2 );

        // Properly restore blog if necessary
        add_action( 'loop_end', array( $this, 'action_loop_end' ), 11, 1 );

        // Properly switch to blog if necessary
        add_action( 'the_post', array( $this, 'action_the_post' ), 11, 1 );

        // Hook into ElasticPress search integration
        add_action( 'ep_wp_query_search', array( $this, 'ep_wp_query_search' ), 10, 3 );

        // Handle publish transitions
        add_action( 'transition_post_status', array( $this, 'transition_post_status' ), 10, 3 );

        // Handle post saves
        add_action( 'save_post', array( $this, 'reset_cache_key_salt' ), 10, 2 );

    }

    /**
     * Get post types that support Cache WP_Query
     */
    public function get_supported_post_types() {

        $post_types = get_post_types( array(), 'names' );

        $supports = array();

        foreach ( $post_types as $post_type ) {
            if ( post_type_supports( $post_type, 'cache_wp_query' ) ) {
                $supports[] = $post_type;
            }
        }
        $supports[] = 'post';
        $supports[] = 'product';
        $supports[] = 'la_team_member';
        $supports[] = 'la_portfolio';
        $supports = array_unique($supports);
        $this->post_types = apply_filters('lastudio/cache_wp_query/supports', $supports);

    }

    /**
     * @param boolean   $skip
     * @param \WP_Query $query
     */
    public function filter_ep_skip_query_integration( $skip, $query ) {

        if ( ! $skip && false !== apply_filters( 'cache_wp_query_elasticpress', true ) && $query ) {
            $cache_key = $this->get_cache_key();

            if ( ! empty( $cache_key ) ) {
                $cached_posts = $this->get_posts();

                if ( ! empty( $cached_posts ) ) {
                    $skip = true;
                }
            }
        }

        return $skip;

    }

    /**
     * Disables cache_results, adds header.
     *
     * @param \WP_Query $query
     */
    public function action_pre_get_posts( $query ) {

        $this->setup_query( $query );

    }

    /**
     * Switch to the correct site if the post site id is different than the actual one
     *
     * @param array $post
     *
     * @since 0.9
     */
    public function action_the_post( $post ) {

        $cache_key = $this->get_cache_key();

        if ( ! empty( $cache_key ) ) {
            if ( is_multisite() && ! empty( $post->site_id ) && get_current_blog_id() != $post->site_id ) {
                restore_current_blog();

                switch_to_blog( $post->site_id );

                remove_action( 'the_post', array( $this, 'action_the_post' ), 11 );
                setup_postdata( $post );
                add_action( 'the_post', array( $this, 'action_the_post' ), 11, 1 );
            }
        }

    }

    /**
     * Make sure the correct blog is restored
     */
    public function action_loop_end( $query ) {

        $cache_key = $this->get_cache_key();

        if ( ! empty( $cache_key ) ) {
            $this->reset();

            if ( is_multisite() && ! empty( $GLOBALS['switched'] ) ) {
                restore_current_blog();
            }
        }

    }

    /**
     * Filter the posts array to contain cached search results.
     *
     * @param array     $posts
     * @param \WP_Query &$query
     *
     * @return array
     */
    public function filter_the_posts( $posts, $query ) {

        // Can be cached
        $cache_key = $this->get_cache_key();

        if ( ! empty( $cache_key ) ) {
            if ( ! empty( $posts ) ) {
                $this->set_posts( $posts, $query );
            } else {
                $cached_posts = $this->get_posts();

                if ( ! empty( $cached_posts ) ) {
                    $posts = $cached_posts;

                    $query->found_posts   = $this->found_posts;
                    $query->max_num_pages = $this->max_num_pages;
                }
            }
        }

        return $posts;

    }

    /**
     * Remove the found_rows from the SQL Query
     *
     * @param string $sql
     * @param object $query
     *
     * @since 0.9
     * @return string
     */
    public function filter_found_posts_query( $sql, $query ) {

        // Can be cached
        $cache_key = $this->get_cache_key();

        if ( ! empty( $cache_key ) ) {
            $cached_posts = $this->get_posts();

            if ( ! empty( $cached_posts ) ) {
                $sql = '';
            }
        }

        return $sql;

    }

    /**
     * Filter query string used for get_posts(). Search for posts and save for later.
     * Return a query that will return nothing.
     *
     * @param string $request
     * @param object $query
     *
     * @return string
     */
    public function filter_posts_request( $request, $query ) {

        // Can be cached
        $cache_key = $this->get_cache_key();

        if ( ! empty( $cache_key ) ) {
            $cached_posts = $this->get_posts();

            if ( ! empty( $cached_posts ) ) {
                /**
                 * @var \wpdb $wpdb
                 */
                global $wpdb;

                $request = "SELECT * FROM $wpdb->posts WHERE 1=0";
            }
        }

        return $request;

    }

    /**
     * Handle caching ElasticPress posts
     *
     * @param array     $new_posts
     * @param array     $search
     * @param \WP_Query $query
     */
    public function ep_wp_query_search( $new_posts, $search, $query ) {

        // Can be cached
        $cache_key = $this->get_cache_key();

        // Cache ElasticPress posts
        if ( ! empty( $cache_key ) ) {
            $this->set_posts( $new_posts, $query );
        }

    }

    /**
     * Clear caches on post publish
     *
     * @param string  $old_status
     * @param string  $new_status
     * @param WP_Post $post
     */
    public function transition_post_status( $old_status, $new_status, $post ) {

        static $flushed;

        if ( ! empty( $flushed ) ) {
            return;
        }

        if ( $post && in_array( $post->post_type, $this->post_types ) && 'publish' === $new_status && $old_status !== $new_status ) {
            $this->reset_cache_key_salt( $post->ID, $post );

            // Flush Pods Caches
            if ( function_exists( 'pods_api' ) ) {
                pods_api()->cache_flush_pods();
            }

            $flushed = true;
        }

    }

    /**
     * Get posts from cache
     *
     * @return bool|null|array
     */
    public function get_posts() {

        $posts = null;

        // Can be cached
        $cache_key = $this->get_cache_key();

        if ( ! empty( $cache_key ) && empty( $_REQUEST['bypass_cache_wp_query'] ) ) {
            $posts = $this->cached_posts;

            if ( null === $posts ) {
                $posts = $this->cache_get( $cache_key, 'cache-wp-query' );

                if ( is_array( $posts ) && ! empty( $posts ) ) {
                    $posts = array_map( 'get_post', $posts );
                }

                if ( ! is_array( $posts ) || empty( $posts ) ) {
                    $posts = array();

                    $this->cached_posts = null;
                } else {
                    $this->cached_posts = $posts;
                }

                if ( ! empty( $posts ) ) {
                    $this->get_meta();
                }
            }
        }

        return $posts;

    }

    /**
     * Set posts to cache
     *
     * @param array     $posts
     * @param \WP_Query $query
     */
    public function set_posts( $posts, $query ) {

        // Can be cached
        $cache_key = $this->get_cache_key();

        if ( ! empty( $cache_key ) ) {
            if ( ! empty( $posts ) ) {
                if ( ! is_array( $posts ) ) {
                    $posts = array( $posts );
                }

                $posts_to_cache = wp_list_pluck( $posts, 'ID' );

                if ( ! empty( $posts_to_cache ) ) {
                    $this->cache_set( $cache_key, $posts_to_cache, 'cache-wp-query', 30 * MINUTE_IN_SECONDS );

                    $this->cached_posts = $posts;
                } else {
                    $posts = array();
                }
            }

            if ( empty( $posts ) ) {
                $this->cache_clear( $cache_key, 'cache-wp-query' );

                $this->cached_posts = array();
            }

            $this->set_meta( $query );
        }

    }

    /**
     * Get meta from cache
     *
     * @return bool|null|array
     */
    public function get_meta() {

        $meta = null;

        // Can be cached
        $cache_key = $this->get_cache_key();

        if ( empty( $this->found_posts ) && empty( $this->max_num_pages ) && ! empty( $cache_key ) && empty( $_REQUEST['bypass_cache_wp_query'] ) ) {
            $posts = $this->cached_posts;

            if ( ! empty( $posts ) ) {
                $meta = $this->cache_get( $cache_key . '_meta', 'cache-wp-query' );

                if ( is_array( $meta ) && ! empty( $meta ) ) {
                    $this->found_posts   = $meta['found_posts'];
                    $this->max_num_pages = $meta['max_num_pages'];
                }
            }
        }

        return $meta;

    }

    /**
     * Set meta properties
     *
     * @param \WP_Query $query
     */
    public function set_meta( $query ) {

        // Can be cached
        $cache_key = $this->get_cache_key();
        $posts     = $this->cached_posts;

        if ( ! empty( $cache_key ) ) {
            if ( ! empty( $posts ) ) {
                $this->found_posts   = $query->found_posts;
                $this->max_num_pages = $query->max_num_pages;

                $meta = array(
                    'found_posts'   => $this->found_posts,
                    'max_num_pages' => $this->max_num_pages,
                );

                $this->cache_set( $cache_key . '_meta', $meta, 'cache-wp-query', 30 * MINUTE_IN_SECONDS );
            } else {
                $this->cache_clear( $cache_key . '_meta', 'cache-wp-query' );

                $this->found_posts   = null;
                $this->max_num_pages = null;
            }
        }

    }

    /**
     * Get cache key
     *
     * @return string
     */
    public function get_cache_key() {

        $cache_key = $this->cache_key;

        if ( empty( $cache_key ) ) {
            $cache_key = null;

            if ( ! empty( $this->query_vars ) && empty( $this->query_vars['cache_wp_query_skip'] ) ) {
                $cache_key = md5( serialize( $this->query_vars ) );

                $cache_key_salt = get_option( 'cache_wp_query_salt' );

                if ( $cache_key_salt ) {
                    $cache_key .= '_' . $cache_key_salt;
                }
            }

            $this->cache_key = $cache_key;
        }

        return $cache_key;

    }

    /**
     * Reset cache key salt on saving of a post
     *
     * @param int     $post_id
     * @param WP_Post $post
     */
    public function reset_cache_key_salt( $post_id, $post ) {

        if ( ! in_array( $post->post_type, $this->post_types ) ) {
            return;
        }

        update_option( 'cache_wp_query_salt', time() );

    }

    /**
     * Reset query info
     */
    public function reset() {

        // Unset our stuff
        $this->query_vars    = array();
        $this->cache_key     = null;
        $this->cached_posts  = null;
        $this->found_posts   = null;
        $this->max_num_pages = null;

    }

    /**
     * Setup query for caching
     *
     * @param \WP_Query $query
     */
    public function setup_query( $query ) {

        $this->reset();

        $cache = false;

        if ( is_search() && ! empty( $query->query_vars['s'] ) && false !== apply_filters( 'cache_wp_query_search', true ) ) {
            $cache = true;
        } elseif ( ! empty( $query->query_vars['post_type'] ) ) {
            $cache = false;

            if ( ! empty( $query->query_vars['cache_wp_query'] ) ) {
                // Manual integration
                $cache = true;
            } elseif ( ! empty( $query->query_vars['ep_integrate'] ) && false !== apply_filters( 'cache_wp_query_elasticpress', true ) ) {
                // ElasticPress integration
                $cache = true;
            }

            // Check that all post types in query are supported for caching
            if ( $cache ) {
                $post_types = (array) $query->query_vars['post_type'];

                $cache = true;

                foreach ( $post_types as $post_type ) {
                    if ( ! in_array( $post_type, $this->post_types ) ) {
                        $cache = false;

                        break;
                    }
                }
            }
        }

        if ( $cache ) {
            $this->query_vars = $query->query_vars;

            $this->get_posts();
        }

    }

    /**
     * Get value from cache
     *
     * @param string $key   Cache key
     * @param string $group Cache group
     *
     * @return mixed
     */
    public function cache_get( $key, $group ) {

        $value = null;

        if ( function_exists( 'pods_cache_get' ) ) {
            $value = pods_cache_get( $key, $group );
        } else {
            $value = wp_cache_get( $key, $group );
        }

        return $value;

    }

    /**
     * Set cache value
     *
     * @param string   $key     Cache key
     * @param mixed    $value   Cache value
     * @param string   $group   Cache group
     * @param int|null $expires Cache expiration
     */
    public function cache_set( $key, $value, $group, $expires ) {

        if ( function_exists( 'pods_cache_set' ) ) {
            pods_cache_set( $key, $value, $group, $expires );
        } else {
            wp_cache_set( $key, $value, $group, $expires );
        }

    }

    /**
     * Clear cache
     *
     * @param string $key   Cache key
     * @param string $group Cache group
     */
    public function cache_clear( $key, $group ) {

        if ( function_exists( 'pods_cache_clear' ) ) {
            pods_cache_clear( $key, $group );
        } else {
            wp_cache_delete( $key, $group );
        }

    }

    /**
     * Return a singleton instance of the current class
     *
     * @return LaStudio_Cache_WP_Query
     */
    public static function factory() {

        static $instance = false;

        if ( ! $instance ) {
            $instance = new self();

            add_action( 'init', array( $instance, 'setup' ), 99 );
        }

        return $instance;

    }
}