Search with only meta Key in Wordpress - wordpress

I need help to make a query to customize the default wordpress searching. I don't want to include title or content or excerpt in wordpress searching but want to search based on meta value of that post.
In default wordpress search wordpress add meta query in "AND" Condition. If there is a way if meta query add in or condition it will also be fine.
Please Help

If you're referring to changing the main query on search results pages (e.g. http://example.com/?s=hello), then try one of these options:
Option #1
This is for:
I don't want to include title or content or excerpt in wordpress
searching
Hook to pre_get_posts and empty the s parameter.
add_action( 'pre_get_posts', function( $wp_query ){
if ( $wp_query->is_main_query() && $wp_query->is_search() ) {
$wp_query->set( 's', '' );
}
});
Option #2
This is for:
In default wordpress search wordpress add meta query in "AND"
Condition. If there is a way if meta query add in or condition it will
also be fine.
Hook to get_meta_sql and substitute the AND with OR.
add_filter( 'get_meta_sql', function( $sql, $meta_query, $type, $primary_table ){
global $wpdb;
if (
'post' === $type &&
$wpdb->posts === $primary_table &&
is_main_query() && is_search()
) {
if ( $sql['where'] && ' AND (' === substr( $sql['where'], 0, 6 ) ) {
$sql['where'] = ' OR ' . substr( $sql['where'], 5 );
}
}
return $sql;
}, 10, 4 );
Option #3
Create a custom search page and use a custom WP_Query instance for querying the posts.
$q = new WP_Query([
'meta_key' => 'some_key',
'meta_value' => 'some_value',
// Or use meta_query
]);
Options #1 and #2 are both tricky and may conflict with plugins on your site, or any custom code which modifies the search-related parameters/queries. Or even standard queries. So use the code at your very own risks.
Hope that helps..

I create a ajax from where I send the input text as "search_text" and check the text is feature or not from meta_key "job_is_featured" value which is store in postmeta. and also check into custom post type category id.
$catids = '22';
$args = array(
'post_type' => 'job', 'order' => 'DESC','posts_per_page' => '-1','s' => 'search_text' ,'orderby' => 'meta_value',
'tax_query' => array(
array(
'taxonomy' => 'job-category',
'field' => 'term_id',
'terms' => $catids,
),
),
'meta_query' => array(
'relation' => 'AND',
array(
'relation' => 'OR',
array(
'key' => 'job_is_featured',
'value' => 1,
'compare' => '=',
),
array(
'key' => 'job_is_featured',
'value' => 0,
'compare' => '=',
),
),
array(
'key' => 'job_location',
'value' => 'search_text',
'compare' => 'LIKE',
),
),
);
$the_query = new WP_Query( $args );

