I would like to create a wp_query that would return posts meta inside the posts
array.
$args = array (
'post_type' => 'page',
'meta_key' => 'someMetaKeyName',
);
// The Query
$query = new WP_Query( $args );
This returns something like:
As you can see the posts do not have any meta data, is it possible to include the meta data in the returned array as well?
PS I don't want additional wp_queries for performance reasons.
I would like to create a wp_query that would return posts meta inside the posts
array.
$args = array (
'post_type' => 'page',
'meta_key' => 'someMetaKeyName',
);
// The Query
$query = new WP_Query( $args );
This returns something like:
As you can see the posts do not have any meta data, is it possible to include the meta data in the returned array as well?
PS I don't want additional wp_queries for performance reasons.
Share Improve this question asked Dec 12, 2014 at 3:09 YemSalatYemSalat 4593 gold badges6 silver badges14 bronze badges 1 |5 Answers
Reset to default 26By default, WP_Query
returns the standard WP_Post
objects for the posts being queried. I believe with some clever rewrite and use of the filters given in WP_Query
you can add objects to the returned WP_Post
objects array.
Will this be performant? In my opinion, it will hurt performance more as you will need to join results in your query as custom fields are not saved in the wp_posts
table, but in the wp_postmeta
table
Retrieving post meta is really fast and it does not require any extra instance of WP_Query
. You can simply call the custom field with get_post_meta()
. WordPress was very thoughtful when the custom fields was introduced. They added a cache to cache them, so whether you are querying 1 or 100 custom fields, you are hitting the database once, superfast. For a complete test and explanation, see this post I have recently done on this subject.
In my opinion, the extra database call and the actual time spent is worth it and faster than rewriting WP_Query
in such a way to include custom fields in the standard post object returned by $posts
I had a similar problem recently, I needed to get 7 pieces of metadata from a custom post type, but also needed to get the post based on a piece of metadata.
So I created the following SQL statement, I use it often. Hopefully it will help someone else. I'll try and explain it as best I can.
global $wpdb;
$pt = 'clients';
$mk = 'trainerid';
$mv = $pid;
$mk1 = 'email';
$mk2 = 'phone';
$mk3 = 'gender';
$mk4 = 'dob';
$mk5 = 'photo';
$mk6 = 'registrationts';
$mk7 = 'activationts';
$ord = 'p.post_name ASC';
$sql = "
SELECT p.ID, p.post_title AS fullname, pm1.meta_value AS email, pm2.meta_value AS phone, pm3.meta_value AS gender, pm4.meta_value AS dob, pm5.meta_value AS photo, pm6.meta_value AS regts, pm7.meta_value AS actemailts
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID
AND pm.meta_key = '{$mk}'
LEFT JOIN {$wpdb->postmeta} pm1 ON pm1.post_id = p.ID
AND pm1.meta_key = '{$mk1}'
LEFT JOIN {$wpdb->postmeta} pm2 ON pm2.post_id = p.ID
AND pm2.meta_key = '{$mk2}'
LEFT JOIN {$wpdb->postmeta} pm3 ON pm3.post_id = p.ID
AND pm3.meta_key = '{$mk3}'
LEFT JOIN {$wpdb->postmeta} pm4 ON pm4.post_id = p.ID
AND pm4.meta_key = '{$mk4}'
LEFT JOIN {$wpdb->postmeta} pm5 ON pm5.post_id = p.ID
AND pm5.meta_key = '{$mk5}'
LEFT JOIN {$wpdb->postmeta} pm6 ON pm6.post_id = p.ID
AND pm6.meta_key = '{$mk6}'
LEFT JOIN {$wpdb->postmeta} pm7 ON pm7.post_id = p.ID
AND pm7.meta_key = '{$mk7}'
WHERE pm.meta_value = '{$mv}'
AND p.post_type = '{$pt}'
AND p.post_status NOT IN ('draft','auto-draft')
ORDER BY {$ord}
";
$clients = $wpdb->get_results( $wpdb->prepare( $sql ), OBJECT );
First I get the wordpress database functions with global $wpdb. Then I set the posttype with $pt. To get the correct post that matches a specific value in post_meta, I set the $mk (meta_key)
Then I set the $mv (meta_value) var. (in this case the meta value matches a postid)
$mk1-$mk7 are the meta_keys I want from each post. (I'll grab the values in the select statement)
I also make the 'order by' a var, by setting $ord
The select statement goes as follows: I select the post ID and the post_title from the POST or 'p.'
Then I select all the metadata I need selecting them with pm1. -> pm.7 and grabbing the meta_value and renaming them ( AS ) so it's more readable when retrieving the data from my object.
I create a LEFT JOIN for the meta data I need to match to the post. (pm)
I create 7 left join's for each of the meta data I need to retrieve. (pm1-pm7)
The WHERE statement is based on the first LEFT JOIN (pm) so that it will know I need only the posts where the metadata matches.
I also add an 'AND' for the post type, and for the post_statuses that are not drafts. (so only published posts)
Finally I add the 'order by' clause.
This works fast and with the built-in indexes in Wordpress, so it seems efficient.
Don't know if something is better than this, but if it is, I'd love to use it.
Hope this helps.
Marcus
This question is more than 1 year old, but I have the same problomlem, and here is function that will add each meta_value and meta_key to $wp_query object,
instead of query each post meta in while loop, this function will do One extra query example:
"SELECT meta_key, meta_value, post_id FROM $wpdb->postmeta WHERE post_id IN (1,2,3,4,5...)"
where (1,2,3,4,5...) is curently quered post IDs from $wp_query
if(!function_exists('add_query_meta')) {
function add_query_meta($wp_query = "") {
//return In case if wp_query is empty or postmeta already exist
if( (empty($wp_query)) || (!empty($wp_query) && !empty($wp_query->posts) && isset($wp_query->posts[0]->postmeta)) ) { return $wp_query; }
$sql = $postmeta = '';
$post_ids = array();
$post_ids = wp_list_pluck( $wp_query->posts, 'ID' );
if(!empty($post_ids)) {
global $wpdb;
$post_ids = implode(',', $post_ids);
$sql = "SELECT meta_key, meta_value, post_id FROM $wpdb->postmeta WHERE post_id IN ($post_ids)";
$postmeta = $wpdb->get_results($sql, OBJECT);
if(!empty($postmeta)) {
foreach($wp_query->posts as $pKey => $pVal) {
$wp_query->posts[$pKey]->postmeta = new StdClass();
foreach($postmeta as $mKey => $mVal) {
if($postmeta[$mKey]->post_id == $wp_query->posts[$pKey]->ID) {
$newmeta[$mKey] = new stdClass();
$newmeta[$mKey]->meta_key = $postmeta[$mKey]->meta_key;
$newmeta[$mKey]->meta_value = maybe_unserialize($postmeta[$mKey]->meta_value);
$wp_query->posts[$pKey]->postmeta = (object) array_merge((array) $wp_query->posts[$pKey]->postmeta, (array) $newmeta);
unset($newmeta);
}
}
}
}
unset($post_ids); unset($sql); unset($postmeta);
}
return $wp_query;
}
}
Additioanal "postmeta" will be written to each $wp_query->posts[$i]
$wp_query->posts[0]->postmeta
Example with 'someMetaKeyName' don`t forget to put
add_query_meta()
to your theme functin.php
$args = array (
'post_type' => 'page',
'meta_key' => 'someMetaKeyName',
);
// The Query
$query = new WP_Query( $args );
if($wp_query->have_posts()) {
$wp_query = add_query_meta($wp_query);
$i = 0;
while($wp_query->have_posts()) {
$wp_query->the_post();
$post_id = get_the_id();
//Get $someMetaKeyName in current post
foreach($wp_query->posts[$i]->postmeta as $k => $v) {
switch($v->meta_key) {
case('someMetaKeyName') : {
$someMetaKeyName = $v->meta_value;
break;
}
}
}
//Your Code here
//Example
echo isset($someMetaKeyName) ? '<h3>'.$someMetaKeyName.'</h3>' : '';
$i++;
}
}
I just needed a single extra post_meta value (the template in my case) and was able to get something similar to what you are after using get_pages
with a meta_key
parameter.
$args = [
'parent' => $post_id, // in my example, finding the children of some specific post
'meta_key' => '_wp_page_template', // looking for the template used by the post
];
$posts = get_pages($args);
And this returns an array of post object like this
Array
(
[0] => WP_Post Object
(
[ID] => 22765
[post_author] => 173
[post_date] => 2022-03-14 21:11:18
...
[meta_key] => _wp_page_template
[meta_value] => template-module-content.php // <-- BOOM!
...
)
And you can then can access a meta_value
like so
echo $posts[0]->meta_value;
// returns 'template-module-content.php' in my case
Admittedly this could be for a narrow use case, but was just what I needed
Hey Please try this one I think it work fine.
$args = array(
'post_type' => 'page',
'meta_key' => 'someMetaKeyName',
'meta_query' => array(
array(
'key' => 'someMetaKeyName',
'type' => 'CHAR',
),
),
);
$query = new WP_Query( $args );
get_post_meta
on individual keys, 2) runget_post_custom
to get all of a posts custom fields in one shot, or 3) create your own query using the $wpdb class (get_results()
) to build your own return object. ($wpdb class documentation: codex.wordpress.org/Class_Reference/wpdb) – BODA82 Commented Dec 12, 2014 at 4:28