I am using a custom woocommerce product search in my wordpress site where it searchs only in product titles. I would like to include the search in category names too. So if someone search a text, and if that's exists in product category name, all those products under that category also need to be listed.
Here is code I am using:
function wc_filter_search_by_title_only( $search, &$wp_query ) {
global $wpdb;
$not_allowed_post_types = apply_filters( 'wc_filter_search_not_allowed_array', array(
'product', //Default WooCommerce products post type
'shop_webhook', //MyStyle Custom post type
) );
if ( empty( $search ) || ! in_array( $wp_query->query_vars['post_type'], $not_allowed_post_types ) ) {
return $search; // skip processing - no search term in query
}
$q = $wp_query->query_vars;
$n = ! empty( $q['exact'] ) ? '' : '%';
$search =
$searchand = '';
foreach ( (array) $q['search_terms'] as $term ) {
$term = esc_sql( $wpdb->esc_like( $term ) );
$search .= "{$searchand}($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";
$searchand = ' AND ';
}
if ( ! empty( $search ) ) {
$search = " AND ({$search}) ";
if ( ! is_user_logged_in() )
$search .= " AND ($wpdb->posts.post_password = '') ";
}
return $search;
}
add_filter( 'posts_search', 'wc_filter_search_by_title_only', 500, 2 );
Kindly let me know if anyway I can implement this.
Thank you in advance.
The easiest way really is to use SearchWP with its WooCommerce extension. Besides, it gives you a lot more functionality than just that.
Related
WP Job Manager doesn’t provide an option for users to search jobs by job title only. This, the results of a job search can be widely off the mark as the search queries the post content by default.
I’ve found some code which works with WordPress posts, it limits the general site search to query post titles only.
My question is, I need it to work with the custom post type for WP Job Manager, which I believe is job_listing. Any thoughts appreciated.
function __search_by_title_only( $search, &$wp_query )
{
global $wpdb;
if ( empty( $search ) )
return $search; // skip processing - no search term in query
$q = $wp_query->query_vars;
$n = ! empty( $q['exact'] ) ? '' : '%';
$search =
$searchand = '';
foreach ( (array) $q['search_terms'] as $term ) {
$term = esc_sql( like_escape( $term ) );
$search .= "{$searchand}($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";
$searchand = ' AND ';
}
if ( ! empty( $search ) ) {
$search = " AND ({$search}) ";
if ( ! is_user_logged_in() )
$search .= " AND ($wpdb->posts.post_password = '') ";
}
return $search;
}
add_filter( 'posts_search', '__search_by_title_only', 500, 2 );
I'm trying to check by a post title if post exist or not.
For some reason when i try something like:
http://domain.com/wp-json/wp/v2/posts?filter[post-title]=table
I want if post with the name table exist, to get the post, if not, get an empty response. But for some reason when post with title not exist i get all posts back.
How could get empty when no post exist and the post when it exist.
Unfortunately it is not possible, but you can use slug instead. Slug is editable part of the URL when writing a post and they can represent title of the page (or it can be changed into this).
http://example.com/wp-json/wp/v2/posts?slug=table
More details:
https://developer.wordpress.org/rest-api/reference/pages/#arguments
According to http://v2.wp-api.org/, some have to use search keyword :
http://domain.com/wp-json/wp/v2/posts?search=table.
You cannot do this through wp json, please copy the following code in the functions.php:
function __search_by_title_only( $search, &$wp_query ) {
global $wpdb;
if ( empty( $search ) )
return $search; // skip processing - no search term in query
$q = $wp_query->query_vars;
$n = ! empty( $q['exact'] ) ? '' : '%';
$search =
$searchand = '';
foreach ( (array) $q['search_terms'] as $term ) {
$term = esc_sql( like_escape( $term ) );
$search .= "{$searchand}($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";
$searchand = ' AND ';
}
if ( ! empty( $search ) ) {
$search = " AND ({$search}) ";
if ( ! is_user_logged_in() )
$search .= " AND ($wpdb->posts.post_password = '') ";
}
return $search;
}
add_filter( 'posts_search', '__search_by_title_only', 500, 2 );
I would like to filter the products on a category products so that it shows only the products of a certain author or multiple authors.
I already have the following code. This works as it filters the products. The correct products are displayed. Except the Woocommerce filters on in the left sidebar are not affected by the filter. The filters on the left side are showing all the original products in the category (also from other users) so the count isn't correct and also attributes from products that are filtered are showing. This shouldn't be the case. Do I have to add another pre_get_posts for the filters?
<?php
function pre_get_posts_by_author( $q ) {
if ( ! $q->is_main_query() ) return;
if ( ! $q->is_post_type_archive() ) return;
$cat_obj = $q->get_queried_object();
if($cat_obj->name == 'Nieuw')
{
$q->set( 'author_ids', '2086,2084');
}
}
add_action( 'pre_get_posts', 'pre_get_posts_by_author' );
add_filter( 'posts_where', 'author_posts_where', 10, 2 );
function author_posts_where( $where, &$wp_query )
{
global $wpdb;
if ( $wp_query->get( 'author_ids' ) ) {
$where .= ' AND ' . $wpdb->posts . '.post_author IN (' . $wp_query->get( 'author_ids' ) .')';
}
return $where;
}
?>
Thanks for helping out!
Probabaly a better way to do this is by setting 'author__in' argument in your query which will take an array of authors the query will return products of.
function pre_get_posts_by_author( $q ) {
if ( ! $q->is_main_query() || !$q->is_post_type_archive() ) return;
$cat_obj = $q->get_queried_object();
if( $cat_obj->name == 'Nieuw' ){
$q->set( 'author__in', array(2086,2084));
}
}
add_action( 'pre_get_posts', 'pre_get_posts_by_author' );
My updated solution: still dirty as it modifies Woocommerce's core files (2.2.4), but it works:
in the pre_get_posts-hook I retrieve the ids of the products I want to exclude with the following code:
$_SESSION['total_excluded'] = get_objects_in_term( $term_ids, $taxonomies, $args )`
(reference: http://codex.wordpress.org/Function_Reference/get_objects_in_term)
Then in woocommerce/includes/widgets/class-wc-widget-layered-nav.php I changed line 258 to:
$count = sizeof( array_diff(array_intersect( $_products_in_term, WC()->query->filtered_product_ids) , $_SESSION['total_excluded'] ) );
In woocommerce/includes/widgets/class-wc-widget-price-filter.php the new lines 121, 136 are:
%1$s.ID IN (' . implode( ',', array_map( 'absint', array_diff(WC()->query->layered_nav_product_ids, $_SESSION['total_excluded'] ) ) ) . ')
In woocommerce/includes/widgets/class-wc-widget-price-filter.php the new lines 123, 138 are:
%1$s.post_parent IN (' . implode( ',', array_map( 'absint', array_diff(WC()->query->layered_nav_product_ids, $_SESSION['total_excluded'] ) ) ) . ')
I've added tags to all Media items with this code:
function wptp_add_tags_to_attachments() {
register_taxonomy_for_object_type( 'post_tag', 'attachment' );
}
add_action( 'init' , 'wptp_add_tags_to_attachments' );
It works great expect one thing. If I search for a media file in the Admin Media Library it does not work with tags.
How can I get the Admin Media Library to include the tags in the search?
You can do this using WordPress action hooks. You need to update the WordPress default search query when searching attachments using hooks posts_where, posts_join and posts_groupby.
Please add below to your themes functions.php
function custom_attachments_join( $join, $query )
{
global $wpdb;
//if we are not on admin or the current search is not on attachment return
if(!is_admin() || (!isset($query->query['post_type']) || $query->query['post_type'] != 'attachment'))
return $join;
// if current query is the main query and a search...
if( is_main_query() && is_search() )
{
$join .= "
LEFT JOIN
{$wpdb->term_relationships} ON {$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id
LEFT JOIN
{$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id = {$wpdb->term_relationships}.term_taxonomy_id
LEFT JOIN
{$wpdb->terms} ON {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_id ";
}
return $join;
}
add_filter( 'posts_join', 'custom_attachments_join', 10, 2 );
function custom_attachments_where( $where, $query )
{
global $wpdb;
//if we are not on admin or the current search is not on attachment return
if(!is_admin() || (!isset($query->query['post_type']) || $query->query['post_type'] != 'attachment'))
return $where;
// if current query is the main query and a search...
if( is_main_query() && is_search() )
{
// explictly search post_tag taxonomies
$where .= " OR (
( {$wpdb->term_taxonomy}.taxonomy IN('post_tag') AND {$wpdb->terms}.name LIKE '%" . $wpdb->escape( get_query_var('s') ) . "%' )
)";
}
return $where;
}
add_filter( 'posts_where', 'custom_attachments_where', 10, 2 );
function custom_attachments_groupby( $groupby, $query )
{
global $wpdb;
//if we are not on admin or the current search is not on attachment return
if(!is_admin() || (!isset($query->query['post_type']) || $query->query['post_type'] != 'attachment'))
return $groupby;
// if current query is the main query and a search...
if( is_main_query() && is_search() )
{
// assign the GROUPBY
$groupby = "{$wpdb->posts}.ID";
}
return $groupby;
}
add_filter( 'posts_groupby', 'custom_attachments_groupby', 10, 2 );
What these functions does is:
custom_attachments_join functions joins term_relationships and term_taxonomy for giving us ability to search for tags
custom_attachments_where function modifies the WordPress default where condition to include our search terms to search for taxonomy or terms fields
custom_attachments_groupby adds group by condition to remove duplicate posts if any.
These functions also check whether we are searching for attachment and if we are performing the search in the WordPress admin area.
Please check with this links for more reference on the hooks I have used.
posts_join
posts_where
posts_groupby
Hope this helps you
This plugin's changelog page says that it searches media tags added by its program:
http://wordpress.org/plugins/media-tags/changelog/
If you're building your own plugin, I recommend grabbing their code and seeing what they're doing. Otherwise, their plugin seems to be exactly what you're looking for.
Unfortunately Sabari's solution doesn't work for the search-form in the "Add Media" - section.
I am using the following function in my functions.php (code based on the "Media Search Enhanced" plugin by Yoren Chang):
function myprefix_posts_clauses( $pieces ) {
global $wp_query, $wpdb;
$vars = $wp_query->query_vars;
if ( empty( $vars ) ) {
$vars = ( isset( $_REQUEST['query'] ) ) ? $_REQUEST['query'] : array();
}
// Rewrite the where clause
if ( ! empty( $vars['s'] ) && ( ( isset( $_REQUEST['action'] ) && 'query-attachments' == $_REQUEST['action'] ) || 'attachment' == $vars['post_type'] ) ) {
$pieces['where'] = " AND $wpdb->posts.post_type = 'attachment' AND ($wpdb->posts.post_status = 'inherit' OR $wpdb->posts.post_status = 'private')";
if ( class_exists('WPML_Media') ) {
global $sitepress;
//get current language
$lang = $sitepress->get_current_language();
$pieces['where'] .= $wpdb->prepare( " AND wpml_translations.element_type='post_attachment' AND wpml_translations.language_code = %s", $lang );
}
if ( ! empty( $vars['post_parent'] ) ) {
$pieces['where'] .= " AND $wpdb->posts.post_parent = " . $vars['post_parent'];
} elseif ( 0 === $vars['post_parent'] ) {
// Get unattached attachments
$pieces['where'] .= " AND $wpdb->posts.post_parent = 0";
}
if ( ! empty( $vars['post_mime_type'] ) ) {
// Use esc_like to escape slash
$like = '%' . $wpdb->esc_like( $vars['post_mime_type'] ) . '%';
$pieces['where'] .= $wpdb->prepare( " AND $wpdb->posts.post_mime_type LIKE %s", $like );
}
if ( ! empty( $vars['m'] ) ) {
$year = substr( $vars['m'], 0, 4 );
$monthnum = substr( $vars['m'], 4 );
$pieces['where'] .= $wpdb->prepare( " AND YEAR($wpdb->posts.post_date) = %d AND MONTH($wpdb->posts.post_date) = %d", $year, $monthnum );
} else {
if ( ! empty( $vars['year'] ) && 'false' != $vars['year'] ) {
$pieces['where'] .= $wpdb->prepare( " AND YEAR($wpdb->posts.post_date) = %d", $vars['year'] );
}
if ( ! empty( $vars['monthnum'] ) && 'false' != $vars['monthnum'] ) {
$pieces['where'] .= $wpdb->prepare( " AND MONTH($wpdb->posts.post_date) = %d", $vars['monthnum'] );
}
}
// search for keyword "s"
$like = '%' . $wpdb->esc_like( $vars['s'] ) . '%';
$pieces['where'] .= $wpdb->prepare( " AND ( ($wpdb->posts.ID LIKE %s) OR ($wpdb->posts.post_title LIKE %s) OR ($wpdb->posts.guid LIKE %s) OR ($wpdb->posts.post_content LIKE %s) OR ($wpdb->posts.post_excerpt LIKE %s)", $like, $like, $like, $like, $like );
$pieces['where'] .= $wpdb->prepare( " OR ($wpdb->postmeta.meta_key = '_wp_attachment_image_alt' AND $wpdb->postmeta.meta_value LIKE %s)", $like );
$pieces['where'] .= $wpdb->prepare( " OR ($wpdb->postmeta.meta_key = '_wp_attached_file' AND $wpdb->postmeta.meta_value LIKE %s)", $like );
// Get taxes for attachements
$taxes = get_object_taxonomies( 'attachment' );
if ( ! empty( $taxes ) ) {
$pieces['where'] .= $wpdb->prepare( " OR (tter.slug LIKE %s) OR (ttax.description LIKE %s) OR (tter.name LIKE %s)", $like, $like, $like );
}
$pieces['where'] .= " )";
$pieces['join'] .= " LEFT JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id";
// Get taxes for attachements
$taxes = get_object_taxonomies( 'attachment' );
if ( ! empty( $taxes ) ) {
$on = array();
foreach ( $taxes as $tax ) {
$on[] = "ttax.taxonomy = '$tax'";
}
$on = '( ' . implode( ' OR ', $on ) . ' )';
$pieces['join'] .= " LEFT JOIN $wpdb->term_relationships AS trel ON ($wpdb->posts.ID = trel.object_id) LEFT JOIN $wpdb->term_taxonomy AS ttax ON (" . $on . " AND trel.term_taxonomy_id = ttax.term_taxonomy_id) LEFT JOIN $wpdb->terms AS tter ON (ttax.term_id = tter.term_id) ";
}
$pieces['distinct'] = 'DISTINCT';
$pieces['orderby'] = "$wpdb->posts.post_date DESC";
}
return $pieces;
}
add_filter( 'posts_clauses', 'myprefix_posts_clauses', 20 );
The solution benedikt works fine, but the language filter is with the wpml plugin.
I use Polylang and looking for the right way to do the same filter, I can not find a solution even with the Polylang documentation...
There is just this part to change :
if ( class_exists('WPML_Media') ) {
global $sitepress;
//get current language
$lang = $sitepress->get_current_language();
$pieces['where'] .= $wpdb->prepare( " AND wpml_translations.element_type='post_attachment' AND wpml_translations.language_code = %s", $lang );
}
by something like that :
if ( function_exists( 'pll_current_language' ) ) {
//get current language
$lang = pll_current_language();
$pieces['where'] .= $wpdb->prepare( here I don't know how to write it... );
}
If someone can help ?
I discovered this custom function in WordPress blog, and it seems to do exactly what I need. The only problem is I don't know what to pass as the second parameter. It's asking for a query but doesn't the query happen INSIDE of this function? What query would I pass it?
I've searched for over an hour and I keep finding similar functions, so it's my WordPress novice coming into play here.
BTW the function is supposed to accept a search term (the first parameter) and return all posts that have titles LIKE the search param.
function custom_search( $search, &$wp_query )
{
global $wpdb;
if ( empty( $search ) )
return $search; // skip processing - no search term in query
$q = $wp_query->query_vars;
$n = ! empty( $q['exact'] ) ? '' : '%';
$search =
$searchand = '';
foreach ( (array) $q['search_terms'] as $term ) {
$term = esc_sql( like_escape( $term ) );
$search .= "{$searchand}($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";
$searchand = ' AND ';
}
if ( ! empty( $search ) ) {
$search = " AND ({$search}) ";
if ( ! is_user_logged_in() )
$search .= " AND ($wpdb->posts.post_password = '') ";
}
return $search;
}
add_filter( 'c_search', 'custom_search', 500, 2 );
Basically the second argument in the function would be a reference. You can read about it at the following link:
http://www.php.net/manual/en/functions.arguments.php
In your case if you remove the second argument for the function about and define
global $wp_query;
And then inside the function the code should still work but you will also have to change the add_filter( 'c_search', 'custom_search', 500, 1 );
Or you can keep the function as is and define the global $wp_query; anywhere in your functions.php, if its not already defined and pass that as the parameter
Actually, you shouldn't need to pass any parameters... the key to that code it's on the last line; what it does it's that it adds a call to a function that will modify the data that it will receive... the arguments for add_filter are:
the point where the data will be filtered
the function that will receive and filter the data
the priority of execution (lower is first)
the number of arguments that the function defined in (2) will receive
so those arguments are always passed on to the function
the filter that code it's referencing it's probably not part of the wordpress core but of some custom plugin, framework or theme
if you want to create a custom query for your own theme/plugin/whatever, take a look at http://codex.wordpress.org/Plugin_API/Filter_Reference/request
You can also make search by following code:
function __search_custom( $search, &$wp_query )
{
global $wpdb;
if ( empty( $search ) )
return $search; // skip processing - no search term in query
$q = $wp_query->query_vars;
$n = ! empty( $q['exact'] ) ? '' : '%';
$search =
$searchand = '';
foreach ( (array) $q['search_terms'] as $term ) {
$term = esc_sql( like_escape( $term ) );
$search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";
$searchand = ' AND ';
}
if ( ! empty( $search ) ) {
$search = " AND ({$search}) ";
if ( ! is_user_logged_in() )
$search .= " AND ($wpdb->posts.post_password = '') ";
}
return $search;
}
add_filter( 'posts_search', '__search_custom', 500, 2 );
if you want to search only by title then replace $search with following code:
$search .= "{$searchand}($wpdb->posts.post_title LIKE '{$n}{$term}{$n}')";