Here is the code which you need to add in functions.php
This code will work with Post Meta and Taxonomy both
if(!function_exists('custom_wp_meta_and_tax_search')){
function custom_wp_meta_and_tax_search($search_args){
/* taxonomy query and meta query arrays */
$tax_query = array();
$meta_query = array();
/* Keyword Based Search */
if( isset ( $_GET['keyword'] ) ) {
$keyword = trim( $_GET['keyword'] );
if ( ! empty( $keyword ) ) {
$search_args['s'] = $keyword;
}
}
/* Custom Meta Key Parameter */
if( isset($_GET['meta_input']) && ($_GET['meta_input'] != 'any')){
$meta_query[] = array(
'key' => 'custom_meta_key',
'value' => $_GET['meta_input'],
'compare' => 'like',
);
}
$min_value = '';
$max_value = '';
if(isset($_GET['min-value']) && $_GET['min-value'] <> 'any'){
$min_value = $_GET['min-value'];
}
if(isset($_GET['max-value']) && $_GET['max-value'] <> 'any'){
$max_value = $_GET['max-value'];
}
/* Logic for Min and Max value Parameters */
/* You need to replace custom_tax with custom taxonomy */
if( isset($min_value) && ($min_value != 'any') && isset($max_value) && ($max_value != 'any') ){
$min_value = doubleval($min_value);
$max_value = doubleval($max_value);
if( $min_value >= 0 && $max_value > $min_value ){
$meta_query[] = array(
'key' => 'custom_tax',
'value' => array( $min_value, $max_value ),
'type' => 'NUMERIC',
'compare' => 'BETWEEN'
);
}
}else if( isset($min_value) && ($min_value != 'any') ){
$min_value = doubleval($min_value);
if( $min_value > 0 ){
$meta_query[] = array(
'key' => 'custom_tax',
'value' => $min_value,
'type' => 'NUMERIC',
'compare' => '>='
);
}
}else if( isset($max_value) && ($max_value != 'any') ){
$max_value = doubleval($max_value);
if( $max_value > 0 ){
$meta_query[] = array(
'key' => 'custom_tax',
'value' => $max_value,
'type' => 'NUMERIC',
'compare' => '<='
);
}
}
// /* if more than one taxonomies exist then specify the relation */
$tax_count = count( $tax_query );
if( $tax_count > 1 ){
$tax_query['relation'] = 'AND';
}
/* if more than one meta query elements exist then specify the relation */
$meta_count = count( $meta_query );
if( $meta_count > 1 ){
$meta_query['relation'] = 'AND';
}
if( $tax_count > 0 ){
$search_args['tax_query'] = $tax_query;
}
/* if meta query has some values then add it to base home page query */
$search_args['meta_query'] = $meta_query;
/* Sort By meta value */
/* You need to replace "custom_meta_key" with the key of custom field you created with post. */
if( (isset($min_value) && ($min_value != 'any')) || ( isset($max_value) && ($max_value != 'any') ) ){
$search_args['orderby'] = 'meta_value_num';
$search_args['meta_key'] = 'custom_meta_key';
$search_args['order'] = 'ASC';
}
return $search_args;
}
}
add_filter('custom_search_parameters','custom_wp_meta_and_tax_search');
Now Run the Query and Filter your posts with Post Meta and taxonomy
$custom_search_args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'paged' => $paged,
);
$custom_search_args = apply_filters('custom_search_parameters',$custom_search_args);
$search_query = new WP_Query( $custom_search_args );

Add this in function.php
add_action( 'pre_get_posts', function( $q )
{
if( $title = $q->get( '_meta_or_title' ) )
{
add_filter( 'get_meta_sql', function( $sql ) use ( $title )
{
global $wpdb;
// Only run once:
static $nr = 0;
if( 0 != $nr++ ) return $sql;
// Modified WHERE
$sql['where'] = sprintf(
" AND ( %s OR %s ) ",
$wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $title),
mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
);
return $sql;
});
}
});
Usage
$meta_query = array();
$args = array();
$search_string = "test";
$meta_query[] = array(
'key' => 'staff_name',
'value' => $search_string,
'compare' => 'LIKE'
);
$meta_query[] = array(
'key' => 'staff_email',
'value' => $search_string,
'compare' => 'LIKE'
);
//if there is more than one meta query 'or' them
if(count($meta_query) > 1) {
$meta_query['relation'] = 'OR';
}
// The Query
$args['post_type'] = "staff";
$args['_meta_or_title'] = $search_string; //not using 's' anymore
$args['meta_query'] = $meta_query;
$the_query = new WP_Query($args)

if ( $query->is_search())
{
$meta_query = $query->get( 'meta_query' );
//print_r($meta_query);
$meta_query[] = array('key' => '_product_attributes', /* Product Attribute Meta key Here example (_sku, _stock, _stock_status, height, width ) */
'value' => $city,
'compare' => 'LIKE');
$query->set( 'meta_query', $meta_query );
}
}
}
add_action( 'woocommerce_product_query' , 'Add_custom_search2' );

Related

How Can I Order The Results Of Meta Query? - woocommerce_product_query_meta_query

I have the following code:
function custom_meta_query( $meta_query ){
$rem_width = get_query_var('rem_width');
$rem_length = get_query_var('rem_length');
$meta_query[] = array( 'key'=>'remnant_width', 'value' => $rem_width, 'compare'=>'>=');
$meta_query[] = array( 'key'=>'remnant_length', 'value' => $rem_length, 'compare'=>'>=');
$meta_query['relation'] = 'AND';
return $meta_query;
}
// The main shop and archives meta query
add_filter( 'woocommerce_product_query_meta_query', 'custom_product_query_meta_query', 10, 2 );
function custom_product_query_meta_query( $meta_query, $query ) {
if( (! is_admin() ) && ((isset($_GET['rem_width'])) || (isset($_GET['rem_length']) ) ))
return custom_meta_query( $meta_query );
}
I want to order the products returned by width and currently it is showing alphabetical order.
'orderby' => 'meta_value_num',
'meta_key' => 'remnant_width',
'order' => 'ASC'
But I don't know how to incorporate it into what has gone before.
Thanks

