1

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 Jan 17 at 0:47
0

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);
}
| improve this answer | |
  • Thank you! admin_init was actually running more than once for some odd reason, so I used a modification of this - added a dashboard widget where if a certain $_POST variable was set it ran the function, and if not it showed a form with that hidden $_POST input and a submit button to ensure it only ran once. Very odd things happened when it ran multiple times! – WebElaine Jan 17 at 21:11

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.