6

Looking at get_post_meta() I always have to remember to set the $single param to true. I generally assume I'm setting a value and I expect to get that value back.

Retrieve post meta field for a post.

  • $post_id (int) (Required) Post ID.
  • $key (string) (Optional) The meta key to retrieve. By default, returns data for all keys. Default value: ''
  • $single (bool) (Optional) Whether to return a single value. Default value: false

I know this should exist as an option for a reason but I don't personally know why that is. Can someone explain why this returns an array of values by default? It makes sense from a backwards compatibility standpoint but have things evolved? Or are there Core features that require it to be this way for an efficiency that I am unaware of.

Does adding $prev_value to update_post_meta() create a history as array elements?

I would appreciate a working example of when this, being set to false, makes sense. That means code I can test. In addition to, a genuinely well thought out and researched answer. That means I want comments like TLC wants scrubs.

  • 1
    metas are made to store multiple values and then returns then as a array. if you store only one value, it does a array with a single item. – mmm Nov 8 '16 at 13:54
  • But why store multiple values? I'd like to see a good reason for that. Can't you save an array as an item? – jgraup Nov 8 '16 at 14:07
  • Of course you can, that my case to group all my plugin settings options and my cpt fields to access them in one shot. – Benoti Nov 8 '16 at 14:25
  • 2
    This is explained in What is the index 0 for on post meta fields? – fuxia Nov 8 '16 at 14:55
  • 2
    The alternative for multiple entries is a serialized array or object. A very bad idea, you should never store a PHP proprietary format in a database. – fuxia Nov 8 '16 at 15:28
11

In general, storing PHP serialized data in database in a bad idea. It can be easily understood if you use multple key-value pairs of data in one field row, that is, you use an array or a object with one meta key.

Imaging a car as the object. You can set multiple meta values to describe the car, for example color and fuel. You can serialize the data and store it in one meta field (only one meta key):

$metadata = array(
    'color' => 'white',
    'fuel'  => 'diesel'
);
// as it is an array, $metadata will be serialized automatically by WordPRess
update_post_meta( 458, 'car_meta', $metadata );

In this example, you can use get_post_meta() with the third parameter set to false;

$carmeta = get_post_meta( 458, 'car_meta', false );
// Serialized meta is unserialized automatically by WordPress
echo $carmeta[0]['color'];
echo $carmeta[0]['fuel'];

Or you can use it with true, it is not a big difference:

$carmeta = get_post_meta( 458, 'car_meta', true );
echo $carmeta['color'];
echo $carmeta['fuel'];

Now imaging you want to get only red cars thar run diesel. You would need to get all cars and their meta data from database, and loop over all cars, unserialize the meta data and search the white cars that run diesel. This is really bad.

On the other hand, if you use a meta key for each meta data, for example:

$metadata = array(
    'car_color' => 'white',
    'car_fuel'  => 'diesel'
);
foreach( $metadata as $key => $value ) {
    update_post_meta( 458, $key, $value );
}

then you can get what you are looking for directly from database:

$args = array(
    'meta_query' => array(
        'relation'  => 'AND',
         array(
             'key'   => 'car_color',
             'value' => 'red'
         ),
         array(
             'key'   => 'car_fuel',
             'value' => 'diesel'
         )
    )
);

$query = new WP_Query( $args );

Now imaging that a car can be available in multiple colors, you could do this:

$metadata = array(
    'car_colors' => array( 'red', 'white' ),
    'car_fuel'   => 'diesel'
);
foreach( $metadata as $key => $value ) {
    update_post_meta( 458, $key, $value );
}

Now we have car_colors meta key with a serialized array. We face the same problems described before if we want to query only for cars available in one color. So, it is better to store colors as repeater meta field:

$metadata = array(
    'car_colors' => array( 'red', 'white' ),
    'car_fuel'   => 'diesel'
);
foreach( $metadata as $key => $value ) {
    if( is_array( $value ) ) {
        foreach( $value as $val ) {
            // We add multiiple meta fields with the same meta key
            add_post_meta( 458, $key, $val );
        }
    } else {
        update_post_meta( 458, $key, $value );
    }
}

Now, if you want to get all available colors of a car, you need the third parameter of get_post_meta() set to false, if you set it to true you will get only the first available color found in database for that car.

