2

Update 2: Check out @NateWr method using add_post_meta with the default post:

add_post_meta( 1, 'my_items', 1 );
add_post_meta( 1, 'my_items', 2 );
add_post_meta( 1, 'my_items', new \stdClass );  

var_dump(get_post_meta(1, 'my_items', true));
echo "<br><br>";
var_dump(get_post_meta(1));
echo "<br><br>";

$GLOBALS['wp_object_cache']->stats();

And the results:

string(1) "1" 

array(1) {
  ["my_items"]=>array(3) {
    [0]=> string(1) "1"
    [1]=> string(1) "2"
    [2]=> string(19) "O:8:"stdClass":0:{}"
  }
}

This time, it hits the cache but the meta value is different. Now, if I don't know meta_key and I just use only post ID to retrieve and parse post meta manually, it's obvious that i will get wrong value.


Update 1: Check out @NateWr method using update_post_meta with the default post:

update_post_meta(1, 'my_items', 1);
update_post_meta(1, 'my_items', 2);
update_post_meta(1, 'my_items', 3);

var_dump( get_post_meta(1) );

echo "<br><br>";

$GLOBALS['wp_object_cache']->stats();

Results:

array(1) {
  ["my_items"]=>array(1) {
    [0]=>string(1) "3"
  }
} 

Look like Cache Hits doesn't change and WordPress still return an meaningless array as meta_value. Or I missed something?


Question:

I'm trying to avoid extra queries on templates by pre-fetching necessary data while the WP_Query retrieving posts. This is basically how it looks like:

add_filter('the_posts', function($posts, $query)
{
  if ( !is_admin() ) {
    $mapper = new Vendor\PostMapper($GLOBALS['wpdb']);
    foreach ($posts as $post) {
      $post->post_link = get_permalink($post);
      $post->post_meta = $mapper->getMetadata($post);
      $post->post_thumbnail = $mapper->getThumbnail($post);
      ...
    }
  }

  return $posts;
}, PHP_INT_MAX, 2);

Everything works fine but I feel unease while parsing metadata. By using metadata API, if I don't specify meta_key, meta values are always arrays of only one element such as:

array(3) {
  ["_edit_last"]=>array(1) {
    [0]=>string(1) "1"
  }
  ["_edit_lock"]=>array(1) {
    [0]=>string(12) "1467358332:1"
  }
  ["_thumbnail_id"]=>array(1) {
    [0]=>string(3) "767"
  }
}

I think I will never be able to know all meta_key. I also have no ideas why WordPress need to do that. The arrays look meaningless and it bothers me a lot.

So, given that meta_key isn't required and I don't specify meta_key, I really need your help to understand:

Q1: Can one meta_key have multiple meta_value? If not, why WordPress need to use an meaningless array as output for meta_value?

Q2: Why WordPress don't unserialize all serialized meta values?

  • 1
    I didn't include this in my answer, but typically a WP_Query retrieves post metadata and stores it in object cache. That means that you can call get_post_meta( $post_id, 'my_first_meta_key', true); and then call get_post_meta( $post_id, 'my_second_meta_key', true ); and keep making calls like that, and you won't be hitting the database every time. It will go to the object cache for the meta values. I'm not sure your exact application, but that may circumvent the issue for you. – NateWr Jul 1 '16 at 9:34
2

Q1 Yes, you can store serialized arrays as a single meta key, eg:

update_post_meta( $post_id, 'my_items', array( 1, 2, 3, 4 );

Furthermore, you can store multiple values against a single meta key, eg:

add_post_meta( $post_id, 'my_items', 1 );
add_post_meta( $post_id, 'my_items', 2 );

The latter is preferred because meta queries can be more efficiently performed against them.

In the first example, there is a single row in the post_meta table. In the second example, there are two rows.

So, in the second example, you can perform a query for posts which have a my_item meta value of 2 without having to pull out and unserialize every my_item entry in the database.

Many people, myself included, learned this the hard way.

Q2 I'm sorry I can't answer the why, though I do know that serialization and unserialization can have performance implications for large data sets.

  • Thanks you! I have just check out your method and updated my question but somehow, WordPress still return an meaningless array. – MinhTri Jul 1 '16 at 13:12
  • Sorry, I should have used add_post_meta, not update_post_meta. Updating will obviously override the existing value. You need to add if you want multiple values attached to a single key like in example 2. That's also why update_post_meta lets you pass a prev_value argument: that way you can update just the one meta value instead of all of them. – NateWr Jul 1 '16 at 15:56
  • Hey @NateWr, I have updated the question again. Look like I still misunderstand something... – MinhTri Jul 2 '16 at 1:04
  • The results you post under Update 2 look correct and as expected. Maybe if you clarify what you expected them to be I can clear up the confusion. – NateWr Jul 3 '16 at 8:23
  • Thanks @NateWr! I'm wondering how to parse metadata without knowing about meta keys because the results of with and without a meta_key are different. – MinhTri Jul 6 '16 at 2:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.