gocodebox/lifterlms

View on GitHub
includes/class.llms.query.php

Summary

Maintainability
C
1 day
Test Coverage
F
59%
<?php
/**
 * LLMS_Query class file.
 *
 * @package LifterLMS/Classes
 *
 * @since 1.0.0
 * @version 7.5.0
 */

defined( 'ABSPATH' ) || exit;

/**
 * Query base class
 *
 * Handles queries and endpoints.
 *
 * @since 1.0.0
 * @since 4.0.0 Remove previously deprecated methods.
 */
class LLMS_Query {

    /**
     * Query var
     *
     * @var array
     */
    public $query_vars = array();

    /**
     * Constructor.
     *
     * @since 1.0.0
     * @since 3.28.2 Unknown.
     * @since 3.36.3 Changed `pre_get_posts` callback from `10 (default) to `15`,
     *               so to avoid conflicts with the Divi theme whose callback runs at `10`,
     *               but since themes are loaded after plugins it overrode our one.
     * @since 4.5.0 Added action to serve 404s on unviewable certificates.
     * @since 6.0.0 Add callback to redirect old `llms_my_certificates` requests to the new url.
     */
    public function __construct() {

        add_action( 'init', array( $this, 'add_endpoints' ) );

        if ( ! is_admin() ) {

            add_filter( 'query_vars', array( $this, 'set_query_vars' ), 0 );
            add_action( 'parse_request', array( $this, 'parse_request' ), 0 );
            add_action( 'wp', array( $this, 'maybe_404_certificate' ), 50 );
            add_action( 'wp', array( $this, 'maybe_redirect_certificate' ), 50 );

        }

        $this->init_query_vars();

        add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ), 15 );

    }

    /**
     * Add Query Endpoints
     *
     * @since 1.0.0
     * @since 3.28.2 Handle dashboard tab pagination via a rewrite rule.
     * @since 5.0.2 Add support for slugs with non-latin characters.
     *
     * @return void
     */
    public function add_endpoints() {

        foreach ( $this->get_query_vars() as $key => $var ) {
            add_rewrite_endpoint( $var, EP_PAGES, $key );
        }

        global $wp_rewrite;
        foreach ( LLMS_Student_Dashboard::get_tabs() as $id => $tab ) {
            if ( ! empty( $tab['paginate'] ) ) {
                $regex    = sprintf( '(.?.+?)/%1$s/%2$s/?([0-9]{1,})/?$', urldecode( $tab['endpoint'] ), $wp_rewrite->pagination_base );
                $redirect = sprintf( 'index.php?pagename=$matches[1]&%s=$matches[3]&paged=$matches[2]', $id );
                add_rewrite_rule( $regex, $redirect, 'top' );
            }
        }

    }

    /**
     * Get query variables
     *
     * @since Unknown
     *
     * @return array
     */
    public function get_query_vars() {
        return apply_filters( 'llms_get_endpoints', $this->query_vars );
    }

    /**
     * Get a taxonomy query that filters out courses & memberships based on catalog / search visibility settings
     *
     * @since 3.6.0
     *
     * @param array $query Existing taxonomy query from the global $wp_query.
     * @return array
     */
    private function get_tax_query( $query = array() ) {

        if ( ! is_array( $query ) ) {
            $query = array(
                'relation' => 'AND',
            );
        }

        $terms = wp_list_pluck(
            get_terms(
                array(
                    'taxonomy'   => 'llms_product_visibility',
                    'hide_empty' => false,
                )
            ),
            'term_taxonomy_id',
            'name'
        );

        $not_in = ( is_search() ) ? array( $terms['hidden'], $terms['catalog'] ) : array( $terms['hidden'], $terms['search'] );

        $query[] = array(
            'field'    => 'term_taxonomy_id',
            'operator' => 'NOT IN',
            'taxonomy' => 'llms_product_visibility',
            'terms'    => $not_in,
        );

        return $query;

    }

    /**
     * Init queries
     *
     * @since Unknown
     *
     * @return void
     */
    public function init_query_vars() {

        $this->query_vars = array(
            'confirm-payment' => get_option( 'lifterlms_myaccount_confirm_payment_endpoint', 'confirm-payment' ),
            'lost-password'   => get_option( 'lifterlms_myaccount_lost_password_endpoint', 'lost-password' ),
        );

    }

    /**
     * Parse the request for query variables
     *
     * @since unknown
     * @since 3.31.0 sanitize and unslash `$_GET` vars.
     *
     * @return void
     */
    public function parse_request() {

        global $wp;

        foreach ( $this->get_query_vars() as $key => $var ) {
            if ( isset( $_GET[ $var ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                $wp->query_vars[ $key ] = sanitize_text_field( wp_unslash( $_GET[ $var ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            } elseif ( isset( $wp->query_vars[ $var ] ) ) {
                $wp->query_vars[ $key ] = $wp->query_vars[ $var ];
            }
        }

    }

    /**
     * Sets the WP_Query variables for "post_type" on LifterLMS custom taxonomy archive pages for Courses and Memberships.
     *
     * @since 1.4.4 Moved from LLMS_Post_Types.
     * @since 3.16.8
     * @since 3.33.0 Added `post_title` as a secondary sort when the primary sort is `menu_order`
     * @since 3.36.3 Changed `pre_get_posts` callback from `10 (default) to `15`,
     *               so to avoid conflicts with the Divi theme whose callback runs at `10`,
     *               but since themes are loaded after plugins it overrode our one.
     * @since 3.36.4 Don't remove this callback from within the callback itself.
     *               Rather use a static variable to make sure the business logic of this
     *               method is executed only once.
     *
     * @param WP_Query $query Main WP_Query Object.
     * @return void
     */
    public function pre_get_posts( $query ) {

        static $done      = false;
        $modify_tax_query = false;

        if ( $done ) {
            return;
        }

        if ( ! is_admin() && $query->is_main_query() ) {

            if ( is_search() ) {
                $modify_tax_query = true;
            }

            if ( is_tax( array( 'course_cat', 'course_tag', 'course_difficulty', 'course_track', 'membership_tag', 'membership_cat' ) ) ) {

                $query->set( 'post_type', array( 'course', 'llms_membership' ) );
                $modify_tax_query = true;

            }

            if ( is_post_type_archive( 'course' ) || $query->get( 'page_id' ) == llms_get_page_id( 'courses' ) || is_tax( array( 'course_cat', 'course_tag', 'course_difficulty', 'course_track' ) ) ) {

                $query->set( 'posts_per_page', get_option( 'lifterlms_shop_courses_per_page', 10 ) );

                $sorting = explode( ',', get_option( 'lifterlms_shop_ordering', 'menu_order,ASC' ) );

                $orderby = empty( $sorting[0] ) ? 'menu_order' : $sorting[0];
                if ( 'menu_order' === $orderby ) {
                    $orderby .= ' post_title';
                }
                $order = empty( $sorting[1] ) ? 'ASC' : $sorting[1];

                $query->set( 'orderby', apply_filters( 'llms_courses_orderby', $orderby ) );
                $query->set( 'order', apply_filters( 'llms_courses_order', $order ) );

                $modify_tax_query = true;

            } elseif ( is_post_type_archive( 'llms_membership' ) || $query->get( 'page_id' ) == llms_get_page_id( 'memberships' ) || is_tax( array( 'membership_tag', 'membership_cat' ) ) ) {

                $query->set( 'posts_per_page', get_option( 'lifterlms_memberships_per_page', 10 ) );

                $sorting = explode( ',', get_option( 'lifterlms_memberships_ordering', 'menu_order,ASC' ) );

                $orderby = empty( $sorting[0] ) ? 'menu_order' : $sorting[0];
                if ( 'menu_order' === $orderby ) {
                    $orderby .= ' post_title';
                }
                $order = empty( $sorting[1] ) ? 'ASC' : $sorting[1];

                $query->set( 'orderby', apply_filters( 'llms_memberships_orderby', $orderby ) );
                $query->set( 'order', apply_filters( 'llms_memberships_order', $order ) );

                $modify_tax_query = true;

            }

            // Do it once.
            $done = true;

        }

        if ( $modify_tax_query ) {

            $query->set( 'tax_query', $this->get_tax_query( $query->get( 'tax_query' ) ) );

        }

    }

    /**
     * Serve a 404 for certificates that are not viewable by the current user
     *
     * @since 4.5.0
     *
     * @return void
     */
    public function maybe_404_certificate() {

        if ( 'llms_my_certificate' === get_post_type() ) {
            $cert = new LLMS_User_Certificate( get_the_ID() );
            if ( ! $cert->can_user_view() ) {

                global $wp_query;
                $wp_query->set_404();
                status_header( 404 );
                nocache_headers();

            }
        }

    }

    /**
     * Redirect requests to old llms_my_certificate URLs to the new url.
     *
     * Redirects `/my_certificate/slug` to `/certificate/slug` maintaining
     * translations.
     *
     * This will only redirect if `$wp_query` detects a 404 and a certificate
     * exists with the parsed slug. This check is important to prevent against
     * collisions which are theoretically possible, though probably unlikely.
     *
     * @since 6.0.0
     * @since 7.5.0 Fixed passing null to parameter #1 ($haystack) using `strpos`.
     *
     * @return void
     */
    public function maybe_redirect_certificate() {

        global $wp, $wp_query;

        $old  = sprintf( '/%s/', _x( 'my_certificate', 'slug', 'lifterlms' ) );
        $path = wp_parse_url( home_url( $wp->request ), PHP_URL_PATH );
        if ( $wp_query->is_404() && $path && 0 === strpos( $path, $old ) ) {
            $slug     = str_replace( $old, '', $path );
            $new_post = get_page_by_path( $slug, 'OBJECT', 'llms_my_certificate' );
            if ( $new_post ) {
                llms_redirect_and_exit( get_permalink( $new_post->ID ) );
            }
        }

    }

    /**
     * Set query variables
     *
     * @since Unknown
     *
     * @param  array $vars WP query variables available for query.
     * @return array
     */
    public function set_query_vars( $vars ) {

        foreach ( $this->get_query_vars() as $key => $var ) {
            $vars[] = $key;
        }

        return $vars;

    }

}

return new LLMS_Query();