// This gets only the first car_colors entry found in database for car 458
$available_colors = get_post_meta( 458, 'car_colors', true );
// This gets all the car_colors entries for car 458
$available_colors = get_post_meta( 458, 'car_colors', false );

It is very basic example but I think it illustrates a use case where third parameter of get_post_meta() makes sense, so I hope this answers your question.

Another example could be the one exposed in other answer about shows that are performed several times within a day, for example a movie in a cinema. You want "starting times" to be a repeater field, not one field with all the starting times stored as serialized data.

About the other quesiotn: Does adding $prev_value to update_post_meta() create a history as array elements? No. If you pass $prev_value to update_post_meta(), only the existent row in database with that value will be updated; if $pre_value is not set, all rows for the meta key will be updated.

Finally, if you want to delete all available colors of a car:

delete_post_meta( 458, 'car_colors' );

And if you want to delete only one entry with a specific value:

delete_post_meta( 458, 'car_colors', 'white' );
-1

It is not so much get_post_meta as add_post_meta that is important here.

In the naive implementation os meta fields, as exposed by the custome fields UI, you can have multiple values assigned to one meta key.

It was probably a lapse of judgment by someone that envisioned that arrays of data will be stored by adding and removing rows to the meta table, instead of realizing that for 95% of the applications serialization is a much better option at least from the POV of readable code. A simple better alternative could have been to reverse the default of that parameter.

There are still 5% (ok, maybe 1%) usages for which this is actually an helpful way to store meta data - when you need to perform a query on it. Easiest example is probably a site which hold the movies at the local theaters and you want to know what is on tonight (8pm - 9pm start time). If you store start times, each in its own db meta row, it is trivial to write a wp_query to return all the relevant movies, while almost impossible if the data is serialized.

  • I appreciate the answer but I'm pretty good with code. Please show me an example that I can test. I do like where this is going though. – jgraup Nov 8 '16 at 14:16
  • you can make a query with serialized value and use maybe_unserialize($metas) – Benoti Nov 8 '16 at 14:41
  • 1
    @Benoti, no, you can't use unserialize in a query. You can't construct a query on serialized data without knowing how many items are in the data and the exact format of them.... or at least it is very non trivial – Mark Kaplun Nov 8 '16 at 14:44
  • $args = array( 'meta_query' => array( array( 'key' => 'ma-meta', 'value' => maybe_serialize( array("bar" => "foobar") ) ) ) ); $query = new WP_Query( $args ); found here screenfeed.fr/blog/… – Benoti Nov 8 '16 at 14:51
  • @Benoti, 1. not trivial 2. how do you compare integer values?. Compare here means <, > etc, not equality – Mark Kaplun Nov 8 '16 at 15:14
-1

If you have a serialize value in the meta, you can set it to true and get the unserialize array.

So it could make sense if you need to pass it through a form to set it to false, the value will be ready to be send.

Note that get_post_meta() is a simple function that return the result of get_metadata. This function uses: maybe_unserialize() to unserialize the metadata before it is returned.

From the codex (translated from french from this page):

This may not be very explicit in the case of serialized string. If you retrieve a serialized array with this method, you need to set $single to "true" to actually get a de-serialized array. If you go to "false", or if you leave it blank, you will have a picture of one, and the value at index 0 is the serialized string.

  • I appreciate the answer but I'm pretty good with code. Please show me an example that I can test. – jgraup Nov 8 '16 at 14:14
  • I will later, I can't find a simple example. I have some work to finish and I will. Can you find my link in english ? It can find it !!! and as I didn't find example I ran in the past, I don't know but this info appears recently,I noticed that a few weeks ago. – Benoti Nov 8 '16 at 14:22
-1
$meta = get_post_meta( get_the_ID(), 'meta_key', true );

'meta_key' is an example meta key.

if you use 'false' in the third parameter you will get result in $meta in the form of an array(). you can not echo like this e.g echo $meta; you will use echo $meta[0];

if you use 'true' in the third parameter you will get the result stored in the $meta variable as string. you can echo the result e.g echo $meta;

if you leave the third (Boolean) parameter it is set to 'false' by default so it prints the results as an array();

to understand this, use the following code inside the loop and you will see the results.

$meta = get_post_meta( get_the_ID(), 'meta_key', true );
echo '<pre>';
print_r($meta);
echo '</pre>';

change true to false and see the results. also change 'meta_key' to your meta key.

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.