How To Get The Post ID By Post Meta Value

One of the nicest and most flexible aspects of the WordPress API is the ability to associate meta data with certain models – for lack of a better term – in the database.

That is, we can assign meta value to Users, Posts, Authors, and so on.

Retrieving the data is typically trivially easy. Simply supply the ID of the model in question and then pass the key value for said post meta.

But what if you need to get the post ID or post meta key by the meta value instead?

Get Post ID By Meta Value

Whenever you end up having to locate the post ID or the meta key by the value instead, it naturally feels like you’re doing something backwards. I think a case can be made for either misusing the API and/or not properly organizing your data.

Nonetheless, there have been projects where I’ve needed to retrieve either the post ID or the post’s meta key when all I had was the value.

An Actual Example

But before at looking at how to do it, there needs to be some sort of example data:

Let’s say, for example, that I have a page that has an associated post meta value of “This page is locked.”

Because the database is large, I don’t know the page’s ID nor do I know the meta key that is associated with the set piece of meta data.

So here’s what I have:

  • It’s a page post type
  • The meta value is “This page is locked.”

There are two ways that we can go about actually retrieving this information.

1. Using WP_Query and The Loop

The first way that you can retrieve a post’s ID through it’s meta value is by using WP_Query. The only information you really need to know is the meta value for which you’re looking, although it also helps to have the post type handy.

To do this, you can setup the following query:

