Get Posts With Same Custom Field VALUE As Current Post
By Alex on June 10 2009 | Listed under Tutorials, WordPress | 13 Comments
So, you’ve read all the tutorials on how to get custom field values and how to get posts that have a certain key/value, but what about if the post your are viewing has a custom field, and you want all the other posts with that custom field value; a value that you won’t know in advance…?
When I say “that you won’t know in advance”, what I mean is that most custom field tutorials deal with finding posts for a SPECIFIC key/value pair. What I’m dealing with here, is the prospect that you might know the key, but not what the value is going to be, but you still want all the other posts with the same value.
(If all of this is gibberish, please start here, at the codex.)
So, this might be clearer with a real world example. Let’s take a motorbike spec website. All the bike’s specificaitons are listed in custom fields; for example: Engine Size as the Key, and 125cc as the Value.
If we’re viewing a post, we know that the custom field key for Engine Size is going to be there, but not what the value is going to be. So in our sidebar we want to display all the other bikes that have the same engine size as the current bike. Clearer?!
Lets get to the code. This is all going to be outside of the loop, and I’m putting it in sidebar.php. The first thing we need to do is get the custom field value for our key. Let’s set up a variable.
1 | <?php $cur_post_value = get_post_meta($post->ID, 'Engine Size', true); |
This does the following:
- Opens our PHP tag
- Creates a variable
- Assigns the result of the fuction get_post_meta to that variable
- $post-> gets the current post’s ID, so we know which post to look in for our key/value
- The name of the Key of our custom field
- the last parameter is set to true to just get the first value associated with our Key
Now we want to search all of the other posts for this value that we have just retrieved. We do that using a mySql select query.
2 3 4 5 6 7 8 9 10 11 12 13 | $other_posts_with_value = " SELECT wposts.* FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta WHERE wposts.ID = wpostmeta.post_id AND wpostmeta.meta_key = 'Item Author' AND wpostmeta.meta_value = '".$cur_post_value."' AND wposts.post_status = 'publish' AND wposts.post_type = 'post' ORDER BY wposts.post_date DESC "; $other_posts_array = $wpdb->get_results($other_posts_with_value, OBJECT); ?> |
This does the following:
- Creates a variable where we can store the results of our query
- Accesses the $wpdb class, which provides us with functions for using our database
- The next important part is wpostmeta.meta_key. This is where we put what the custom field Key is going to be
- Then we want to find all posts with the Value that the current post has, so we use the variable we created earlier. NB. That is single quote, double quote, period $cur_post_value, period, double quote, single quote
- Then we make sure we are only getting posts that have been published, and are definitely posts and not Pages
- Next we order our posts in descending date order
- Finally we create a new variable that will be an array of the data set we just got with our SELECT query and then close the PHP tag
By means of a pointer to what we’re going to show, we can make a title for our list:
1 | <h3>Other bikes with a <?php $cur_post_value ; ?> Engine</h3> |
Next we need to set up our custom loop to display these related posts.
2 3 4 5 6 7 8 9 10 11 | <?php if ($other_posts_array): ?> <h3>Other bikes with a <?php $cur_post_value ; ?> Engine</h3> <?php foreach ($other_posts_array as $post): ?> <?php setup_postdata($post); ?> <li><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>" rel="bookmark"><?php the_title(); ?></a></li> <?php endforeach; ?> <?php else : ?> <li>No other <?php $cur_post_value ; ?> bikes were found</li> <?php endif; ?> |
Let’s have a look at each of those elements:
- We first want to check that our query and array actually has some results in it, so we check for $other_posts_array
- Then we create a foreach loop to go through our results one by one
- setup_postdata provides us with access to WordPress’ post formatting, so we can use the_title etc
- We then do the normal post display stuff, title and link etc. In our case we create an ordered list of items
- End what we do for each of our results with endforeach
- Then we do something if no other results were found, in our case a message saying that no other bikes were found with the current bikes engine size. The $cur_post_value was set earlier remember.
- Finish off our loop with ending the if statement
And we’re all done! Play around with the idea and see what you can come up with. The screenshots you can see are little unpublished project of mine tracking who wrote a certain plugin I mention in a post, and then finding other plugins by them.
There is one thing that is lacking from the code, and that needs adding; think about what results we get with our query. How would you solve this?
Did you enjoy this post? If you did, so might others! Please share it!











12 Comments - Add Yours!
I don’t think you need this to be this complex. I’d try the following:
< ?php
global $post;
$cur_value = get_post_meta( $post->ID, 'whatever name' );
$posts = get_posts( array( 'meta_key' => 'whatever name', 'meta_value' => $cur_value ) );
?>
See here: http://codex.wordpress.org/Template_Tags/get_posts
@Nick – Hi, thanks for dropping by my site! I looked into what you suggested, and at first it looked like it was indeed going to be much easier. There are two things though that I found.
Firstly, to get your code to work, I needed to replace the array within the get_posts call with a variable, which I then defined as that array. Not sure why but that then found the posts, while it hadn’t done previously with the array inside the function.
Secondly, I thought I’d do some more reading around, and I came back to a post that I linked to in the article, and specifically a comment that said that when using query_posts, if the custom values are going to be ‘0′ ever, then a SELECT query was needed. Since query_posts and get_posts now “use the same database query code internally” I wondered if this was the case here too. So I created some custom values as 0, and sure enough, all posts with the desired custom key were returned, regardless of their value. Returning the code to the SELECT query retrieved only the posts with the correct and current custom value.
So, not knowing whether a user/blogger is going to create custom field values/keys as ‘0′, I figure the SELECT version is the one to go with.
Hope that’s clear?! If you have got your code to work though in any other way, let me know, since obviously the easier the better!
In general, I’d go with the above approach and stipulate that a value of 0 (just like the empty string) is invalid for the value for a meta field. Keeps things easier, plus if they change the database scheme in future versions of WordPress, you’re totally screwed if you’re using a raw SELECT statement. The API call will still work, though.
Thank you for this very clear and helpful piece of code. You saved me quite a bit of time!
@Harvey – Thanks for visiting, and I’m glad the code helped you out.
The code looks awesome and is working fine. Can you tell me how to include a category name(and id) to compare as well?
So both should have a value to get a result.
I am using wp2.7.1
@devdarsh – I’ll update the post in the next couple of days to include a category comparison too – great idea!
Hi
Great tutorial, I tried and it works, but I would like to know how to exclude from the list the current post.
cheers
Thank you for this very clear and helpful piece of code. You saved me quite a bit of time!
Hi Alex.
Thank you so much for sharing this great feature. I searched all over the web but kept stumbling on to those tedious custom field “mood” tutorials (you’d think one was enought), but finally I find yours. It’s also really great that you explain what is going on.
Miklas.
P.S. Shouldn’t there be an “echo” in front of “$cur_post_value ;” so the value is printed
Praise the Lord! I’ve been up for about 30 odd hours coding, and none of the solutions like this were working for me. You’ve saved my life and my state of mental health, LOL.
The only part which was not quite right is that it also posts the current post, which i did not want, so i posted the ID of the post and made it invisible with CSS, LOL
Your little piece of code have helped me a lot!!! Your rock!
One Trackback