I would probably take an alternative route and let the serialization happen at the end after the data was already merged like in the example below.
So first query meta data for both old keys. Then merge the old data into an array (regular or associative) with post ID as key. Then use the resulting array in a loop which uses update_post_meta
to let it handle the serialization. Finally some $wpdb
query to wipe the data with the old keys from the database.
This might not be the most efficient way to do this, but if you’re executing this only once, then I don’t think it matters too much.
add_action('admin_init', 'convert_meta_data');
function convert_meta_data() {
$data = query_old_data( old_keys() );
$data = merge_old_data( $data ) ;
update_meta_with_new_key( $data, 'new_meta_key' );
delete_data_with_old_keys( old_keys() );
}
function old_keys() {
return array(
'field_1',
'field_2'
);
}
function query_old_data( array $old_keys ) {
$data = array();
global $wpdb;
foreach( $old_keys as $old_key ) {
$data[$old_key] = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM wp_postmeta WHERE meta_key = {$old_key}")
);
}
return $data;
}
function merge_old_data( array $data ) {
$out = array();
foreach ($data as $old_key => $records) {
foreach ($records as $record) {
$out[$record->post_id][$old_key] = maybe_unserialize($record->meta_value);
// I don't know what happens, if some of the data in the resulting array was serialized and some not, so lets make sure everything is unserialized
}
}
return $out;
}
function update_meta_with_new_key( array $data, string $key ) {
foreach ($data as $post_id => $meta_array) {
update_post_meta($post_id, $key, $meta_array); // handles serialization
}
}
function delete_data_with_old_keys( array $old_keys ) {
// not too sure about this
$sql = "meta_key = " . implode('OR ', $old_keys);
global $wpdb;
$wpdb->delete( 'wp_postmeta', $sql);
}