One possible approach would be to use one of the helper methods in the WPDB classWPDB 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 toUsing the WPDB method get_col$wpdb
which returnsfunction get_col
it's possible return 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 chosenspecified post type, post status and with a specific meta key (or custom field to the less technically minded).
function get_meta_values( $key$meta_key = '', $type$post_type = 'post', $status$post_status = 'publish' ) {
global $wpdb;
if( empty( $key$meta_key ) )
return;
$r$meta_values = $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_statuspost_type = %s
AND p.post_typepost_status = %s
", $key$meta_key, $status$post_type, $type$post_status ) );
return $r;$meta_values;
}
So for example, if you would 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.
If you wanted to do nothinglittle more than print that data to the screen, PHP's implode
function can quickly splice that simplecondense the array into lines of dataa string.
You can also use the returned data to work out how many posts have thesethe meta values by doing a simple loopiteration(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;
}
}
// Output the number of ratings
printf( '<pre>%s</pre>', print_r( $num_of_ratings ) );
/*
ResultOutput:
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.
Using transients to cache the results
And here's an updated version that uses WordPress transients to cache the query, as that seems to be the main criticism for using $wpdb
in other provided answers.
function get_meta_values( string $meta_key, string $post_type = 'post', bool $distinct = false, string $post_status = 'publish' ) {
global $wpdb, $wp_post_types;
if( !isset( $wp_post_types[$post_type] ) )
// Existing WP string, it should translate as is
return __( 'Invalid post type.' );
$transient_key = 'get_' . $wp_post_types[$post_type]->name . '_type_meta_values';
$get_meta_values = get_transient( $transient_key );
if( true === (bool)$get_meta_values )
return $get_meta_values;
$distinct = $distinct ? ' DISTINCT' : '';
$get_meta_values = $wpdb->get_col( $wpdb->prepare( "
SELECT{$distinct} 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_type = %s
AND p.post_status = %s
", $meta_key, $post_type, $post_status ) );
set_transient( $transient_key, $get_meta_values, DAY_IN_SECONDS );
return $get_meta_values;
}
The DAY_IN_SECONDS
constant is one of various time in seconds constants setup by WordPress.
Updated argument and variable names to make them more consistent with WordPress naming and also implemented DISTINCT
as an optional parameter following the tip from Howdy_McGee in the comments.