Fork me on GitHub

article

WordPress export, import and double serialization.

August 2, 2010 | Web Design & Development, WordPress

Ran in to a fun one in the WordPress core today. If your plugin stores post meta and you store that post meta as an array then you’re prone to a bug in the WordPress core that can break your data should someone export their data and reimport it on another WordPress install. Yeah, this is a small minority of what actually goes on in WordPress but when you’re dealing with migrating data from one install to another, or are trying to supply complex sample data with a theme distribution, then things like this tend to get on your nerves. Quickly.

I’m gonna sound jaded through this writeup, but I’ll get over it.

Say your plugin saves and retrieves data correctly, like this greatly oversimplified example:

  1.  <?php
  2.  global $post;
  3.  $postmeta = array('one','two','bunnies');
  4.  add_post_meta($post->ID, 'my-meta-key', $postmeta);
  5.  // ...
  6.  // and later
  7.  // ...
  8.  $postmeta = get_post_meta($post->ID, 'my-meta-key');
  9.  ?>

You’re properly using the post-meta api and your array is serialized in the database, all safe and sound.

Now imagine your user migrates to a new host, exports a WXR and imports that WXR on their new host. Your data will break. Why? On import your serialized array is then double serialized as a string. The post-meta in the WXR is imported the same way as if the data had been saved programmatically which means it makes a trip through the function maybe_serialize. Unfortunately maybe_serialize has a bug that explicitly serializes already serialized data. So now your data is broken because your serialized array has just been serialized as a string. Don’t expect this behavior to change any time soon. The core WordPress team is too worried about breaking the functionality of plugins who have been saving data the wrong way to try and make this function work correctly. You have to safeguard yourself against its behavior.

Its not a lost cause, though, you can protect yourself by being a bit more verbose when pulling your post meta. When retrieving your post meta don’t assume that you know how its gonna come out. Yeah, it sounds funny, but its better safe than broken. Simply changing the above code by one line can help protect your data when it moves from server to server. Like so:

  1.  <?php
  2.  global $post;
  3.  $postmeta = array('one','two','bunnies');
  4.  add_post_meta($post->ID, 'my-meta-key', $postmeta);
  5.  // ...
  6.  // and later
  7.  // ...
  8.  $postmeta = maybe_unserialize(get_post_meta($post->ID, 'my-meta-key'));
  9.  ?>

By wrapping the get_post_meta function call in a maybe_unserialize call you force the data coming out of the database to be inspected one more time and then double-unserialize if necessary. Its extra work but it can save your butt.

8 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  • Hi,

    I am I completely out of luck if I have the meta key as an array of meta keys?? e.g.

    $data = get_post_meta($post->ID, $array, true);

    If you could help that that would be legendary!! 😉

    Andy, August 5, 2010 1:34 am | permalink

  • Does that work at all?

    Shawn, August 5, 2010 7:42 am | permalink

  • HI! I need help on how to get the values of the custom fields (all pages) with a search function.

    e.g. I have a custom field named keywords in all my pages which has a value of ‘jose’.

    If I enter ‘jose’ in the search box. Then all pages with custom field keywords w/ a value ‘jose’ must display.

    Please help! Thanks!

    bella, August 26, 2010 4:21 am | permalink

  • Bella, that’s a little beyond the scope of this article and a comment.

    Shawn, August 28, 2010 11:47 pm | permalink

  • Hi Shawn,

    Yes it works great apart from the import/export. I just get a load of “a” characters when I import.

    Any light you can shed on this?

    Andy, October 23, 2010 3:53 am | permalink

  • That doesn’t sound right at all. I’d have to see what your WXR looks like to start with that one.

    Shawn, October 23, 2010 8:59 am | permalink

  • Let me ask you this, since the data will get fixed during runtime … meaning when a user goes in the a post and makes a change where the data gets rewritten to the wp_postmeta table … if a post is never rewritten and the site goes through a second or third export/import, I assume there exists a possibility of the data getting triple and quadrupole serialized …

    I’d like to find a way to hook into the import and do a mass fix…

    Dimas, November 24, 2010 1:19 am | permalink

  • I tested multiple imports and each get serialized each time, causing triple, quadruple, etc. serialization.

    My solution was to use the “import_post_meta” action of the wordpress-importer plugin (which is default) and correct the double serialization on import.

    Here is my final code: https://github.com/farinspace/wpalchemy/commit/33892fb4f90ba0c3c26bfedfea98ad7e4ea5b356

    Note the stripslashes() function call (its important).

    Dimas, November 24, 2010 2:40 am | permalink

Comments are closed