get( 'sg7g_search_term' ); $live_likes_sort = (bool) $query->get( 'sg7g_live_likes_sort' ); if ( ( ! is_string( $term ) || '' === trim( $term ) ) && ! $live_likes_sort ) { return $clauses; } global $wpdb; if ( $live_likes_sort ) { $table = SG7G_Likes::table_name(); if ( false === strpos( $clauses['join'], $table ) ) { $clauses['join'] .= " LEFT JOIN {$table} AS sg7g_live_likes ON sg7g_live_likes.post_id = {$wpdb->posts}.ID"; } $clauses['groupby'] = $clauses['groupby'] ? $clauses['groupby'] . ", {$wpdb->posts}.ID" : "{$wpdb->posts}.ID"; $clauses['orderby'] = "COUNT(sg7g_live_likes.id) DESC, {$wpdb->posts}.post_date DESC"; } if ( is_string( $term ) && '' !== trim( $term ) ) { $like = '%' . $wpdb->esc_like( self::sanitize_term( $term ) ) . '%'; $clauses['where'] .= $wpdb->prepare( " AND {$wpdb->posts}.post_title LIKE %s", $like ); } return $clauses; } public static function register_rest_route(): void { register_rest_route( self::REST_NAMESPACE, self::REST_ROUTE, array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( __CLASS__, 'rest_search' ), 'permission_callback' => '__return_true', 'args' => array( 'term' => array( 'default' => '', 'sanitize_callback' => array( __CLASS__, 'sanitize_term' ), ), 'page' => array( 'default' => 1, 'sanitize_callback' => 'absint', 'validate_callback' => static function ( $value ): bool { return absint( $value ) >= 1; }, ), 'taxonomy' => array( 'default' => '', 'sanitize_callback' => 'sanitize_key', 'validate_callback' => static function ( $value ): bool { return in_array( (string) $value, array( '', 'sg7g_category', 'sg7g_tag' ), true ); }, ), 'term_id' => array( 'default' => 0, 'sanitize_callback' => 'absint', ), 'media_type' => array( 'default' => '', 'sanitize_callback' => 'sanitize_key', 'validate_callback' => static function ( $value ): bool { return in_array( (string) $value, array( '', 'video', 'audio' ), true ); }, ), 'category' => array( 'default' => 0, 'sanitize_callback' => 'absint', ), 'year' => array( 'default' => 0, 'sanitize_callback' => 'absint', ), 'sort' => array( 'default' => 'newest', 'sanitize_callback' => 'sanitize_key', 'validate_callback' => static function ( $value ): bool { return in_array( (string) $value, array( 'newest', 'oldest', 'views', 'likes' ), true ); }, ), ), ) ); } public static function rest_search( WP_REST_Request $request ): WP_REST_Response { $term = self::sanitize_term( (string) $request->get_param( 'term' ) ); $page = min( 10000, max( 1, absint( $request->get_param( 'page' ) ) ) ); $taxonomy = sanitize_key( (string) $request->get_param( 'taxonomy' ) ); $term_id = absint( $request->get_param( 'term_id' ) ); $media_type = sanitize_key( (string) $request->get_param( 'media_type' ) ); $category = absint( $request->get_param( 'category' ) ); $year = absint( $request->get_param( 'year' ) ); $sort = sanitize_key( (string) $request->get_param( 'sort' ) ); $sort = in_array( $sort, array( 'newest', 'oldest', 'views', 'likes' ), true ) ? $sort : 'newest'; $query_args = array( 'post_type' => 'sg7g_media', 'post_status' => 'publish', 'has_password' => false, 'posts_per_page' => max( 1, (int) SG7G_Settings::get( 'posts_per_page', 12 ) ), 'paged' => $page, 'ignore_sticky_posts' => true, 'sg7g_search_term' => $term, 'no_found_rows' => false, ); if ( $taxonomy && $term_id && term_exists( $term_id, $taxonomy ) ) { // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- User-selected gallery category filter. $query_args['tax_query'] = array( array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => array( $term_id ), ), ); } if ( in_array( $media_type, array( 'video', 'audio' ), true ) ) { $query_args['meta_query'] = array( array( 'key' => '_sg7g_media_type', 'value' => $media_type, ), ); } if ( $category > 0 && term_exists( $category, 'sg7g_category' ) ) { $query_args['tax_query'] = isset( $query_args['tax_query'] ) && is_array( $query_args['tax_query'] ) ? $query_args['tax_query'] : array(); $query_args['tax_query'][] = array( 'taxonomy' => 'sg7g_category', 'field' => 'term_id', 'terms' => array( $category ), ); } if ( $year >= 1970 && $year <= 2100 ) { $query_args['date_query'] = array( array( 'year' => $year ) ); } switch ( $sort ) { case 'oldest': $query_args['orderby'] = 'date'; $query_args['order'] = 'ASC'; break; case 'views': $query_args['meta_key'] = '_sg7g_views'; $query_args['orderby'] = array( 'meta_value_num' => 'DESC', 'date' => 'DESC' ); $query_args['order'] = 'DESC'; break; case 'likes': // filter_posts_clauses performs a live COUNT(*); no // aggregate like-count meta is used for ordering. $query_args['sg7g_live_likes_sort'] = true; $query_args['orderby'] = 'date'; $query_args['order'] = 'DESC'; break; case 'newest': default: $query_args['orderby'] = 'date'; $query_args['order'] = (string) SG7G_Settings::get( 'sort_order', 'DESC' ); break; } $search_query = new WP_Query( $query_args ); // A stale browser-history URL can point beyond the last available // results page after content is removed. Return the real last page // instead of a misleading empty result set. $max_pages = max( 0, (int) $search_query->max_num_pages ); if ( $search_query->found_posts > 0 && $max_pages > 0 && $page > $max_pages ) { $page = $max_pages; $query_args['paged'] = $page; $search_query = new WP_Query( $query_args ); } ob_start(); while ( $search_query->have_posts() ) { $search_query->the_post(); SG7G_Renderer::card(); } $cards_html = (string) ob_get_clean(); wp_reset_postdata(); $total = (int) $search_query->found_posts; $pages = max( 0, (int) $search_query->max_num_pages ); $status = ''; if ( '' !== $term ) { $status = 0 === $total ? __( 'No content matched your search.', '7sgaleri' ) : sprintf( /* translators: %s is the number of search results. */ /* translators: %s: Number of search results. */ _n( '%s result found.', '%s results found.', $total, '7sgaleri' ), number_format_i18n( $total ) ); } $response = new WP_REST_Response( array( 'html' => $cards_html, 'total' => $total, 'page' => $page, 'pages' => $pages, 'status' => $status, 'emptyText' => __( 'No content matched your search.', '7sgaleri' ), ), 200 ); $response->header( 'Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0' ); $response->header( 'Pragma', 'no-cache' ); $response->header( 'X-Robots-Tag', 'noindex, nofollow' ); return $response; } }