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