I'm replacing 2 fields that were previously set up with ACF and saved separately. Instead of those, I want to have 1 piece of serialized postmeta.
So, I'm going from
meta_key: old_key_1, meta_value: value_1
meta_key: old_key_2, meta_value: value_2
to
meta_key: new_meta_key, meta_value: a:2:{i:0;s:7:"value_1";i:1;s:7:"value_2";}
(I'm not querying on these, just displaying on single posts, so I'd prefer to have a single entry in the database that holds each post's meta.) Because I have several hundred posts to update, I'd like to do this programmatically, either in phpMyAdmin or PHP, but I'm not sure what queries to run.
Question 1 - this part is solved
How do I update field_1
to contain serialized data?
I added a temporary function to update the meta key and serialize the meta value of the first field:
<?php add_action('admin_init', 'convert_double_meta');
function convert_double_meta() {
global $wpdb;
$first_records = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM wp_postmeta WHERE meta_key = 'field_1'")
);
foreach($first_records as $record) {
// Serialize the meta value by passing it as an array
update_post_meta($record->post_id, 'field_1', array(0 => $record->meta_value));
// Update the meta key
$updated = $wpdb->update(
'wp_postmeta',
array(
'meta_key' => 'new_meta_key'
),
array('meta_id' => $record->meta_id)
);
}
} ?>
Question 2 - still unsolved
How can I merge the data from old_key_2
into the serialized value for new_meta_key
? (And if there's an easier way to complete all of this, I'm quite open to doing different steps to achieve the same result.)
I'm replacing 2 fields that were previously set up with ACF and saved separately. Instead of those, I want to have 1 piece of serialized postmeta.
So, I'm going from
meta_key: old_key_1, meta_value: value_1
meta_key: old_key_2, meta_value: value_2
to
meta_key: new_meta_key, meta_value: a:2:{i:0;s:7:"value_1";i:1;s:7:"value_2";}
(I'm not querying on these, just displaying on single posts, so I'd prefer to have a single entry in the database that holds each post's meta.) Because I have several hundred posts to update, I'd like to do this programmatically, either in phpMyAdmin or PHP, but I'm not sure what queries to run.
Question 1 - this part is solved
How do I update field_1
to contain serialized data?
I added a temporary function to update the meta key and serialize the meta value of the first field:
<?php add_action('admin_init', 'convert_double_meta');
function convert_double_meta() {
global $wpdb;
$first_records = $wpdb->get_results(
$wpdb->prepare("SELECT * FROM wp_postmeta WHERE meta_key = 'field_1'")
);
foreach($first_records as $record) {
// Serialize the meta value by passing it as an array
update_post_meta($record->post_id, 'field_1', array(0 => $record->meta_value));
// Update the meta key
$updated = $wpdb->update(
'wp_postmeta',
array(
'meta_key' => 'new_meta_key'
),
array('meta_id' => $record->meta_id)
);
}
} ?>
Question 2 - still unsolved
How can I merge the data from old_key_2
into the serialized value for new_meta_key
? (And if there's an easier way to complete all of this, I'm quite open to doing different steps to achieve the same result.)
- Do you need to preserve the old keys? In other words, should the new array use the old keys as their indexes? – Jacob Peattie Commented Jan 17, 2020 at 0:47
1 Answer
Reset to default 0I 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);
}