4

When adding arrays to post meta, using add_post_meta, new sub-arrays are added. I was wondering if there was a way to have those sub-arrays named.

so instead of ending up with

array([0](2,3), [1](4,5))

I would get

array ([meaningful_name](2,3),[meaningful_name2](4,5))
2
  • What are your save/update calls look like? I don't quite follow why is this an issue.
    – Rarst
    Oct 21, 2015 at 18:31
  • The reason it's an issue is because it makes it more taxing to check if an item is in the array. In my case the custom field will store user submitted content. If the subarrays had meaningful names I could just do something like in_array(userID) and then name the subarrays with the relevant user ID's. Instead I need to iterate through the subarrays checking each one for the user id, then deal with settings flags and whatnot. Oct 22, 2015 at 3:04

2 Answers 2

9

When multiple meta values are used for same meta key, WordPress store the values in different database rows. So every array, is stored in one row.

Initial Data

Let's assume you have an array like this:

$family = [
  'father'  => [ 'John', 'Doe', 40 ],
  'mother'  => [ 'Jane', 'White', 39 ],
  'child_1' => [ 'Luke', 'Doe', 5 ]
];

If you store each sub array as a different meta row, the only identifier for that row is the meta_id but it's not really meaningful and is hard to get using WordPress functions.

The "map" approach

A workaround could be to store a map of values / meta IDs in another post meta.

That can be done thanks to the fact that both update_post_meta() and add_post_meta() return the meta ID just added.

Store Data

So you can do something like this:

$map = [];
foreach( $family as $who => $person ) {
  // update_post_meta returns the meta ID
  $map[ $who ] = update_post_meta( $postId, 'family_member', $person );
}
// we store the map of family "role" to meta IDs in a separate meta
update_post_meta( $postId, 'family_members_map', $map );

Retrieve Data

When you retrieve values, e.g.

$family = get_post_meta( $postId, 'family_member' );

you get a 2 dimensions unkeyed array like this:

[
  [ 'John', 'Doe', 40 ],
  [ 'Jane', 'White', 39 ],
  [ 'Luke', 'Doe', 5 ],
]

In short you loose the sub array keys.

But you can use the map you stored and the function get_post_meta_by_id to recreate your original data:

$map = get_post_meta( $postId, 'family_members_map', true );
$family = array_combine( array_keys( $map ), array_map( 'get_post_meta_by_id', $map ) );

And family will be equal to the original data:

[
  'father'  => [ 'John Doe', 40 ],
  'mother'  => [ 'Jane White', 39 ],
  'child_1' => [ 'Luke Doe', 5 ]
]

Update Data

Update data, it's not very hard:

$justBorn = [ 'Anna', 'Doe', 0 ];

// current map
$map = get_post_meta( $postId, 'family_members_map', true);

// add both new sub array and new meta ID to map
$map['child_2'] = update_post_meta( $postId, 'family_member', $justBorn );

// update the map
update_post_meta( $postId, 'family_members_map', $map );

An alternative: the "all in one place" approach

The approach above works, but it's not the easiest way.

In fact, would be easier to store the whole initial associative array (the $family array) is a single meta instead of in different sub-arrays.

// store data
update_post_meta( $postId, 'family_members', $family );

// retrieve data (please note the `true` as 3rd argument)
$family = get_post_meta( $postId, 'family_members', true );

// update data
$family = get_post_meta( $postId, 'family_members', true );
$family['child_2'] = [ 'Anna', 'Doe', 0 ];
update_post_meta( $postId, 'family_members', $family );

To store, retrieve and update data is quite easy and there's no additional overhead.

Advantages of the "map" approach

In most of the cases, the "all in one place" approach is the most convenient.

But if there are hundreds or even thousands of sub arrays, using an unique meta value to store them all would result in a very large amount of memory used to fetch and parse data. Using different rows and a modern PHP feature like generators, that amount of memory can be drastically reduced.

Moreover, when dealing with existing data (maybe inherited from old version of the website), this approach could be helpful to obtain meaningful information without conversion of old data.

Finally, having smaller and more characterized sub arrays stored in different DB rows, a query for posts using meta query and LIKE against the serialized array in the meta value could be easier and more reliable, even if the actual reliability depends a lot on the structure of the data.

3
  • Quite informative, specially the "map" approach ;-) Oct 21, 2015 at 19:26
  • Thanks. This is super informative and extremely thorough. Oct 21, 2015 at 19:43
  • if want to update post meta programatically, the 3rd argument = true its live saver
    – Andy
    Feb 12, 2019 at 3:27
0

Some possible ways for using add_post_meta :

For details please follow link

add_post_meta($post_id, $meta_key, $meta_value, $unique);
update_post_meta($post_id, $meta_key, $meta_value, $prev_value);
$meta_values = get_post_meta( $post_id, $key, $single );



 update_post_meta($post_ID, {key}, {array of vals})

 $data = Array(
    'url' => $url,
    'name' => $name,
    'description' => $desc,
 );

 //Update inserts a new entry if it doesn't exist, updates otherwise
  update_post_meta($post_ID, 'yourkey', $data);

 //To Fetch
 $yourdata = get_post_meta($post_ID, 'yourkey');

Codex link for details

Thanks!

1
  • Correct, this is how I use it. if you print out 'yourkey' you will get an array of anonymous arrays. It will look like; Array ( [0] => Array ( [v1] => 1 [v2] => 2 )[1] => Array ( [v1] => 1 [v2] => 2 ) ). What I'm looking for is to name the [0] and [1] Oct 21, 2015 at 19:03

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.