Store custom meta box data as serialized array

serialised PHP has security risks and can cause problems during search replaces if you change the length of values

The argument for the serialised array is that it only fills ‘one space’ in the database as opposed to multiple rows but it sounds like it is difficult to perform WP_QUERY on a serialised array and difficult to perform searches.

Yes, you can’t reliably query sub-sections of serialized data, and some types of query aren’t possible at all. If you must serialize, do it with JSON, but that only mitigates some minor issues.

Keep in mind:

  • post meta/custom fields are fast when you already know the post ID
  • get_post_meta is very fast, WP will prefetch the post meta so calling it twice does not create duplicate queries
  • meta_query/searching for and filtering by post meta is slow, and does not scale. If you need to filter, search for posts, then store that specific piece of data in a custom taxonomy.
    • For example, a product_category post meta, or a type post meta is a terrible idea, but they’re all great as taxonomies
  • You can have more than one meta value with the same key, meta keys are not unique, e.g. $cars = get_post_meta( $post_id, 'car', false ); foreach ( $cars as $car ) {...
  • WP serializes arrays and objects when you try to save them to be helpful, but WP is stuck doing this for backwards compatibility reasons and cannot stop. This does not mean it’s a good thing to do
  • You will find many people who have spent their entire careers doing things entirely with post meta who will resist advice otherwise, or think you’re advocating a total replacement. These things all have tradeoffs and are nuanced, the correct answer for how to store your data is going to depend on how you use your data
  • if you know that you are only going to display this data when on the post/page in a template, and will never need to search/filter for it, then you’re fine to store a JSON serialized structure. Just understand that to the database, a post meta value is just a string of text. It can’t see sub-structure in the columns WP tables use, and those tables are not optimised to search or filter for it.
    • this also means you can’t update/delete change sub-sections either, you have to fetch the entire structure, modify it in PHP, then save the entire value back. Same with deletion and addition etc

only fills ‘one space’ in the database as opposed to multiple rows

MySQL and MariaDB are capable of storing billions of rows if your storage can support it, that’s not the issue.

The issue is the type of queries you make. For example, you can make a query that runs fast on 10 million rows into a query that grinds to a halt on 500 rows by specifying you want a random order and specifying a NOT clause. Extra rows on their own won’t slow down your site, much like I can have 50 tiny plugins and be faster than a site with 1 chonky plugin that does everything badly.