feat: refact general search

This commit is contained in:
vnmedeiros 2022-11-11 00:31:08 -03:00
parent 310ca1ed02
commit 0b562f0797
3 changed files with 89 additions and 64 deletions

View File

@ -93,7 +93,8 @@ class REST_Controller extends \WP_REST_Controller {
'hierarchical' => 'hierarchical',
'exclude' => 'post__not_in',
'excludetree' => 'exclude_tree',
'include' => 'include'
'include' => 'include',
'sentence' => 'sentence'
];
$meta_query = [
@ -312,6 +313,12 @@ class REST_Controller extends \WP_REST_Controller {
'validate_callback' => 'rest_validate_request_arg',
);
$query_params['sentence'] = array(
'description' => __( 'Whether to search by phrase. Default false.', 'tainacan' ),
'type' => 'boolean',
'default' => true,
);
$query_params['authorid'] = array(
'description' => __("Limit result set to objects assigned to specific authors by id.", 'tainacan'),
'type' => 'integer',

View File

@ -53,9 +53,21 @@ class Elastic_Press {
//https://www.elasticpress.io/blog/2019/02/custom-search-with-elasticpress-how-to-limit-results-to-full-text-matches/
if ( ! empty( $formatted_args['query']['bool']['should'] ) ) {
$formatted_args['query']['bool']['must'] = $formatted_args['query']['bool']['should'];
$formatted_args['query']['bool']['must'][0]['multi_match']['operator'] = 'AND';
$formatted_args["query"]["bool"]["must"][0]["multi_match"]["type"] = "phrase_prefix";
// $formatted_args['query']['bool']['must'][0]['multi_match']['operator'] = 'AND';
if ( isset($formatted_args['query']['bool']['must'][0]['multi_match']['operator']))
unset($formatted_args['query']['bool']['must'][0]['multi_match']['operator']);
if ( isset($formatted_args['query']['bool']['must'][1]['multi_match']['operator']))
unset($formatted_args['query']['bool']['must'][1]['multi_match']['operator']);
if ( isset($formatted_args['query']['bool']['must'][2]['multi_match']['operator']))
unset($formatted_args['query']['bool']['must'][2]['multi_match']['operator']);
if ( isset($formatted_args['query']['bool']['must'][2]) ) {
$formatted_args['query']['bool']['must'][2]['multi_match']['analyzer'] = 'default';
}
unset( $formatted_args['query']['bool']['should'] );
unset( $formatted_args["query"]["bool"]["must"][0]["multi_match"]["type"] );
}
/**
@ -63,22 +75,22 @@ class Elastic_Press {
* Elasticsearch is not good a substring matches similar to SQL like.
* here we replace `match_phrase` with` wildcard`, but this is not an efficient operation.
*/
if ( ! empty( $formatted_args['post_filter']['bool']['must'] ) ) {
$array_must = $formatted_args['post_filter']['bool']['must'];
for($i = 0; $i < count($array_must); $i++ ) {
$el_must = $array_must[$i];
if( ! empty($el_must['bool']['must']) ) {
$array_must_nested = $el_must['bool']['must'];
for($j = 0; $j < count($array_must_nested); $j++ ) {
if ( isset ($array_must_nested[$j]['match_phrase'] ) ) {
$formatted_args['post_filter']['bool']['must'][$i]['bool']['must'][$j]['match_phrase_prefix'] =
array_map( function($match) { return "$match"; } ,$array_must_nested[$j]['match_phrase']);
unset($formatted_args['post_filter']['bool']['must'][$i]['bool']['must'][$j]['match_phrase']);
}
}
}
}
}
// if ( ! empty( $formatted_args['post_filter']['bool']['must'] ) ) {
// $array_must = $formatted_args['post_filter']['bool']['must'];
// for($i = 0; $i < count($array_must); $i++ ) {
// $el_must = $array_must[$i];
// if( ! empty($el_must['bool']['must']) ) {
// $array_must_nested = $el_must['bool']['must'];
// for($j = 0; $j < count($array_must_nested); $j++ ) {
// if ( isset ($array_must_nested[$j]['match_phrase'] ) ) {
// $formatted_args['post_filter']['bool']['must'][$i]['bool']['must'][$j]['match_phrase_prefix'] =
// array_map( function($match) { return "$match"; } ,$array_must_nested[$j]['match_phrase']);
// unset($formatted_args['post_filter']['bool']['must'][$i]['bool']['must'][$j]['match_phrase']);
// }
// }
// }
// }
// }
return $formatted_args;
} );

View File

@ -60,7 +60,7 @@ class Search_Engine {
// added slashes screw with quote grouping when done early, so done later
$s = stripslashes( $s );
if ( $sentence ) {
$search_terms = array( $s );
$search_terms = array( trim($s, " '\"\n\r\t\v\0") );
} else {
preg_match_all( '/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $s, $matches );
@ -116,7 +116,7 @@ class Search_Engine {
}
}
private function build_search_terms_query ($type = 'default') {
function get_where_to_title_and_content() {
global $wpdb;
$searchQuery = '';
$seperator = '';
@ -124,62 +124,68 @@ class Search_Engine {
$terms = $this->get_search_terms();
foreach ( $terms as $term ) {
$esc_term = $wpdb->prepare("%s", $not_exact ? "%".$term."%" : $term);
switch ($type) {
case 'tax_terms':
$searchQuery .= "{$seperator}(tter.name LIKE {$esc_term})";
break;
case 'meta_terms':
if (defined('TAINACAN_SEARCH_ENGINE_USING_FULL_TEXT') && TAINACAN_SEARCH_ENGINE_USING_FULL_TEXT === true) {
$esc_term = $wpdb->prepare("%s", $not_exact ? "*".$term."*" : $term);
$searchQuery .= "{$seperator}(MATCH (m.meta_value) AGAINST ({$esc_term} IN BOOLEAN MODE))";
} else {
$searchQuery .= "{$seperator}(m.meta_value LIKE {$esc_term})";
}
break;
default:
if ( !empty( $this->relationships ) ) {
$searchQuery .= "{$seperator}($wpdb->posts.post_title LIKE {$esc_term} OR $wpdb->posts.post_content LIKE {$esc_term} OR p2->posts.post_title LIKE {$esc_term} OR p2.post_content LIKE {$esc_term})";
} else {
$searchQuery .= "{$seperator}($wpdb->posts.post_title LIKE {$esc_term} OR $wpdb->posts.post_content LIKE {$esc_term})";
}
break;
}
$seperator = ' OR ';
$seperator = ' AND ';
}
return empty($searchQuery) ? false : "($searchQuery)";
}
function get_where_to_term_taxonomies() {
if ( $this->is_tainacan_search && !empty( $this->taxonomies ) ) {
global $wpdb;
$join = '';
$searchTaxQuery = $this->build_search_terms_query('tax_terms');
if ( $searchTaxQuery != false && $this->is_tainacan_search && !empty( $this->taxonomies ) ) {
$search_tax_query = '';
$seperator = '';
$not_exact = empty($this->query_instance->query_vars['exact']);
$terms = $this->get_search_terms();
foreach ( $terms as $term ) {
$esc_term = $wpdb->prepare("%s", $not_exact ? "%".$term."%" : $term);
$search_tax_query .= "{$seperator}(tter.name LIKE {$esc_term})";
$seperator = ' AND ';
}
if (empty($search_tax_query)) return '';
$tax_where = ' ttax.taxonomy IN ( \'' . implode( '\',\'', $this->taxonomies ) . '\' ) ';
$join = "EXISTS (
return "EXISTS (
SELECT trel.object_id
FROM
$wpdb->term_relationships AS trel
INNER JOIN $wpdb->term_taxonomy AS ttax ON trel.term_taxonomy_id = ttax.term_taxonomy_id
INNER JOIN $wpdb->terms AS tter ON ttax.term_id = tter.term_id
WHERE
$wpdb->posts.ID = trel.object_id AND $tax_where AND ( $searchTaxQuery )
$wpdb->posts.ID = trel.object_id AND $tax_where AND ( $search_tax_query )
)";
}
return $join;
return '';
}
function get_where_to_metadatas() {
if ( $this->is_tainacan_search ) {
global $wpdb;
$join = "";
$searchMetaQuery = $this->build_search_terms_query('meta_terms');
if ( $searchMetaQuery != false && $this->is_tainacan_search ) {
$join .= "EXISTS (
$search_meta_query = '';
$seperator = '';
$not_exact = empty($this->query_instance->query_vars['exact']);
$terms = $this->get_search_terms();
foreach ( $terms as $term ) {
$esc_term = $wpdb->prepare("%s", $not_exact ? "%".$term."%" : $term);
$search_meta_query .= "{$seperator}(m.meta_value LIKE {$esc_term})";
$seperator = ' AND ';
}
if ( empty($search_meta_query) ) return '';
$join = \is_user_logged_in()
? ''
: " INNER JOIN $wpdb->posts pmeta ON m.meta_key = pmeta.ID AND pmeta.post_status = 'publish'";
return "EXISTS (
SELECT m.post_id
FROM $wpdb->postmeta m
WHERE ( $wpdb->posts.ID = m.post_id AND $searchMetaQuery )
FROM $wpdb->postmeta m $join
WHERE ( $wpdb->posts.ID = m.post_id AND $search_meta_query )
)";
}
return $join;
return '';
}
// add where clause to the search query
@ -195,16 +201,16 @@ class Search_Engine {
if ( !$this->is_tainacan_search && !$this->ajax_request)
return $where;
$searchQuery = $this->build_search_terms_query();
$searchTaxQuery = $this->get_where_to_term_taxonomies();
$searchMetaQuery = $this->get_where_to_metadatas();
$searchQuery = "($searchQuery) ";
if(!empty($searchTaxQuery)) $searchQuery .= " OR ($searchTaxQuery) ";
if(!empty($searchMetaQuery)) $searchQuery .= " OR ($searchMetaQuery) ";
$search_query = $this->get_where_to_title_and_content();
$search_tax_query = $this->get_where_to_term_taxonomies();
$search_meta_query = $this->get_where_to_metadatas();
$search_query = "($search_query) ";
if(!empty($search_tax_query)) $search_query .= " OR ($search_tax_query) ";
if(!empty($search_meta_query)) $search_query .= " OR ($search_meta_query) ";
if ( $searchQuery != '' && $searchQuery != '()' ) {
if ( $search_query != '' && $search_query != '()' ) {
// lets use _OUR_ query instead of WP's, as we have posts already included in our query as well(assuming it's not empty which we check for)
$where = " AND ((" . $searchQuery . ")) ";
$where = " AND ((" . $search_query . ")) ";
}
return $where;
}