BP_Search::do_search( mixed $args = '' )
Perform search and generate search results
Description
Parameters
- $args
-
(Optional)
Default value: ''
Source
File: bp-search/classes/class-bp-search.php
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 = "<div class='results-group results-group-{$type} " . apply_filters( 'bp_search_class_search_wrap', 'bp-search-results-wrap', $label ) . "'>" . "<header class='results-group-header clearfix'>" . "<h3 class='results-group-title'><span>" . apply_filters( 'bp_search_label_search_type', $label ) . "</span></h3>" . "<span class='total-results'>" . sprintf( _n( '%d result', '%d results', $total_results, 'buddyboss' ), $total_results ) . "</a>" . "</header>" . "<ul id='{$type}-stream' class='item-list {$type}-list bp-list " . apply_filters( 'bp_search_class_search_list', 'bp-search-results-list', $label ) . "'>"; $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 = "</ul>"; if ( $total_results > 3 ) { $end_html .= "<footer class='results-group-footer'>"; $end_html .= "<a href='" . $category_search_url . "' class='view-all-link'>" . sprintf( esc_html__( 'View (%d) more', 'buddyboss' ), $total_results - $args['number'] ). "</a>"; $end_html .= "</footer>"; } $end_html .= "</div>"; $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 = "<div class='results-group results-group-{$args['search_subset']} " . apply_filters( 'bp_search_class_search_wrap', 'bp-search-results-wrap', $args['search_subset'] ) . "'>" . "<ul id='{$args['search_subset']}-stream' class='item-list {$args['search_subset']}-list bp-list " . apply_filters( 'bp_search_class_search_list', 'bp-search-results-list', $args['search_subset'] ) . "'>"; $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 = "</ul></div>"; $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; } }
Changelog
Version | Description |
---|---|
BuddyBoss 1.0.0 | Introduced. |
Questions?
We're always happy to help with code or other questions you might have! Search our developer docs, contact support, or connect with our sales team.