build_args( $atts ); /** * Filter the testimonial query arguments. * * @param array $args WP_Query args. * @param array $atts Display attributes. */ $args = apply_filters( 'advanced_testimonial_query_args', $args, $atts ); // A random order must not be cached: the transient would store the IDs // the first visitor happened to get, so everyone else would see that // same handful for an hour, merely shuffled among themselves. if ( empty( $atts['ids'] ) && ! empty( $atts['cache'] ) && 'random' !== $atts['order'] ) { return $this->cached_query( $args, $atts ); } return new \WP_Query( $args ); } /** * Assemble the base query arguments. * * @param array $atts Normalized attributes. * @return array */ private function build_args( array $atts ) { $args = array( 'post_type' => CPT::POST_TYPE, 'post_status' => 'publish', 'posts_per_page' => (int) $atts['limit'], 'no_found_rows' => true, 'ignore_sticky_posts' => true, ); if ( 'random' === $atts['order'] ) { $args['orderby'] = 'rand'; } elseif ( 'rating' === $atts['orderby'] ) { // Order by the rating meta. The OR/NOT EXISTS clause keeps // unrated testimonials in the results (sorted last) instead of // the INNER JOIN a plain meta_key sort would force. $order = ( 'asc' === $atts['order'] ) ? 'ASC' : 'DESC'; $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- intentional, scoped display. 'relation' => 'OR', 'at_rating' => array( 'key' => Helpers::meta_key( 'rating' ), 'type' => 'DECIMAL(3,1)', 'compare' => 'EXISTS', ), array( 'key' => Helpers::meta_key( 'rating' ), 'compare' => 'NOT EXISTS', ), ); $args['orderby'] = array( 'at_rating' => $order, 'date' => 'DESC', ); } else { $args['orderby'] = $atts['orderby']; $args['order'] = ( 'asc' === $atts['order'] ) ? 'ASC' : 'DESC'; } if ( ! empty( $atts['verified'] ) ) { $verified_clause = array( 'key' => Helpers::meta_key( 'verified' ), 'value' => '1', ); if ( isset( $args['meta_query'] ) ) { // Combine with the rating sort clause: (rating OR no rating) AND verified. $args['meta_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- intentional, scoped display. 'relation' => 'AND', $args['meta_query'], $verified_clause, ); } else { $args['meta_query'] = array( $verified_clause ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- intentional, scoped display. } } if ( ! empty( $atts['ids'] ) ) { $args['post__in'] = $atts['ids']; if ( 'random' !== $atts['order'] ) { $args['orderby'] = 'post__in'; } $args['posts_per_page'] = count( $atts['ids'] ); } if ( ! empty( $atts['group'] ) ) { $args['tax_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- intentional, scoped display. array( 'taxonomy' => Taxonomy::TAXONOMY, 'field' => is_numeric( $atts['group'] ) ? 'term_id' : 'slug', 'terms' => $atts['group'], ), ); } return $args; } /** * Run the query through a transient cache (post IDs only). * * @param array $args Base query args. * @param array $atts Display attributes. * @return \WP_Query */ private function cached_query( array $args, array $atts ) { $version = (int) get_option( self::CACHE_VERSION_OPTION, 1 ); $key = 'at_q_' . $version . '_' . md5( (string) wp_json_encode( $args ) ); $ids = get_transient( $key ); if ( false === $ids ) { $id_args = $args; $id_args['fields'] = 'ids'; $id_query = new \WP_Query( $id_args ); $ids = array_map( 'intval', $id_query->posts ); set_transient( $key, $ids, HOUR_IN_SECONDS ); } if ( empty( $ids ) ) { return new \WP_Query( array( 'post_type' => CPT::POST_TYPE, 'post__in' => array( 0 ), ) ); } return new \WP_Query( array( 'post_type' => CPT::POST_TYPE, 'post_status' => 'publish', 'post__in' => $ids, 'orderby' => ( 'random' === $atts['order'] ) ? 'rand' : 'post__in', 'posts_per_page' => count( $ids ), 'no_found_rows' => true, 'ignore_sticky_posts' => true, ) ); } /** * Invalidate all cached testimonial queries by bumping the version counter. * * @return void */ public static function bust_cache() { $version = (int) get_option( self::CACHE_VERSION_OPTION, 1 ); update_option( self::CACHE_VERSION_OPTION, $version + 1, false ); } }