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.
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' );