One possible approach would be to use one of the helper methods in the WPDB class to do a more refined meta-based query.
Using the $wpdb
function get_col
it's possible return a simple flat array of data.
Here's an example function which queries the database for all posts of a specified post type, post status and meta key (or custom field to the less technically minded).
function get_meta_values( $meta_key = '', $post_type = 'post', $post_status = 'publish' ) {
global $wpdb;
if( empty( $meta_key ) )
return;
$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_type = %s
AND p.post_status = %s
", $meta_key, $post_type, $post_status ) );
return $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 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 little more than print that data to the screen, PHP's implode
function can quickly condense the array into a string.
// Print the meta values separated 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 the meta values by doing a simple iteration(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 = [];
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 ) );
/*
Output:
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.