Include postmeta in WordPress search - wordpress

How can I tell the default WordPress search function to also look at the postmeta data?
For example, I have a postameta key called 'item_number' and if someone searches '113', I'd like for it to check the key's value as well as the post content.
Thanks!

A quick and dirty way to include meta values inside your searching scope: you can hook into pre_get_posts and add a meta_query like this:
Inside your functions.php:
add_filter( 'pre_get_posts', 'so_9224493_adjust_search_query');
function so_9224493_adjust_search_query( $query ) {
if ( !is_admin() && $query->is_search ) { //the !is_admin() boolean ensures that this does not affect your dashboard
$meta_query_arguments = array(
array(
'key' => 'item_number', //this is where you would put your meta key
'value' => $query->query_vars['s'],
'compare' => 'LIKE',
),
);
$query->set('meta_query', $meta_query_arguments);
};
}
The only problem with this route is that it will include the meta query so that your search query will only match posts that include the search term inside the Title/Content/Excerpt and the meta field, which might not be preferable for you.

You must replace your Wordpress search function with your own. Check this answer.

Very simple workaround: put all meta values you want to be searchable into post_exerpt field (use save_post action), so they will be found without any search modifications.

This site provided the answer I was looking for:
http://flav36rs.com/2010/03/15/extend-wordpress-search-to-include-custom-post-meta/
There are some helpful comments below the tutorial worth looking at if you run into problems.
EDIT:
The above link is dead.
Ultimately, I ended up writing a complete custom search query using JOINS to build the query I needed.

Related

Add word to custom taxonomy slug in WordPress

I want to add a specific word to every taxonomy archive.
I've this domain:
http://example.com/brand/nike/
And I want it to look like this:
http://example.com/nike-shop/
Is there any way to add the word "shop" to the slug and remove the taxonomy name (brand)?
I've checked to codex but I couldn't find anything.
EDIT: Changed the question to make it more clear
If you're using your custom taxonomy, you can try to add rewrite parameter to the code, like this:
register_taxonomy('taxonomy',
array('post'),
array(
...
'rewrite' => array(
'slug' => 'taxonomy-archive'
)
)
);
But once you change your code, do not forget to go to Settings-Permalinks and just click Save Changes button there.
If you can not affect on the register_taxonomy() function, you can try the solution based on this tutorial https://rudrastyh.com/wordpress/remove-taxonomy-slug-from-urls.html

How to reconfigure custom post type after it has been defined?

I'm using a WordPress theme that adds a custom post type.
This is somewhat useful, but would be even more useful if I could adjust some of the CTP's configuration.
In particular, I need to adjust the capabilities defined on the CTP. I already have an array of the capability values needed, e.g.,
$caps = array(
'publish_posts' => 'activate_plugins',
'read_post' => 'read',
... etc
);
Is there a generic way to reconfigure a CTP with these values after it has been defined, i.e, via functions.php?
Or would I need to overwrite whatever theme code is creating the CTP, perhaps using a child theme?
Yes you can reconfigure the already defined CPT's properties. By using following filter: register_post_type_args
Src: https://developer.wordpress.org/reference/hooks/register_post_type_args/
Filters the arguments for registering a post type.
For example you can change slug like this:
add_filter('register_post_type_args', 'movies_to_films', 10, 2);
function movies_to_films($args, $post_type){
if ($post_type == 'movies'){
$args['rewrite']['slug'] = 'films';
}
return $args;
}
You can edit capabilities similarly see already answered question which solved exact problem:
https://wordpress.stackexchange.com/a/215697/30852

new Wp_Query() or pre_get_posts() to view ALL posts for custom post type?

I have an archive-template file that shows all posts for custom post type personnel (called archive-personnel.php):
This is the begining of the file...
<?php
get_header();
//Show all posts for this custom posttype (personnel)
$args = array( 'post_type' => 'personnel', 'posts_per_page' => -1 );
$personnel_query = new WP_Query( $args );
if (have_posts()) : while ($personnel_query->have_posts()) : $personnel_query->the_post();
This is working, but I know that I can use pre_get_posts() as well. But with pre_get_posts() - filter you have to check if it affects admin etc.
So my question is: Does it really matter which alternative I use or is just a matter of preference/taste?
Main query versus secondary queries:
Does it really matter which alternative I use or is just a matter of
preference/taste?
Yes , there is a real difference:
1) pre_get_posts is modifying the main query (or all queries) versus adding a secondary query using WP_Query.
2) If you want paging to work on the secondary query, you usually have to make modifications to the main query.
By using the pre_get_posts hook you can modify all queries that are instances of WP_Query(), including the main query, which is an instance of WP_Query() and is present for every page request.
Remember that get_posts() is a wrapper for WP_Query() and the filter is active when the suppress_filters attribute is set as FALSE.
When using pre_get_posts you usually want to target specific queries by using some conditional tags. Here are few examples, you can use:
a) is_main_query() to determine if the current query is the main query.
b) ! is_admin() to prevent modifications to queries in the backend.
c) is_post_type_archive() to target the post type archives.
When you add your custom WP_Query(), then you are adding extra queries in addition to the main query.
I usually go with the pre_get_posts action if I can, instead of adding a secondary query.
Example:
If you want to modify the main query, for the archive of the custom post type personnel, you can try:
add_action( 'pre_get_posts', function( $query ){
if ( ! is_admin() && $query->is_main_query() ) {
if ( is_post_type_archive( 'personnel' ) ) {
$query->set('posts_per_page', -1 );
}
}
});
This is untested but you get the idea ;-)
Further reading:
Hopefully the following links can give you more information regarding the difference:
https://wordpress.stackexchange.com/questions/50761/when-to-use-wp-query-query-posts-and-pre-get-posts/
https://wordpress.stackexchange.com/questions/76553/should-i-use-pre-get-posts-or-wp-query
https://wordpress.stackexchange.com/questions/1753/when-should-you-use-wp-query-vs-query-posts-vs-get-posts
https://wordpress.stackexchange.com/questions/81695/what-is-main-query

