内容

BP_Search

BuddyPress全局搜索主控制器类

描述

文件:bp-search /类/ class-bp-search.php

类BP_Search {/ ** *该变量以适用于每种类型搜索的辅助类对象。* e.g * [*'posts'=> bp_search_posts的对象,*'组'=> bp_search_groups *]的对象* @var array * @since buddyboss 1.0.0 * / public $ search_helpers = array();公共$ Semiceable_Items;/ ** *要包含用于搜索参数的变量。*稍后将被其他方法使用它。* @var array * / public $ search_args = array();/ ** *要保持搜索结果的变量。* The results will be grouped into different types(e.g: posts, members, etc..) * * The structure of array after being populated should be: * 'posts' => [ * 'total_match_count' => 34, * 'items' => * ], * 'members' => * @var array */ public $search_results = array(); /** * Insures that only one instance of Class exists in memory at any * one time. Also prevents needing to define globals all over the place. * * @since BuddyBoss 1.0.0 * * @see BP_Search::instance() * * @return object bp_search_Plugin */ public static function instance() { // Store the instance locally to avoid private static replication static $instance = null; // Only run these methods if they haven't been run previously if ( null === $instance ) { $instance = new self(); //create instances of helpers and associate them with types add_action( 'init', array( $instance, 'load_search_helpers' ), 80 ); add_action( 'wp_ajax_bp_search_ajax', array( $instance, 'ajax_search' ) ); add_action( 'wp_ajax_nopriv_bp_search_ajax', array( $instance, 'ajax_search' ) ); } // Always return the instance return $instance; } /* Magic Methods * =================================================================== */ /** * A dummy constructor to prevent this class from being loaded more than once. * * @since BuddyBoss 1.0.0 */ private function __construct() { /* Do nothing here */ } /** * A dummy magic method to prevent this class from being cloned. * * @since BuddyBoss 1.0.0 */ public function __clone() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin\' huh?', 'buddyboss' ), '1.7' ); } /** * A dummy magic method to prevent this class being unserialized. * * @since BuddyBoss 1.0.0 */ public function __wakeup() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin\' huh?', 'buddyboss' ), '1.7' ); } /** * @todo add title/description * * @since BuddyBoss 1.0.0 */ public function load_search_helpers() { global $bp; //load the helper type parent class require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-types.php' ); //load and associate helpers one by one if ( bp_is_search_post_type_enable( 'post' ) ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-posts.php' ); $this->search_helpers['posts'] = new Bp_Search_Posts( 'post', 'posts' ); $this->searchable_items[] = 'posts'; } if ( bp_is_search_post_type_enable( 'page' ) ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-posts.php' ); $this->search_helpers['pages'] = new Bp_Search_Posts( 'page', 'pages' ); } if ( bp_is_active( 'forums' ) && bp_is_search_post_type_enable( 'forum' ) ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-bbpress.php' ); if ( bp_is_search_post_type_enable( 'forum' ) ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-bbpress-forums.php' ); $this->search_helpers['forum'] = Bp_Search_bbPress_Forums::instance(); $this->searchable_items[] = 'forum'; } if ( bp_is_search_post_type_enable( 'topic' ) ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-bbpress-forums-topics.php' ); $this->search_helpers['topic'] = Bp_Search_bbPress_Topics::instance(); $this->searchable_items[] = 'topic'; } if ( bp_is_search_post_type_enable( 'reply' ) ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-bbpress-forums-replies.php' ); $this->search_helpers['reply'] = Bp_Search_bbPress_Replies::instance(); $this->searchable_items[] = 'reply'; } } //Check BuddyPress is active if ( bp_is_search_members_enable() ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-members.php' ); $this->search_helpers['members'] = Bp_Search_Members::instance(); $this->searchable_items[] = 'members'; } if ( bp_is_active( 'groups' ) && bp_is_search_groups_enable() ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-groups.php' ); $this->search_helpers['groups'] = Bp_Search_Groups::instance(); $this->searchable_items[] = 'groups'; } if ( bp_is_active( 'activity' ) && bp_is_search_activity_enable() ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-activities.php' ); $this->search_helpers['activity'] = Bp_Search_Activities::instance(); $this->searchable_items[] = 'activity'; if ( bp_is_search_activity_comments_enable() ) { require_once( $bp->plugin_dir . 'bp-search/classes/class-bp-search-activity-comments.php' ); $this->search_helpers['activity_comment'] = Bp_Search_Activity_Comment::instance(); $this->searchable_items[] = 'activity_comment'; } } /** * Hook to load helper classes for additional search types. */ $additional_search_helpers = apply_filters( 'bp_search_additional_search_helpers', array() ); if ( ! empty( $additional_search_helpers ) ) { foreach ( $additional_search_helpers as $search_type => $helper_object ) { /** * All helper classes must inherit from bp_search_Type */ if ( ! isset( $this->search_helpers[ $search_type ] ) && is_a( $helper_object, 'BP_Search_Type' ) ) { $this->search_helpers[ $search_type ] = $helper_object; } } } } public function ajax_search() { check_ajax_referer( 'bp_search_ajax', 'nonce' ); if ( isset( $_POST["view"] ) && $_POST["view"] == "content" ) { $_GET["s"] = $_POST["s"]; if ( ! empty( $_POST["subset"] ) ) { $_GET["subset"] = $_POST["subset"]; } if ( ! empty( $_POST["list"] ) ) { $_GET["list"] = $_POST["list"]; } $content = ""; BP_Search::instance()->prepare_search_page(); $content = bp_search_buffer_template_part( 'results-page-content', '', false ); echo $content; die(); } $args = array( 'search_term' => $_REQUEST['search_term'], //How many results should be displyed in autosuggest? //@todo: give a settings field for this value 'ajax_per_page' => $_REQUEST['per_page'], 'count_total' => true, 'template_type' => 'ajax', ); if ( isset( $_REQUEST['forum_search_term'] ) ) { $args['forum_search'] = true; } $this->do_search( $args ); $search_results = array(); if ( isset( $this->search_results['all']['items'] ) && ! empty( $this->search_results['all']['items'] ) ) { /* ++++++++++++++++++++++++++++++++++ group items of same type together ++++++++++++++++++++++++++++++++++ */ $types = array(); foreach ( $this->search_results['all']['items'] as $item_id => $item ) { $type = $item['type']; if ( empty( $types ) || ! in_array( $type, $types ) ) { $types[] = $type; } } $new_items = array(); foreach ( $types as $type ) { $first_html_changed = false; foreach ( $this->search_results['all']['items'] as $item_id => $item ) { if ( $item['type'] != $type ) { continue; } //add group/type title in first one /* if( !$first_html_changed ){ //this filter can be used to change display of 'posts' to 'Blog Posts' etc.. $label = apply_filters( 'bp_search_label_search_type', $type ); //$item['html'] = "
{$label}
" . $item['html']; $first_html_changed = true; } */ $new_items[ $item_id ] = $item; } } $this->search_results['all']['items'] = $new_items; /* _______________________________ */ $url = $this->search_page_search_url( false ); if ( true === $this->search_args['forum_search'] ) { $url = $url; } else { $url = esc_url( add_query_arg( array( 'view' => 'content', 'no_frame' => '1', 'bp_search' => 1 ), $url ) ); } $type_mem = ""; foreach ( $this->search_results['all']['items'] as $item_id => $item ) { $new_row = array( 'value' => $item['html'] ); $type_label = apply_filters( 'bp_search_label_search_type', $item['type'] ); $new_row['type'] = $item['type']; $new_row['type_label'] = ""; $new_row['value'] = $item['html']; if ( isset( $item['title'] ) ) { $new_row['label'] = $item['title']; } // if ( $type_mem != $new_row['type'] ) { // $type_mem = $new_row['type']; // $cat_row = $new_row; // $cat_row["type"] = $item['type']; // $cat_row['type_label'] = $type_label; // $category_search_url = esc_url( add_query_arg( array( 'subset' => $item['type'] ), $url ) ); // $html = "" . $type_label . ""; // $cat_row["value"] = apply_filters( 'buddypress_gs_autocomplete_category', $html, $item['type'], $url, $type_label ); // $search_results[] = $cat_row; // } $search_results[] = $new_row; } // Show "View All" link if ( absint( $this->search_results['all']['total_match_count'] ) > absint( bp_search_get_form_option( 'bp_search_number_of_results', 5 ) ) ) { $all_results_row = array( "value" => "", "type" => 'view_all_type', "type_label" => '' ); $search_results[] = $all_results_row; } } else { //@todo give a settings screen for this field $search_results[] = array( 'value' => '
' . sprintf( __( "Nothing found for '%s'", "buddyboss" ), stripslashes( $this->search_args['search_term'] ) ) . '
', 'label' => $this->search_args['search_term'] ); } die( json_encode( $search_results ) ); } /** * Perform search and generate search results * * @param mixed $args * * @since BuddyBoss 1.0.0 */ public function do_search( $args = '' ) { global $wpdb; $args = $this->sanitize_args( $args ); $defaults = array( //the search term 'search_term' => '', //Restrict search results to only this subset. eg: posts, members, groups, etc. //See Setting > what to search? 'search_subset' => 'all', // //What all to search for. e.g: members. //See Setting > what to search? //The options passed here must be a subset of all options available on Setting > what to search, nothing extra can be passed here. // //This is different from search_subset. //If search_subset is 'all', then search is performed for all searchable items. //If search_subset is 'members' then only total match count for other searchable_items is calculated( so that it can be displayed in tabs) //members(23) | posts(201) | groups(2) and so on. // 'searchable_items' => BP_Search::instance()->option( 'items-to-search' ), //how many search results to display per page 'per_page' => 20, //current page 'current_page' => 1, //should we calculate total match count for all different types? //it should be set to false while calling this function for ajax search 'count_total' => true, //template type to load for each item //search results will be styled differently(minimal) while in ajax search //options ''|'minimal' 'template_type' => '', 'forum_search' => false, 'number' => 3 ); $args = wp_parse_args( $args, $defaults ); if ( true === $args['forum_search'] ) { $this->searchable_items = array( 'forum', 'topic', 'reply' ); } $this->search_args = $args;//save it for using in other methods //bail out if nothing to search for if ( ! $args['search_term'] ) { return; } if ( 'all' == $args['search_subset'] ) { /** * 1. Generate a 'UNION' sql query for all searchable items with only ID, RANK, TYPE(posts|members|..) as columns, order by RANK DESC. * 3. Generate html for each of them */ /* an example UNION query :- ----------------------------------------------------- ( SELECT wp_posts.id , 'posts' as type, wp_posts.post_title LIKE '%ho%' AS relevance, wp_posts.post_date as entry_date FROM wp_posts WHERE 1=1 AND ( ( (wp_posts.post_title LIKE '%ho%') OR (wp_posts.post_content LIKE '%ho%') ) ) AND wp_posts.post_type IN ('post', 'page', 'attachment') AND ( wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private' ) ) UNION ( SELECT DISTINCT g.id, 'groups' as type, g.name LIKE '%ho%' AS relevance, gm2.meta_value as entry_date FROM wp_bp_groups_groupmeta gm1, wp_bp_groups_groupmeta gm2, wp_bp_groups g WHERE 1=1 AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND ( g.name LIKE '%ho%' OR g.description LIKE '%ho%' ) ) ORDER BY relevance DESC, entry_date DESC LIMIT 0, 10 ---------------------------------------------------- */ $sql_queries = []; $total = []; foreach ( $this->searchable_items as $search_type ) { if ( ! isset( $this->search_helpers[ $search_type ] ) ) { continue; } /** * the following variable will be an object of current search type helper class * e.g: an object of Bp_Search_Groups or Bp_Search_Posts etc. * so we can safely call the public methods defined in those classes. * This also means that all such classes must have a common set of methods. */ $obj = $this->search_helpers[ $search_type ]; $limit = isset( $_REQUEST['view'] ) ? " LIMIT " . ( $args['number'] ) : ''; $sql_queries[] = "( " . $obj->union_sql( $args['search_term'] ) . " $limit ) "; $total[ $search_type ] = $obj->get_total_match_count( $args['search_term'] ); } if ( empty( $sql_queries ) ) { //thigs will get messy if program reaches here!! return; } $pre_search_query = implode( ' UNION ', $sql_queries ) . " ORDER BY relevance, type DESC, entry_date DESC "; if ( isset( $args['ajax_per_page'] ) && $args['ajax_per_page'] > 0 ) { $pre_search_query .= " LIMIT {$args['ajax_per_page']} "; } $results = $wpdb->get_results( $pre_search_query ); /* $results will have a structure like below */ /* id | type | relevance | entry_date 45 | groups | 1 | 2014-10-28 17:05:18 40 | posts | 1 | 2014-10-26 13:52:06 4 | groups | 0 | 2014-10-21 15:15:36 */ if ( ! empty( $results ) ) { $this->search_results['all'] = array( 'total_match_count' => 0, 'items' => array(), 'items_title' => array() ); //segregate items of a type together and pass it to corresponsing search handler, so that an aggregate query can be done //e.g one single wordpress loop can be done for all posts foreach ( $results as $item ) { $obj = $this->search_helpers[ $item->type ]; $obj->add_search_item( $item->id ); } //now get html for each item foreach ( $results as $item ) { $obj = $this->search_helpers[ $item->type ]; $result = array( 'id' => $item->id, 'type' => $item->type, 'html' => $obj->get_html( $item->id, $args['template_type'] ), 'title' => $obj->get_title( $item->id ) ); $this->search_results['all']['items'][ $item->type . '_' . $item->id ] = $result; } //now we've html saved for search results if ( ! empty( $this->search_results['all']['items'] ) && $args['template_type'] != 'ajax' ) { /* ++++++++++++++++++++++++++++++++++ group items of same type together ++++++++++++++++++++++++++++++++++ */ //create another copy, of items, this time, items of same type grouped together $ordered_items_group = array(); foreach ( $this->search_results['all']['items'] as $item_id => $item ) { $type = $item['type']; if ( ! isset( $ordered_items_group[ $type ] ) ) { $ordered_items_group[ $type ] = array(); } $item_id = absint( str_replace( $type . '_', '', $item_id ) ); $ordered_items_group[ $type ][ $item_id ] = $item; } $search_items = bp_search_items(); $search_url = $this->search_page_search_url(); foreach ( $ordered_items_group as $type => &$items ) { //now prepend html (opening tags) to first item of each $category_search_url = esc_url( add_query_arg( array( 'subset' => $type, 'bp_search' => 1 ), $search_url ) ); $label = isset( $search_items[ $type ] ) ? trim( $search_items[ $type ] ) : trim( $type ); $first_item = reset( $items ); $total_results = $total[ $type ]; $start_html = "
" . "
" . "

" . apply_filters( 'bp_search_label_search_type', $label ) . "

" . "" . sprintf( _n( '%d result', '%d results', $total_results, 'buddyboss' ), $total_results ) . "" . "
" . "
    "; $group_start_html = apply_filters( "bp_search_results_group_start_html", $start_html, $type ); $first_item['html'] = $group_start_html . $first_item['html']; $items[ $first_item['id'] ] = $first_item; //and append html (closing tags) to last item of each type $last_item = end( $items ); $end_html = "
"; if ( $total_results > 3 ) { $end_html .= ""; } $end_html .= "
"; $group_end_html = apply_filters( "bp_search_results_group_end_html", $end_html, $type ); $last_item['html'] = $last_item['html'] . $group_end_html; $items[ $last_item['id'] ] = $last_item; } //replace orginal items with this new, grouped set of items $this->search_results['all']['items'] = array(); foreach ( $ordered_items_group as $type => $grouped_items ) { // Remove last item from list if ( count( $grouped_items ) > 3 ) { array_pop( $grouped_items ); } foreach ( $grouped_items as $item_id => $item ) { $this->search_results['all']['items'][ $type . '_' . $item_id ] = $item; } } /* ________________________________ */ } } } else { //if subset not in searchable items, bail out. if ( ! in_array( $args['search_subset'], $this->searchable_items ) ) { return; } if ( ! isset( $this->search_helpers[ $args['search_subset'] ] ) ) { return; } /** * 1. Search top top 20( $args['per_page'] ) item( posts|members|..) * 2. Generate html for each of them */ //$args['per_page'] = get_option( 'posts_per_page' ); $obj = $this->search_helpers[ $args['search_subset'] ]; $pre_search_query = $obj->union_sql( $args['search_term'] ) . " ORDER BY relevance DESC, entry_date DESC "; if ( $args['per_page'] > 0 ) { $offset = ( $args['current_page'] * $args['per_page'] ) - $args['per_page']; $pre_search_query .= " LIMIT {$offset}, {$args['per_page']} "; } $results = $wpdb->get_results( $pre_search_query ); /* $results will have a structure like below */ /* id | type | relevance | entry_date 45 | groups | 1 | 2014-10-28 17:05:18 40 | posts | 1 | 2014-10-26 13:52:06 4 | groups | 0 | 2014-10-21 15:15:36 */ if ( ! empty( $results ) ) { $obj = $this->search_helpers[ $args['search_subset'] ]; $this->search_results[ $args['search_subset'] ] = array( 'total_match_count' => 0, 'items' => array() ); //segregate items of a type together and pass it to corresponsing search handler, so that an aggregate query can be done //e.g one single wordpress loop can be done for all posts foreach ( $results as $item ) { $obj->add_search_item( $item->id ); } //now get html for each item foreach ( $results as $item ) { $html = $obj->get_html( $item->id, $args['template_type'] ); $result = array( 'id' => $item->id, 'type' => $args['search_subset'], 'html' => $obj->get_html( $item->id, $args['template_type'] ), 'title' => $obj->get_title( $item->id ), ); $this->search_results[ $args['search_subset'] ]['items'][ $item->id ] = $result; } //now prepend html (opening tags) to first item of each type $first_item = reset( $this->search_results[ $args['search_subset'] ]['items'] ); $start_html = "
" . "
    "; $group_start_html = apply_filters( "bp_search_results_group_start_html", $start_html, $args['search_subset'] ); $first_item['html'] = $group_start_html . $first_item['html']; $this->search_results[ $args['search_subset'] ]['items'][ $first_item['id'] ] = $first_item; //and append html (closing tags) to last item of each type $last_item = end( $this->search_results[ $args['search_subset'] ]['items'] ); $end_html = "
"; $group_end_html = apply_filters( "bp_search_results_group_end_html", $end_html, $args['search_subset'] ); $last_item['html'] = $last_item['html'] . $group_end_html; $this->search_results[ $args['search_subset'] ]['items'][ $last_item['id'] ] = $last_item; } } //html for search results is generated. //now, lets calculate the total number of search results, for all different types if ( $args['count_total'] ) { $all_items_count = 0; foreach ( $this->searchable_items as $search_type ) { if ( ! isset( $this->search_helpers[ $search_type ] ) ) { continue; } $obj = $this->search_helpers[ $search_type ]; $total_match_count = $obj->get_total_match_count( $this->search_args['search_term'] ); $this->search_results[ $search_type ]['total_match_count'] = $total_match_count; $all_items_count += $total_match_count; } $this->search_results['all']['total_match_count'] = $all_items_count; } } /** * setup everything before starting to display content for search page. */ public function prepare_search_page() { $args = array(); if ( isset( $_GET['subset'] ) && ! empty( $_GET['subset'] ) ) { $args['search_subset'] = $_GET['subset']; } if ( isset( $_GET['s'] ) && ! empty( $_GET['s'] ) ) { $args['search_term'] = $_GET['s']; } if ( isset( $_GET['list'] ) && ! empty( $_GET['list'] ) ) { $current_page = (int) $_GET['list']; if ( $current_page > 0 ) { $args['current_page'] = $current_page; } } $args = apply_filters( 'bp_search_search_page_args', $args ); $this->do_search( $args ); } /** * Sanitize user inputs before performing search. * * @param mixed $args * * @return array */ public function sanitize_args( $args = '' ) { $args = wp_parse_args( $args, array() ); if ( isset( $args['search_term'] ) ) { $args['search_term'] = sanitize_text_field( $args['search_term'] ); } if ( isset( $args['search_subset'] ) ) { $args['search_subset'] = sanitize_text_field( $args['search_subset'] ); } if ( isset( $args['per_page'] ) ) { $args['per_page'] = absint( $args['per_page'] ); } if ( isset( $args['current_page'] ) ) { $args['current_page'] = absint( $args['current_page'] ); } return $args; } /** * Returns the url of the page which is selected to display search results. * @since BuddyBoss 1.0.0 * @return string url of the serach results page */ public function search_page_url( $value = "" ) { $url = home_url( '/' ); if ( ! empty( $value ) ) { $url = esc_url( add_query_arg( 's', urlencode( $value ), $url ) ); } return $url; } /** * function to return full search url, added with search terms and other filters */ private function search_page_search_url( $default = true ) { if ( true == $this->search_args['forum_search'] ) { //Full search url for bbpress forum search if ( true === $default ) { $base_url = bbp_get_search_url( false ); } else { $base_url = bbp_get_search_url( false ) . $this->search_args['search_term']; } if ( true === $this->search_args['forum_search'] ) { $full_url = esc_url( $base_url ); } else { $full_url = esc_url( add_query_arg( 'bbp_search', urlencode( $this->search_args['search_term'] ), $base_url ) ); } } else { $base_url = $this->search_page_url(); $full_url = esc_url( add_query_arg( 's', urlencode( stripslashes( $this->search_args['search_term'] ) ), $base_url ) ); //for now we only have one filter in url } return $full_url; } public function print_tabs() { // No tabs if 0 results if ( $this->search_results['all']['total_match_count'] < 1 ) { //return; } $search_url = $this->search_page_search_url(); //first print the 'all results' tab $class = 'all' == $this->search_args['search_subset'] ? 'active current selected' : ''; //this filter can be used to change display of 'all' to 'Everything' etc.. $all_label = __( 'All Results', 'buddyboss' ); $label = apply_filters( 'bp_search_label_search_type', $all_label ); if ( $this->search_args['count_total'] && isset( $this->search_results['all'] ) ) { $label .= "" . $this->search_results['all']['total_match_count'] . ""; } $tab_url = $search_url; echo "
  • {$label}
  • "; //then other tabs $search_items = bp_search_items(); foreach ( $this->searchable_items as $item ) { $class = $item == $this->search_args['search_subset'] ? 'active current' : ''; //this filter can be used to change display of 'posts' to 'Blog Posts' etc.. $label = isset ( $search_items[ $item ] ) ? $search_items[ $item ] : $item; $label = apply_filters( 'bp_search_label_search_type', $label ); if ( empty( $this->search_results[ $item ]['total_match_count'] ) ) { continue; //skip tab } if ( $this->search_args['count_total'] ) { $label .= "" . (int) $this->search_results[ $item ]['total_match_count'] . ""; } $tab_url = esc_url( add_query_arg( 'subset', $item, $search_url ) ); echo "
  • {$label}
  • "; } } public function print_results() { if ( $this->has_search_results() ) { $current_tab = $this->search_args['search_subset']; foreach ( $this->search_results[ $current_tab ]['items'] as $item_id => $item ) { echo $item['html']; } if ( $current_tab != 'all' ) { $page_slug = untrailingslashit( str_replace( home_url(), '', $this->search_page_url() ) ); bp_search_pagination_page_counts( $this->search_results[ $current_tab ]['total_match_count'], $this->search_args['per_page'], $this->search_args['current_page'] ); bp_search_pagination( $this->search_results[ $current_tab ]['total_match_count'], $this->search_args['per_page'], $this->search_args['current_page'], $page_slug ); } } else { bp_search_buffer_template_part( 'no-results' ); } } public function get_search_term() { return isset( $this->search_args['search_term'] ) ? $this->search_args['search_term'] : ''; } public function has_search_results() { $current_tab = isset( $this->search_args['search_subset'] ) ? $this->search_args['search_subset'] : ''; return isset( $this->search_results[ $current_tab ]['items'] ) && ! empty( $this->search_results[ $current_tab ]['items'] ); } }

    方法

    问题吗?

    我们总是很乐意帮助您解决代码或其他问题!搜索我们的开发人员文档联络支持,或与我们联系销售团队