Getting the most out of WordPress custom fields

WordPress custom fields are a pretty nifty idea that can allow you to add custom content to individual posts, outside of the standard content area. Most examples on how to implement custom fields show fairly innocuous uses, just inserting little strings of text in various locations. However, by populating the custom field with wonderfully portable JSON, it’s possible to perform much more complex and powerful actions on individual posts and pages.

A basic overview of how custom fields work can be found on the WordPress Codex. What you’ll see if you read through it is that custom fields work as essentially a two-level array. The first level is the array of all the meta keys associated with a particular post, and at the second level each key stores an array of values associated with that key. This structure allows quite a bit of flexibility, but I wanted to be able to build objects with dynamic depth without the built in two-level limitation.

If you’re comfortable with JSON syntax, this goal becomes surprisingly easy. Simply pass a well formed JSON string as your custom field value, retrieve it in the PHP of your theme files, and use json_decode() to convert the string to a generic PHP object. With that setup, you can pass custom field values with a virtually unlimited amount of metadata attached.

How I use it on this site

I started using the method described above on this site to get the “Downloads” sidebar widget working the way I wanted it (examples: single post, blog/archive page). I wanted to be able to specify the following things on each individual post:

  • An unlimited number of associated downloads
  • Custom display text and URL for each
  • A boolean representing whether the link should display on blog/archive pages as well.

To do this, I use a JSON string that defines two-levels of depth (for those of you keeping score at home, that means we now get four total levels out of each custom field). The first level is simply a count of each download defined for that particular post. So far I haven’t needed more than one, but I want the option to expand to be there. Within each of those items, I define three properties, the display text, the URL, and the blog/archive boolean. The result for the example post linked above looks like this:

Display on an individual post

Displaying the custom data within a post’s page is pretty easy. Just edit your theme’s single.php file (or its equivalent, if your theme calls it something else) and make the call to get_post_meta() wherever you need it. In my case, I don’t want to display the “Downloads” widget at all if there’s no downloads associated with that post, so first I check to make sure that get_post_meta() doesn’t return empty, then insert the necessary HTML.

Display on a blog/archive page

Using custom fields from posts on archive pages which contain them is a little trickier, but still very doable. The first thing you need to do is collect the IDs of every post included on the page. I did this by creating an array and adding to it with every iteration of The Loop.

Once The Loop ends and we have all the post IDs, we can create an array of custom field values from each post.

Now we have our array, but it probably contains some empty items since not every post is going to contain a value for the custom field. To filter those items out, I created a new array, and moved only items with a value into it.

At this point all the items in the array will have a value, but we still don’t know if they should be used on this page. Each download object has a property called ownPageOnly that will be set to “false” if it should display here, “true” if it shouldn’t. I filtered out these items in two separate steps. First I made sure that each post left in my $downloadsArray had at least one item that was set to “false.”

After that we can be sure that if the $downloadsArray is not empty then there must be at least one download item that should be inserted into the page. So we create the widget HTML exactly the same way as was done in the individual post, and only change PHP script inside the <ul> tag. The adjustments are necessary because:

  • Each download object is now a member of a parent array, adding another layer of depth to loop through
  • We still need to check each item to make sure “ownPageOnly” is set to “false”

This all combines to create a pretty seamless system where the values that I specify as a custom field in each post are propagated throughout the site, wherever the post is used. I think it would be possible to duplicate this behavior while staying within the standard functionality of WordPress custom fields, but that approach would have felt cumbersome and unwieldy to me, whereas this feels intuitive and the way data should be handled. I’m also reasonably confident that this approach opens the door to a whole world of possibilities that are not available if you just treat the values of custom fields as strings.

Tagged with: ,
Posted in HTML & CSS, PHP, Server Side Code, WordPress
One comment on “Getting the most out of WordPress custom fields
  1. mark2013 says:

    Hi Ben, that is a really innovative way to use custom fields! I also like your post on the Ajax database form; that’s inspired.

    Good work, hope you get the rest of the site template sorted 😉

Leave a Reply

Your email address will not be published. Required fields are marked *