getting all values for a custom field key (cross-post)

I know how to get a custom field value for a specific post.

get_post_meta($post_id, $key, $single);

What I need is to get all the values associated with a specific custom post key, across all posts.

Anyone knows of an efficient way to do this? I wouldn’t want to loop through all post id’s in the DB.

Example:

4 posts all with different values for a custom field called ‘Mood’.
2 posts have the value ‘happy’, 1 post have ‘angry’ and 1 post has ‘sad’

I want to output : across all posts we have: two happy, one angry and one sad author(s).

But for LOTS of posts.

What I’m looking for is either:

  • a WP function to get this.
    or
  • a custom query to get this as efficiently as possible.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

One possible approach would be to use one of the helper methods in the WPDB class to do a more refined meta based query. The caveat to using some of these functions however, is that you don’t usually get back a simple array of data and usually have to make needless references to object properties, even if you’re only calling for one column or row.

Of course, not all functions are the one and the same, and a purposeful mention goes out to the WPDB method, get_col which returns a simple flat array of the data queried for, i make this mention specifically because the example following will call upon this method.

WordPress – WPDB Selecting a column of data
$wpdb->get_col()

Here’s an example function which queries the database for all posts of a chosen post type, post status and with a specific meta key(or custom field to the less technically minded).

function get_meta_values( $key = '', $type = 'post', $status = 'publish' ) {

    global $wpdb;

    if( empty( $key ) )
        return;

    $r = $wpdb->get_col( $wpdb->prepare( "
        SELECT pm.meta_value FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = %s 
        AND p.post_status = %s 
        AND p.post_type = %s
    ", $key, $status, $type ) );

    return $r;
}

So for example, if you like to find out which posts have a meta key of rating, for the post type movies and you’d like to store that information inside a variable, an example of such a call would be..

$movie_ratings = get_meta_values( 'rating', 'movies' );

If you wanted to do nothing more than print that data to screen, PHP’s implode function can quickly splice that simple array into lines of data.

// Print the meta values seperate by a line break
echo implode( '<br />', get_meta_values( 'YOURKEY' ));

You can also use the returned data to work out how many posts have these meta values by doing a simple loop over the returned data and building an array of the counts, for example.

$movie_ratings = get_meta_values( 'rating', 'movies' );
if( !empty( $movie_ratings ) ) {
    $num_of_ratings = array();
    foreach( $movie_ratings as $meta_value )
        $num_of_ratings[$meta_value] = ( isset( $num_of_ratings[$meta_value] ) ) ? $num_of_ratings[$meta_value] + 1 : 1;
}

/*
Result:
Array(
    [5] => 10
    [9] => 2
)
// ie. there are 10 movie posts with a rating of 5 and 2 movie posts with a rating of 9.
*/

This logic could be applied to various kinds of data, and extended to work any number of different ways. So i hope my examples have been helpful and simple enough to follow.

Method 2

It is not good or needed to use the global $wpdb:

// function to grab all possible meta values of the chosen meta key.
function get_meta_values( $meta_key,  $post_type = 'post' ) {

    $posts = get_posts(
        array(
            'post_type' => $post_type,
            'meta_key' => $meta_key,
            'posts_per_page' => -1,
        )
    );

    $meta_values = array();
    foreach( $posts as $post ) {
        $meta_values[] = get_post_meta( $post->ID, $meta_key, true );
    }

    return $meta_values;

}

$meta_values = get_meta_values( $meta_key, $post_type );

Method 3

I’d just like to add one tiny thing to t31os‘s code above. I changed “SELECT” into “SELECT DISTINCT” to eliminate duplicate entries when I used this code myself.

Method 4

the fastest way would be a custom sql query and i’m not sure but you can try

$wpdb->get_results("
  SELECT posts.* , COUNT(*) 'moodcount'
  FROM $wpdb->posts as posts
  JOIN $wpdb->postmeta as postmeta
  ON postmeta.post_id = posts.ID
  AND postmeta.meta_key = 'Mood'
  GROUP BY postmeta.meta_key
");

If anything then its a start.

Method 5

For getting all meta values by a meta key

Check wp->db wordpress codex

$values = $wpdb->get_col("SELECT meta_value
    FROM $wpdb->postmeta WHERE meta_key = 'yourmetakey'" );

Method 6

There’s no reason why you can’t merge t31os and Bainternet’s code to have a reusable prepared statement (wordpress style) that returns the count and the values in one efficient operation.

It’s a custom query but it’s still using the wordpress database abstraction layer – so for example it doesn’t matter what the table names really are, or if they change, and it’s a prepared statement so we’re that much safer from SQL attacks etc.

In this instance I’m no longer checking for post type and I’m excluding empty strings:

    $r = $wpdb->get_results(  $wpdb->prepare( "
        SELECT pm.meta_value AS name, count(*) AS count  FROM {$wpdb->postmeta} pm
        LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
        WHERE pm.meta_key = '%s'
        AND pm.meta_value != '' 
        AND p.post_type = '%s'
        GROUP BY pm.meta_value
        ORDER BY pm.meta_value          
        ", $key, $type) 
        );
    return $r;

In this particular is

This will return an array of objects like so:

array  
 0 => 
 object(stdClass)[359]
  public 'name' => string 'Hamish' (length=6)
  public 'count' => string '3' (length=1)
 1 => 
 object(stdClass)[360]
  public 'name' => string 'Ida' (length=11)
  public 'count' => string '1' (length=1)
 2 => 
 object(stdClass)[361]
  public 'name' => string 'John' (length=12)
  public 'count' => string '1' (length=1)

Method 7

Use the following with foreach

 $key = get_post_custom_values( 'key' );

Assumes the named of your custom field key is


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x