$args = array(
	'post_type'		=>	'page',
	'meta_query'	=>	array(
			'value'	=>	'this is my example value.'
$my_query = new WP_Query( $args );

From here, you can setup a standard variation of The Loop:

if( $my_query->have_posts() ) {
  while( $my_query->have_posts() ) {
    // Do your work...
  } // end while
} // end if

But if you’re expecting a single post, then there’s no need to actually setup the while loop.

Finally, note that the more information you have about the post, the better. That is, knowing the post type is good, but knowing more meta information about the post can help provide a more optimized query.

2. Using SQL

On the other hand, there are times when it’s possible to use raw SQL to retrieve the results. To do this, you’ll need two pieces of information:

  • The name of the table in which the meta data is kept. In our case, that’s the wp_postmeta table
  • The post meta value

From here, you can use $wpdb and raw SQL for retrieving the results:

global $wpdb;
$results = $wpdb->get_results( "select post_id, meta_key from $wpdb->postmeta where meta_value = 'this is my example value.'", ARRAY_A );

That said, I don’t actually recommend doing this unless you’re extraordinarily skilled with SQL and have a deep understanding of query performance, the database schema indexes, etc.

Which is Better?

When it comes to writing code like this, I usually default to using the WordPress API – that is, WP_Query – for two reasons:

  1. It provides cleaner, more readable code within the context of a WordPress codebase
  2. It will ultimately be reduced to optimized SQL that’s better than what I could’ve come up with on my own

The two example above are simplistic. It’s not often that you’ll need to run a query to pull back one or two results by meta values, nor is it common that you’ll need a simple SELECT statement.

Instead, you’ll likely need more information in order to provide JOINS, LIMITS, and so on in order to make sure you’re pulling back exactly what you need.

So, with all of that said, I recommend using WP_Query – that’s what it’s there for – but if you’re dealing with a complicated set of data, and are deeply familiar with both the WordPress database scheme and SQL, then have it.

16 Replies to “How To Get The Post ID By Post Meta Value”

  1. Hey Tom.

    Couple of notes:

    1. Yet again you have forgotten to include wp_reset_postdata, after WP_Query loop.
    2. While creating custom db queries make sure to use proper table prefixes, that is instead of hardcoding table names, please use $wpdb object properties, for instance $wpdb->postmeta. Otherwise table prefix won’t be taken into account, failing in case it was different than above.
    3. The proposed solution could also be obtained with get_posts method call, reducing the code complicacy.

    I’m certain that you know these. Althogh Knowing the fact that your popularity grows due to being mentioned in weekly issues and producing fabulous frameworks these ought to be included for the WP newbies sake and good programming practices :)


      • You’d really only have to include wp_reset_postdata() if you used a while loop. More specifically, you only need to include it if you make a call the ,the_post. In the original post, I didn’t explicitly make that call. To be complete for the sake of this comment, I’ve updated the post so thanks for mentioning name.
      • This particular point is spot on and the post has been updated. Props for catching that.
      • get_posts would work just fine, too. Since that particular function uses WP_Query, I just default to the latter – I’m more of a fan of it mainly because of its object-oriented nature and because of just how much can be done with it. That’s why you rarely see me mention anything other than that.
      • Anyway, as always, I dig the input you provide and love having the readers catch critical improvements that can be made.

        My goal’s to make sure the information is as accurate as possible, so it helps to have multiple eyes reviewing the code :).

      1. Marvelous ;)

        Thanks for taking these into account.

        You’re right about the above. Although such an in-depth knowledge makes use consciously omit some parts of the code – it’s always a nice measure to at least mention it :)

        My goal’s to make sure the information is as accurate as possible, so it helps to have multiple eyes reviewing the code .

        Perfect. I’ll make sure to catch all issues, so stay tuned !

  2. I was struggling with this issue before I found this post.

    I think for my code the second option of using SQL query would work better. I want to get just the list of post IDs which have a meta key with a specific meta value. I don’t know if this can done using any of the in-build functions, but for now I’m using the 2nd option.


  3. After working with WordPress for years, I would actually recommend using SQL whenever possible. In most cases, one doesn’t have to be “extraordinarily” skilled with SQL, but simply have the minimum knowledge required when dealing with any RDBMS. This specific case doesn’t even require “deep” understanding of query performance, database schema, etc. It’s super simple. :)

    There is no excuse for not knowing SQL. Having a good grasp of it is part of the basic skillset that any WordPress developer should possess.

    1. Though I recognize the power and the benefit of using SQL directly – especially in some instances more than others – I actually opt to use the APIs whenever necessary.

      Ideally, the APIs should provide better protection against certain things (like SQL injection) than using vanilla SQL and its one of those things that translates down to more secure SQL anyway.

      Plus, if the API is available, I’d rather use it than not as it doesn’t feel as if I am circumventing the system and I’ll always have the documentation and the source code to dig into should it end up doing something that I’m not expecting.

      Granted, the latter could be said about using SQL as well, but I’m not as good with SQL as I’d like, so it’s a matter of personal security for me.

      1. I think that both of these are fine. The biggest benefit of writing queries yourself is, assuming the one who writes is a pro the fact that it’s much easier to optimize them.

        As Tom said, the API is a good wrapper for those are not comfortable with their own queries. Moreover with WordPress core having a lot of global variables which need to be reset the API query seems to be easier to mantain and read.

        Lastly in case anything changed in WordPress core DB structure (which is very unlikely) the API queries will most probably work without any code changes, whereas the former solution might not end up so well.

  4. Hi guys I was wondering if you could help. I am using a similar code found in this website:

    //Get Post ID by meta key and meta value

    if (!function_exists(‘get_post_id_by_meta_key_and_value’)) {

    function get_post_id_by_meta_key_and_value($key, $value) {

    global $wpdb;

    $meta = $wpdb->get_results(“SELECT * FROM ".$wpdb->postmeta." WHERE meta_key='”.$wpdb->escape($key).”‘ AND meta_value='”.esc_sql($value).”‘”);

    if (is_array($meta) && !empty($meta) && isset($meta[0])) {

    $meta = $meta[0];


    if (is_object($meta)) {

    return $meta->post_id;


    else {

    return false;




    It works fine for one value but what if we try to find a post by a value contained inside the meta key amongst various values, separated by a comma? In my example, these values are also numeric.

    1. Though using $wpdb to do something like this is work, I don’t recommend using that particular object to run queries against the database.

      In the code you’ve provided, you’re not wrapping the query in a prepare function and you’re leaving the query open some maintenance headaches.

      Instead, I’d look at WP_Query and look specifically at the meta_query to try to achieve what you need. It’s a far more elegant solution and uses the native API rather than raw queries.

  5. If i want to get product id based on multiple meta keys and meta values just like searching some product based on some meta values. what would you suggest??

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.