Woocommerce > Hide products that are out of stock BUT skip products with certain tag

I would like to hide products that are out of stock on archive pages.
But products containing tag "backorder" should be skipped.
I tried many options but the problem is that I can't combine meta_query and tax_query to do this.
Does anyone have suggestion on how to do this?
This is my current status:
add_filter( 'woocommerce_product_query_meta_query', 'shop_only_instock_products', 10, 2 );
function shop_only_instock_products( $meta_query, $query ) {
if( is_admin() || is_search() || ! is_shop()) return $meta_query;
$meta_query[] = array(
'key' => '_stock_status',
'value' => 'outofstock',
'compare' => '!='
);
print_r($meta_query);
}
add_filter( 'woocommerce_product_query_tax_query', 'filter_products_with_specific_product_tags', 9, 2 );
function filter_products_with_specific_product_tags( $tax_query, $query ) {
if( is_admin() || is_search() || ! is_shop()) return $tax_query;
$tax_query[] = array(
'taxonomy' => 'product_tag',
'field' => 'name',
'terms' => array('backorder'),
);
return $tax_query;
};
You can try woocommerce_product_query hook. I've not tested this code yet.
add_action( 'woocommerce_product_query', 'action_product_query', 10, 2 );
function action_product_query( $q, $query ) {
// Ignore this condition and test the behind codes firstly
// if( is_admin() || is_search() || ! is_shop()) return;
// Get any existing Tax query
$tax_query = $q->get( 'tax_query');
// Get any existing meta query
$meta_query = $q->get( 'meta_query');
// Define an additional tax query
$tax_query = array(
'taxonomy' => 'product_tag',
'field' => 'name', // backorder looks like slug
'terms' => array('backorder'),
'compare' => 'IN',
);
// Define an additional meta query
$meta_query = array(
'key' => '_stock_status',
'value' => 'outofstock',
'compare' => '!=',
);
// Set the new merged tax query
$q->set( 'tax_query', $tax_query );
// Set the new merged meta query
$q->set( 'meta_query', $meta_query );
}
You should use on backorder setting in your product inverntory. Set Out of stock visibility to true in your Woocommerce > Settings > Product > Inventory . You dont need any additional code for this.

Pagenavi by multiple field search wordpress

I am using the pagenavi plugin and mutiple search by taxonomy and acf custom field. However pagenavi is not working on the query search.
add_filter( 'pre_get_posts','nt_custom_search_filter');
function nt_custom_search_filter( $query ) {
if( $query->is_search && !is_admin() ) {
if( isset($_GET['s'] ) ) {
$query->set( 'post_type', array( 'product' ) );// box text search
}
if( $query->is_main_query() ) {
$args[] = array( 'relation' => 'AND' );
if( isset( $_GET[ 'product_cat' ] ) && $_GET[ 'product_cat' ] != 'all' ) {
$args[] =
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $_GET['product_cat']
);
}$query->set( 'tax_query', $args );
$meta_query = array( 'relation' => 'AND' );
if( isset( $_GET[ 'status' ] ) && $_GET[ 'status' ] != 'all' ) {
$meta_query[] = array(
'key' => 'status',
'value' => $_GET['status'],
'compare' => '='
);
}
$query->set( 'meta_query', $meta_query );
}
}
return $query;}
To solve possible problems with an incorrect calculation of the pagination in WP_Query, you need three additional arguments: posts_per_page, paged and offset
In $count we save the number of posts per page, or just use the default which you have set in your wordpress backend under the settings.
$paged tells us which page the user is currently on.
With $offset you calculate how many contributions the loop should be moved.
So you can adjust the $args[] in your $query. Code can look like:
$count = get_option('posts_per_page', 25); // get 25 posts
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$offset = ($paged - 1) * $count;
$args = array (
'posts_per_page' => $count,
'paged' => $paged,
'offset' => $offset,
'relation' => 'AND'
.
. /* other arguments */
:
);
Edit:
so your code can look like the following. Please notice, that the code is not tested.
add_filter( 'pre_get_posts','nt_custom_search_filter');
function nt_custom_search_filter( $query ) {
if( $query->is_search && !is_admin() ) {
if( isset($_GET['s'] ) ) {
$query->set( 'post_type', array( 'product' ) );// box text search
}
if( $query->is_main_query() ) {
$count = get_option('posts_per_page', 25); // get 25 posts
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$offset = ($paged - 1) * $count;
$args[] = array( 'posts_per_page' => $count, 'paged' => $paged, 'offset' => $offset, 'relation' => 'AND' );
if( isset( $_GET[ 'product_cat' ] ) && $_GET[ 'product_cat' ] != 'all' ) {
$args[] =
array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $_GET['product_cat']
);
}$query->set( 'tax_query', $args );
$meta_query = array( 'relation' => 'AND' );
if( isset( $_GET[ 'status' ] ) && $_GET[ 'status' ] != 'all' ) {
$meta_query[] = array(
'key' => 'status',
'value' => $_GET['status'],
'compare' => '='
);
}
$query->set( 'meta_query', $meta_query );
}
}
return $query;}