Custom Search for WordPress Custom Post Type page

I've got a fairly simple problem, which I would expect would have been fairly common, but after hours of searching and testing, I'm a bit stuck.
All I am trying to do it extend the search capability of the default 'Search Posts' function on my Custom Post Type page. Here is my code, but it is returning nothing when I do a search for a known email address. I get the feeling I might be barking up the wrong tree entirely. Can anyone recommend a solution...
function iymp_modify_mp_posts_search($query) {
/*
* If admin and if my custom post type
*/
if (is_admin() && $query->query_vars['post_type'] === 'mp_post') {
/*
* Show 200 posts per page in ascending order
*/
$query->set('posts_per_page', '200');
$query->set( 'order', 'ASC' );
/*
* If user entered a search term
*/
if (isset($_GET['s'])) {
/*
* As well as searching in the title (default behaviour), search in
* the _email_key field as well.
* *** Doesn't work ***
*/
$query->query_vars['meta_query'][] = array(
'key' => '_email_key',
'value' => $_GET['s'],
'compare' => 'LIKE',
);
}
}
}
add_action( 'pre_get_posts', 'iymp_modify_mp_posts_search' );
Maybe the problem is that WP is ANDing the searches in the title and _email_key fields. If that's the problem, how would I OR them?
The problem was indeed that WP does an AND search in the title and _email_key fields.
To do an OR search, I tried merging WP_Query results as shown here - https://wordpress.stackexchange.com/questions/55519/can-i-merge-2-new-wp-queryvariable-s - in guidod's answer. That wasn't a great solution though, and resulted in erratic behaviour.
The correct solution I found was to modify the query using the WP Custom Query as shown in the code (which requires some modifications) here - http://codex.wordpress.org/Custom_Queries ..

Wordpress page slug conflicts with media library item

I created a new page which is assigned a custom template. When I visit that page's url I see what appears to be the default page layout (not my template) and the admin toolbar shows options pertaining to media (ex: Edit media).
After some head scratching, I deduced that somehow that url must point to a media item. I edited the page slug and "bingo" the actual page appears just as expected. When I visit the original url (from the first slug) I see the same media item.
Bottom line: It appears that coincidentally the page and the media item share the same name, and this was somehow causing WP's wires to get crossed.
My question: Can someone help me understand how/why this happens? Does wordpress create magic permalinks to everything in the media library (other than their location in wp-content/uploads/...)?
Note: The media item was uploaded normally into the media library (not FTP into the root directory, etc)
Yes, in WordPress you cannot have duplicate slugs/categories/taxonomies/tags. So if your theme allows for media files and permalinks to have their own page and the slug is the same as another one, it will usually append a number to it because the database does not like it.
media slug "example"
page slug "example" will not work since that slug exists already , if done in the admin it will automatically change the slug to "example-1".
I just had this problem and fixed it like this:
$post_s=get_posts('posts_per_page=-1');
foreach($post_s as $p){
$atts = get_posts('post_type=attachment&name='.$p->post_name.'&posts_per_page=-1&post_status=inherit');
foreach($atts as $att){
echo 'found!! '.$p->post_name;
// Update post 37
$my_post = array(
'ID' => $atts->ID,
'post_name' => $att->post_name.'-image'
);
// Update the post into the database
wp_update_post( $my_post );
}
}
This is a late answer, but I wanted to give a cleaner version of the answer that alesub gave.
function wp21418_append_to_post_name() {
// Checks to see if the option images_updated has been set or has a value of true.
if ( get_option( 'images_updated' ) === 'true' ) :
return;
endif;
// get all attachment posts.
$attachments = get_posts([
'post_type' => 'attachment',
'post_status' => 'inherit',
'name' => $p->slug,
'posts_per_page' => -1,
]);
// For each attachment, loop and update the post_name
foreach($attachments as $p){
$attachment = array(
'ID' => $p->ID,
'post_name' => $p->post_name.'-image'
);
// Update the post into the database
wp_update_post( $attachment );
}
// Once everything is looped, add the option to the database.
add_option( 'images_updated', 'true' );
}
add_action( 'after_setup_theme', 'wp21418_append_to_post_name' );
This function runs on an action hook right after the theme has setup. The first line checks to see if there is an option in the database images_updated. If that option exists, we bail on the function and it doesn't do any processing. Otherwise, if the option does not exist, it runs the function and sets the option at the very end.
This makes it so it will only run once. You don't have to remove the function after refresh. If you want to run it again, you can simply remove the if statement at the top. As a caveat: doing this will add another -image at the end of post_names even if they have -image already (e.g. -image-image)
There could be more file name checking for that situation. Will update the answer with that if someone really needs it.
I tried one of the suggested solutions, and ended up having attachment pages like /bob-image-image-image-image/.
I'd suggest that instead of using alesub or disinfor's code blindly, use a better option in the form of "Disable Media Pages" plugin.
https://github.com/joppuyo/disable-media-pages
It automatically sets all attachment slugs to an unique id, and there is the option to mangle any existing attachment slugs so they won't cause any issues in the future.

Resources