Pergunta

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.)

Foi útil?

Solução

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);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a wordpress.stackexchange
scroll top