How to create custom taxonomy field searchable? - wordpress

I have added custom taxonomy field on tags, but when I search that field search is not working. Any way to make it searchable in WordPress dashboard?

Here’s the code. You can change $post_type and $custom_fields according to your needs.
function extend_admin_search( $query ) {
// Extend search for document post type
$post_type = 'document';
// Custom fields to search for
/* $custom_fields = array(
"_file_name",
); */
if( ! is_admin() )
return;
if ( $query->query['post_type'] != $post_type )
return;
$search_term = $query->query_vars['s'];
// Set to empty, otherwise it won't find anything
$query->query_vars['s'] = '';
/* if ( $search_term != '' ) {
$meta_query = array( 'relation' => 'OR' );
foreach( $custom_fields as $custom_field ) {
array_push( $meta_query, array(
'key' => $custom_field,
'value' => $search_term,
'compare' => 'LIKE'
));
}
$query->set( 'meta_query', $meta_query );
}; */
$query->set( 's', $search_term );
}
add_action( 'pre_get_posts', 'extend_admin_search' );

Related

Sort orders by paid date in WooCommerce admin order list

I'm trying to sort store orders by date of payment, but there's a problem.
function sp_41964737_custom_product_order( $query ){
global $typenow;
if( is_admin() && $query->is_main_query() && $typenow == 'shop_order' ){
$query->set( 'meta_key', '_date_paid' );
$query->set( 'orderby', 'meta_value_num' );
$query->set( 'order', 'DESC' );
}
}
add_action( 'parse_query', 'sp_41964737_custom_product_order' );
After applying this code, nothing appears in my list of orders except the orders that have paid successfully, so actually only posts that have the _date_paid meta data.
Any advice to get around this?
This is because your current code only shows orders for which the metakey actually exists.
To get around this, you can use:
function action_parse_query( $query ) {
global $pagenow;
// Initialize
$query_vars = &$query->query_vars;
// Only on WooCommerce admin order list
if ( is_admin() && $query->is_main_query() && $pagenow == 'edit.php' && $query_vars['post_type'] == 'shop_order' ) {
// Your meta key
$meta_key = '_date_paid';
// Define an additional meta query
$meta_query[] = array(
'relation' => 'OR',
array(
'key' => $meta_key,
'compare' => 'EXISTS',
),
array(
'key' => $meta_key,
'compare' => 'NOT EXISTS',
)
);
// Set
$query->set( 'orderby', 'meta_value_num' );
$query->set( 'order', 'DESC' );
$query->set( 'meta_query', $meta_query );
}
}
add_action( 'parse_query', 'action_parse_query', 10, 1 );
Proof of concept: the orders for which this meta exists will be displayed first.

WC Vendors - Custom Taxonomy Checklist Not Saving on Front-End

I'm using WC Vendors and have output the taxonomy named "location" on the products using wp_term_checklist per their suggestion. I've got it saving to the product, but it's not saving the checkbox selection on the front-end.
This is the code I've added to the product-edit.php template
$args = array(
'descendants_and_self' => 0,
'selected_cats' => false,
'popular_cats' => false,
'walker' => null,
'taxonomy' => 'location',
'checked_ontop' => false
);
wp_terms_checklist( $my_postid, $args );
$post_to_edit = array(
'ID' => $my_postid,
'tax_input' => array( 'location' => array($_POST['tax_input']['location']) )
);
$pid = wp_update_post($post_to_edit);
if ( isset($_POST['tax_input']['location']) && is_array( $_POST['tax_input']['location'] ) ) {
$location = array_map( 'intval', $_POST['tax_input']['location'] );
$location = array_unique( $location );
wp_set_post_terms($pid, $location, 'location');
}
This is their code where they use a multi-select, but we need checkboxes:
https://gist.github.com/digitalchild/128033d2d41f682acd4387b595d4f607
We have a custom terms checklist called wcv_terms_checklist() in our form helper. It didn't support custom taxonomies but I have modified it to support that now. You can use the following code from v1.7.10 and above to get working custom terms checklists on our front end.
// Output the location checklist
function form_location( $object_id ) {
$args = array(
'taxonomy' => 'location',
);
$field = array(
'id' => 'product_loc_list',
'label' => __( 'Location', 'wcvendors-pro' ),
'class' => 'product_cat_checklist',
);
WCVendors_Pro_Form_Helper::wcv_terms_checklist( $object_id, $args, $field );
}
add_action( 'wcv_after_product_details', 'form_location' );
// Save the terms
function save_location( $post_id ){
if ( isset( $_POST[ 'location' ] ) && is_array( $_POST[ 'location' ] ) ) {
$location = array_map( 'intval', $_POST[ 'location' ] );
$location = array_unique( $location );
wp_set_post_terms( $post_id, $location, 'location' );
}
}
add_action( 'wcv_save_product', 'save_location' );
Gist available here - https://gist.github.com/digitalchild/09e15649425845fef0b8d3af75c79dd1

How to get the first topic in a lesson in learndash

I want to retrieve the first topic in a lesson in learndash and redirect it through it. But for some reason am not sure how to do it.
I checked the API and doesn't see any appropriate filter/hook for it.
Here is my code:
function redirect_to_first_topic() {
// We only want to do this for Topics. But the below code can be adapted to work for Lessons
global $post;
$post_id = $post->ID;
if ( get_post_type( $post_id ) == 'sfwd-lessons' ) {
$progress = learndash_get_course_progress( null, $post_id );
$link = $progress['next'];
$parent_lesson_id = learndash_get_setting( $post, 'topic' );
$parent_lesson = get_post( $parent_lesson_id );
var_dump($parent_lesson);
}
// Always return $link
// return $link;
}
add_action('wp', 'redirect_to_first_topic');
So basically what am doing here is getting the parent which is the lesson.
A bit late, but mb it will help someone else. You can see how to get 1. lesson of a course and go deeper if needed fe. first topic of first lesson and so on :
add_action( 'template_redirect', 'course_overview_redirect' );
function course_overview_redirect() {
global $post;
if ( ! empty( $post ) && $post->post_type == 'sfwd-courses' && ! empty( $post->ID ) ) {
$lessons = learndash_get_course_lessons_list( $post->ID );
if ( ! empty( $lessons ) ) {
$lesson = array_shift( $lessons );
if ( ! empty( $lesson ) ) {
$url = get_permalink( $lesson[ "post" ]->ID );
if ( ! empty( $url ) ) {
wp_redirect( esc_url( $url ) ); // And redirect if needed
exit;
}
}
}
}
}
You can add a button like this;
$args = array(
'posts_per_page' => -1,
'post_type' => 'sfwd-lessons', // you can change here to find topics : 'sfwd-topics'
'suppress_filters' => true,
'fields' => 'ids',
'orderby' => 'menu_order', // ordering by menu_order will show lesson list, in their order in course.
'order' => 'ASC',
// this meta query is used if you want to search a lesson under a course, or if you search for a topic which is in a course but not under a lesson
'meta_query' => array(
array(
'key' => 'course_id',
'value' => $course_id, // this is id of your course
)
// if your topic is under a lesson than you should add lesson meta query
// your meta query should be changed like below
/*
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'course_id',
'value' => $course_id,
),
array(
'key' => 'lesson_id',
'value' => $lesson_id,
),
),
*/
),
);
$all_lessons = get_posts($args);
$first_lesson = $all_lessons[0]; // taking directly first element of array
$button_html = '' . __( 'Start the course', 'custom-text' ) . '';

Search with only meta Key in 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' );

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