WordPress serializes options and meta for you

When tracking down a potential bug last week, I noticed that many plugin authors were making the same mistake and were making their lives much more difficult in the process. The issue was related to the serialization of data (here’s the PHP manual entry). In the most basic use case, serialization is a way to store arrays and objects directly in the database, which can only store numbers, text, and dates. Serialization takes an array and turns it into a serialized string. For example:

$data = array( 'apple', 'banana', 'orange' );
echo serialize( $data );
// Result is a string we can unserialize into an array:
// a:3:{i:0;s:5:"apple";i:1;s:6:"banana";i:2;s:6:"orange";}

WordPress has a few helper functions that we use instead of serialize() and unserialize() — maybe_serialize() and maybe_unserialize(). The first only serializes data that needs to be serialized — arrays and objects — and the second only unserializes data that is already serialized. (We have a lot of handy functions like these.) At some point in 3.0, something changed, and it caused an error for plugins using get_post_meta(). Matt Martz and I tracked this down to a change in maybe_serialize():

It comes out of a change to maybe_serialize() in r13673, which for a long while serialized already serialized data, and now no longer does. We’ll probably revert this. [Which I did in r14074.]

This shouldn’t have broken plugins however, at least not in this case. But here’s what the plugin was doing:

update_post_meta( '_my_plugin_meta', serialize( array( 'foo', bar' ) ) );
unserialize( get_post_meta( '_my_plugin_meta' ) );

The unserialize and serialize bits are unnecessary. The post, comment and user meta functions, and the functions for options and transients (and site meta) all transparently serialize and unserialize data for you. Thus, this works:

update_post_meta( '_my_plugin_meta', array( 'foo', bar' ) );
get_post_meta( '_my_plugin_meta' );

I explained what was going on in #12930. Thanks to Ipstenu for raising the ticket, as we would have received a lot of complaints due to the change:

More or less, that means that you’re serializing the data, then update_option is serializing serialized data, then get_option is unserializing it once, and unserialize is unserializing it again. r13673 breaks this, as update_option doesn’t serialize the data a second time any more, causing the plugin’s unserialize() to attempt to perform a second unserialize() on data that was only serialized once.

In this case, the change was accidental, and we already went through this once nearly two years ago (see #7347r8100r8372, and others). But sometimes plugin developers that the API incorrectly or make bad assumptions makes it significantly more difficult for us to improve WordPress, as we are very mindful of plugins we may break — even if the plugin is “Doing It Wrong.” So please, don’t make it harder for us to make it easier for you.

20 thoughts on “WordPress serializes options and meta for you

  1. Happy to say that this wasn’t a way in which I was “Doing It Wrong,” although WP_DEBUG continues to show me other ways I can improve…

    I will try not to stand in the way of WP’s ascending to the aether of CMS bliss.

  2. Do you think maybe you could add a feature into wordpress.org to start checking for obvious “mistakes” like this and provide the plugin developers with a warning?

    In a similar vein I would *love* to be able to go to WordPress.org and see a list of all plugins that use a specific hook and then be able to view the source code for that hook so that whenever I need to use a hook I could easily find many examples of code that is using it.

    JMTCW.

  3. I found this entry while searching on Google to verify this. I think noone likes to do it wrong, but the Codex says the meta value must be a (string) so it’s not so intuitive. It should be changed to (mixed) maybe.

  4. Agreed – the documentation needs an overhaul to reflect that if you want people to “stop doing it wrong”. I’d read that documentation before, and assumed I had to serialize any arrays etc.

    How do we get that changed?

  5. Pingback: In WordPress, prefix everything | Andrew Nacin

  6. Question from the back row: So does this mean all arrays passed `update_post_meta` and `get_post_meta` are automatically (un)serialized?

    • Yup. When calling get_post_meta, you’ll get the data back unserialized. Same with all get_ functions in the options, transients, post meta, comment meta, and user meta APIs.

  7. andrew, i’m working on a plugin where i want to cache an object as a transient option. if i don’t serialize the object, the option isn’t saved, when i use maybe_serialize() on the object it is saved. are there any known issues that would cause this? i can make it work the wrong way, but i’m more interested in the correct solution. thanks.

  8. I was trying to serialize data before updating usermeta in a plugin of mine. It took me about an hour to realize that WordPress did it for me. I started searching through the core files until I found maybe_serialize(). That was my first hint. I googled it, and had my answer.

    p.s. Lots of good stuff on this blog. :)

  9. Pingback: Warning for wpml users (do not upgrade yet to wpml 2.3.4) | amr ical events

  10. Pingback: Data portability and data serialization in WordPress | WP Garage

  11. Pingback: Handling WordPress meta data and post revisions | Nothing But Words

Comments are closed.