Issue with function and post ID

I am using the following function/shortcode in order to output an average global rating using ACF :
function get_average_rating($post_id) {
$rating_sum = 0;
$reviews_of_post = get_posts( array(
'post_type' => 'avis',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'produit',
'value' => $post_id,
'compare' => '=',
),
),
) );
if ( empty( $reviews_of_post ) ) {
return 0;
}
foreach ( $reviews_of_post as $review ) {
$rating_sum += get_field( 'note_client', 'post_' . $review->ID);
}
return number_format((float)($rating_sum / count( $reviews_of_post )),1, ',', '');
}
add_shortcode( 'note-clients', 'get_average_rating');
It always return 0 except when I manually input the post ID like :
'meta_query' => array(
array(
'key' => 'produit',
'value' => 1234,
'compare' => '=',
),
),
How can I fix this ?
Thanks a lot !
Declare global $post; before your function.
Wordpress uses $post for many of its functions within the loop.
To avoid any conflicts later you should consider use of wp_reset_query
1 . Change key 'key' => 'produit' to 'key' => 'product',
2 .
foreach ( $reviews_of_post as $review ) {
$rating_sum += get_field( 'note_client', 'post_' . $review->ID);
}
**to**
foreach ( $reviews_of_post as $review ) {
$post_id = 'post_' . $review->ID ;
$rating_sum += get_field( 'note_client', $post_id );
}
Confirm ACF key (note_client) is correct
3 . Change this
add_shortcode( 'note-clients', 'get_average_rating');
to
add_shortcode( 'average_rating', 'get_average_rating');
Please try with your post static id:
$post_id = 9; //add here your static post id
$reviews_of_post = get_posts( array(
'post_type' => 'avis',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'produit',
'value' => $post_id,
'compare' => '=',
),
),
) );

2 pre_get_posts functions to filter by custom fields

