The question:
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.
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 1
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' );
Method 2
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.
Method 3
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.
Method 4
$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.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0