EDIT: See the last (3rd) code snippet, it's the working one.
I have an "Actions" page (an archive for a custom post type called Actions), which is an equivalent to "events".
I used this tutorial to filter them with custom fields: ville (city), action (type of action) and date and it works perfectly.
Then I created another function to filter by "date range": past, future actions. And it also works. But they "accumulate". When I select "Past" actions and a city, it shows me ALL past actions + ALL actions that happened or will happen in a city.
So these two functions work, but I don't know how to set their relation to AND or something that makes them work together instead of "accumulating".
Can someone please help me figure this out ?
Thank you.
Function to filter by Type/City/Date custom fields:
// array of filters (field key => field name)
$GLOBALS['my_query_filters'] = array(
'action' => 'action',
'ville' => 'ville',
'date' => 'date',
);
// action
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
function my_pre_get_posts( $query ) {
// bail early if is in admin
if( is_admin() ) return;
// bail early if not main query
// - allows custom code / plugins to continue working
if( !$query->is_main_query() ) return;
// get meta query
$meta_query = $query->get('meta_query');
// loop over filters
foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
// continue if not found in url
if( empty($_GET[ $name ]) ) {
continue;
}
// get the value for this filter
// eg: http://www.website.com/events?city=melbourne,sydney
$value = explode(',', $_GET[ $name ]);
// append meta query
$meta_query[] = array(
'key' => $name,
'value' => $value,
'compare' => 'IN',
);
}
$query->set( 'orderby', array( 'date' => 'DESC' ) );
// update meta query
$query->set('meta_query', $meta_query);
return;
}
?>
Function for Future/Past actions:
<?php
add_action('pre_get_posts', 'future_past_actions', 10, 1);
function future_past_actions( $query ) {
// bail early if is in admin
if( is_admin() ) return;
// bail early if not main query
// - allows custom code / plugins to continue working
if( !$query->is_main_query() ) return;
// get meta query
$meta_query = $query->get('meta_query');
if( isset($_GET['range']) ) {
$range = explode(',', $_GET['range']);
$meta_query[] = array(
'key' => 'range',
'value' => $range,
'compare' => 'IN',
);
if( $query->get( 'range' ) == 'future' ) {
$meta_query[] = array(
'key' => 'date',
'value' => date("Ymd"),
'compare' => '>',
);
$meta_query['relation'] = 'OR';
}
elseif( $query->get( 'range' ) == 'past' ) {
$meta_query[] = array(
'key' => 'date',
'value' => date("Ymd"),
'compare' => '<',
);
$meta_query['relation'] = 'OR';
}
elseif( $query->get( 'range' ) == 'toutes' ) {
return;
}
}
$query->set( 'meta_key', 'date' );
$query->set( 'orderby', array( 'date' => 'DESC' ) );
$query->set('meta_query', $meta_query);
return;
}
?>
The final merged and working code:
<?php
// array of filters (field key => field name)
$GLOBALS['my_query_filters'] = array(
'action' => 'action',
'ville' => 'ville',
'date' => 'date'
);
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
function my_pre_get_posts( $query ) {
// bail early if is in admin
if( is_admin() ) return;
// bail early if not main query
// - allows custom code / plugins to continue working
if( !$query->is_main_query() ) return;
if( ! is_post_type_archive( 'actions' ) ) return;
// CITY/TYPE/DATE filters
// loop over filters
foreach( $GLOBALS['my_query_filters'] as $key => $name ) {
// continue if not found in url
if( empty($_GET[ $name ]) ) { continue; }
// get the value for this filter
// eg: http://www.website.com/events?city=melbourne,sydney
$value = explode(',', $_GET[ $name ]);
// append meta query
$meta_query[] = array(
'key' => $name,
'value' => $value,
'compare' => 'IN',
);
}
// FUTURE/PAST/ALL filters
if( isset($_GET['range']) ) {
$range = $_GET['range'];
if($range != "toutes") {
// Select what kind of compare you need
if($range == "past") {
$comparer = '<';
} else if($range == "future") {
$comparer = '>=';
}
// If you need to filter by date add this to meta_query array
$meta_query[] = array(
'key' => 'date',
'value' => date("Ymd"),
'compare' => $comparer,
);
}
}
// update meta query
$query->set('meta_query', $meta_query);
$query->set( 'meta_key', 'date' );
$query->set( 'orderby', array( 'date' => 'DESC' ) );
$query->set('posts_per_page', '20');
}
?>
In this case best solution in my opinion is to have one action and check query arguments inside of it and then decide what kind of logic you want to do.
$query variable has all the arguments you assign, so your code might look something like this:
Editing considering the comments on situation, you have to use AND relation between two meta fields. Code inside action should look like this:
add_action('pre_get_posts', 'my_pre_get_posts', 10, 1);
function my_pre_get_posts( $query ) {
$meta_query = array(
'relation' => 'AND',
array(
'key' => 'ville',
'value' => '$value',
'compare' => '=',
)
);
// Select what kind of compare you need
if($range == "past") {
$compare = ">";
} else if($range == "future") {
$compare = "<";
}
if($range != "all") {
// If you need to filter by date add this to meta_query array
$date_query = array(
'key' => 'date',
'value' => 'date(\"Ymd\"),',
'compare' => $compare,
);
$meta_query[] = $date_query;
}
$query->set( 'orderby', array( 'date' => 'DESC' ) );
// update meta query
$query->set('meta_query', $meta_query);
}
Because what you do now, you set query arguments multiple times.
If you need more parameters to filter out you can add them conditionally to $meta_query variable considering what kind of parameters you get.
I think if I understand correctly this kind of meta query should return needed results.

Resources