Blog Pile, Wordpress

Put on Your HazMat Suits- Setting Up Metadata For WordPress 3 Custom Content Types


cc licensed flickr photo shared by StayRAW

In the previous posts in this series of using the new WordPress 3 Custom Post Types (I keep calling them custom content types, same thing), I overviewed the plans for the MIDEA web site, we set up the places to create the new content types, and diverged into some set up magic using child themes.

That was the easy stuff. Now I get into the parts I had to more or less invent on my own (well, with some good leg ups from others)- how to add all of the form field elements to my new content types so I could add extra information to them. This are fields for say, my Organization content types, to have a field to enter their web site address, latitude/longitude for doing some mapping, etc.

Now I did this all in custom code, and as hopefully I stated earlier, I have no expectation that this is the way it will be dobe going forward. I foresee a raft of new plugins coming in that will take away this manual code layer, and maybe, when WordPress 3.7 or 4.1 comes out, it might be built in. I have no idea. I did this to show the WP platform can do this.

What we are working towards is creating a place like this for my Organization content type when I create or edit new content:

So returning to our functions.php editing, the first thing we need to do is to activate the bits to turn on the lights inside the WordPress dashboard; adding in the top sequence of our code:

which again, puts a “hook” in the wordpress flow to include the admin functions I want to add. This new function will in turn set up what is needed to add “metaboxes” to the wordpress editing pane- these are my own editing form elements.

Here we use the add_meta_box function to do the work. The variables I am passing, for say the Organization types are:

  • org-meta a unique id just to identify the metabox, likely used to track in the database. I named mine in line with the content type slugs.
  • MIDEA Organization Details the title that will appear in the top of the box
  • midea_org_options the “callback function”, meaning my own function that will be used to do the set up work.
  • org the internal name I set up previously for this content type.
  • normal the placement of the metabox- normal is the main pane (below the post editing field). I could also put it on the right side if I use the value ‘side’
  • low I’m not sure what this does, the codex says “The priority within the context where the boxes should show”; perhaps if it is set to “high” it might appear above the main post editing field?

As something we will need quite a bit, I came up with this approach to define the meta data fields for my content types (as opposed to tossing around global variables). I call one of these when I need to create a code “container” for each content type’s meta data, and later we will use database calls to put in the actual values. But as a utility, this simply returns an array of the metadata, all set with initial empty string values.

Now we are ready to create some metaboxes! For our Organization type, this is the callback function that creates the pieces shown in the image above.

So roughly, as a narrative, this is what I am doing. We always have to add this thing I dont fully understand, but is a security to make sure the form data is coming from my own code, a “nonce”, a hidden form element. The value you use “MyNonceCode” should be any unique string (don’t use that string, its just a placeholder). If you do not do this, any data you add will not “stay”in te database, as WordPress does its own internal cleanups. I think.

Next, I use the functions listed above to get my meta data container, and I cycle through them with the get_post_meta function to grab any values that already exist. If you look carefully, I use the array keys to define the meta data, prefixed in this case with “midea-org-” to identify it in the database.

And lastly, I just echo what I need to build the form fields I want. It may be more code clean to use a function approach as described in Genuine Juice’s key guide to creating these elements but I knew I would adding some very specific labels to my form elements, and I wanted full control. Hence the HazMat suit.

I’m not going to march through all the details of my other two content types, but they are included in my sample code below. The extra wrinkles here was for say, my Project content types, as I wanted one meta data element to be a drop down list of organizations I could associate a project with- so this involved writing a function to get all my Organization names and database ids, and build a menu out of that– isn;t this cool- I use one custom content type as an elemnt to create meta data for another.

And the Events content type had to do some extra work to deal with the date/time entry fields. Instead of creating a series series of month, day, year, hour, minute fields or using some Javascript widget, I took a simpler approach of a single field and using PHP’s strtotime function to convert it to a unix time stamp, which is what we store in the database. There is a bit of gymnastics here for events- if it is a single day event, we look at the time values to generate start/end times. If it is a multi-day event, we just want to know the month/day/year values.

So for now, we can create the form fields for entering data, but we have to add more code to have WordPress save it all.

We have to add another “hook” at the top to tell WordPress do do our extra bits when a post/content type is saved.

The midea_save_post is the callback function used when we save anything- I honestly lost track of what the extra variables do (I did read up on it and just used values I saw used in the examples).

So here is the function I made to save my meta post data

This is a bit more complex, and again, I just modified it from examples I found form early HazMat suit wearers. It uses that same “nonce’ thing (make sure your codes match). I am not 100% sure I needed that hack of using $post_flag I thought at one point I needed to make sure I did not run this function for saving any post type.

Basically, I am setting up my post meta data array, and then looking through the submitting form POST values to see if we have a value there. If we have this already in the database, we need to remove the old data first (delete_post_meta), and then add the new data (add_post_meta).

So now at this point, we can add this metadata, and if we have done it right, when we go to edit, the current values, if they exist, are pre-populated in the fields.

Whew. Anyone still breathing?

The last bit is some useful things you can do to customize the layout when you go to the Edit content types area- you can generate your own list of columns relevant to your content types. For example, when I go to edit my Organization content types, I get this interface:

So rather than a blog or page post title, my columns list the organization name, plus (from my own post meta data) the organization’s URL and their address. I can make any columns I want, and can even manipulate the output anyway relevent (like I made the URL a hyperlink).

To do this, we need to modify our content type creator function midea_custom_init() to include 2 new actions added for each content type, in the case of organizations:

This creates a callback function org_custom_columns used to generate the view above, and uses the org_columns function to define the columns. These functions look like:

So org_columns merely defineds an array of the columns (“cb” is the built in check boxed for multiple editing, and the org_custom_columns function defines the output for each type; you can see for the URL where I do the extra work to extract my meta data values and build a hyperlink.

My sample code below includes the other functions used for my own other two content types. They have a bit more gymnastics, but follow the same concept as above.

So here is e the functions.php cod I have made up to this point. We have set up everything we need to do to create, edit custom content types, the next step is to do some WordPress theme hacking to set up the output. Easy peasy, eh?

For the other parts of this convoluted series…

You can find all the posts in this series at http://cogdogblog.com/2010/07/23/roundup-wp3/

Profile Picture for Alan Levine aka CogDog
An early 90s builder of the web and blogging Alan Levine barks at CogDogBlog.com on web storytelling (#ds106 #4life), photography, bending WordPress, and serendipity in the infinite internet river. He thinks it's weird to write about himself in the third person.

Comments

  1. First of all I wanted to thank for this amazing tutorial , I am very carefully watching this post , I am trying to create multiwebsite for nightclub owners where everyone can create their own website and this post and child themes are exactly what I need , instead organizations I will have nightclubs , events will remains , projects I dont know yet but I will find solution also for that , for me coding is impossible at this moment because I’m programmer – ignorant yet, but copy , edit , delete and paste I know well and I hope that very soon in future thanks tutorials like this I will discover the way how to understand things well.
    One thing I wanted ask you now : Is it hard to change latitute and longitude with something like one of the plugins in wordpress where you enter the address and output will be exact Google map address of the organization? This plugin after you enter right address gives you exact Google map , it should be nice connection with this plugin because you don’t need to search for latitudes etc , it will grab your info from address fields.
    btw. I use changed default theme from developer pack wordpress 3.0 . Keep up good work ! Daniel

  2. Another question wanted to ask you: was studying your mother website of this wonderfully described post type hack (Midea ) and I would like to know whether you are also planning to add some frontpage interface for your website members for adding museums , projects , events theirselves ? At this moment I suppose that everybody has to email you to be included in your database etc and you have to go in your admin dashboard to add it there. I think that it would be better to let the people add their projects , organisations , events themselves in the frontpage and you will only moderate them , it means much less work for you . I am sure that post types will be new hit between wordpress fans and I hope that in wordpress directory they will create new category “post types” (like plugins , widgets etc .)where everybody can get the codes for their functions.php . Only thing I miss now is that somebody should come with some interface to use the post types in frontend.

    1. @Daniel,

      There are a few code bits I’ve not explored that allow you to create some editing privileges on custom content, but I;ve not explored it in depth. The site I was working on is not a giant site where we are collecting a lot of user created content, so its a different scenario of managing it.

      The things you seek will likely emerge as plugins.

  3. Are you planning on doing an entry about how to take the data, format it and display it on your public site? I realize that is like asking for a dessert on top of dessert, since you’ve been so helpful already. So far, the only help I’ve found with that is “sure, easy, modify the loop”. Yikes!

  4. Alan-
    What a wonderful aggregation of meta-box resources and a fine walk through by you! It is much appreciated as this is a more highly technical aspect of WordPress for the advanced user.

    At WordCamp Chicago I asked Jane Wells (core WP developer, UI focused) about the possibility of a built-in UI for custom post types à la Drupal’s CCK/Views/Blocks powerhouse of modules. She referred the audience to the Custom Post Type UI plugin by Brad Williams.

    While this plugin is a “nice” step in a UI direction, it is too simplistic to really do anything with. Like you wrote, we will hopefully see the core team or a dedicated plugin creator create something comprehensive that not only handles the custom post types but also the meta-boxes and the front-facing display of this content.

    I’m creating a thorough research knowledge base in preparation for my PhD work in the fall all with custom post types. There have been plenty of times that I’ve said, “Why am I not doing this with CCK?” In the end, my “allegiance” to WordPress and my desire to learn something new about WP and PHP keeps me chugging along despite the urge to fall back on something easier to use.

    Alas…

    Thanks for your hard work-
    ~Kyle~
    @thecorkboard

  5. Hi Alan

    thanks for the indepth step-by-step article!

    One question: is there any way to make the columns sortable (with a little arrow at the top of each column) so you could sort by address or website or status?

    looking forward to the next installment :) thanks again

  6. Hello Alan , I wanted to ask you , did I miss this somewhere ?
    Christina says:
    June 10, 2010 at 5:48 am
    Are you planning on doing an entry about how to take the data, format it and display it on your public site? I realize that is like asking for a dessert on top of dessert, since you’ve been so helpful already. So far, the only help I’ve found with that is “sure, easy, modify the loop”. Yikes!

    Reply
    Alan Levine aka CogDog says:
    June 10, 2010 at 7:22 am

    @Christina- that part is coming in the next installment (it might be next week), and I’ll show you some loop examples of how to do this, and more.

  7. ok Alan , I understand , I have a lot of work too, so I didn’t check it out here very often, I only wanted to know if I miss it somewhere , it should be a pity to do not finish this great series, Thanks for it -:)

  8. Have you checked the update works properly. By properly I mean no duplicates in the DB, pretty sure every time you update a post this will add a whole new lot of meta_key and meta_values to the wp_postmeta table.

      1. Im not sure how elegant this is but it seems to work.

        // If value is a string it should be unique
        if (!is_array($value))
        {
        // Update meta
        if (!update_post_meta($post_id, $key, $value))
        {
        // Or add the meta data
        update_post_meta($post_id, $key, $value);
        }
        }
        else
        {
        // If passed along is an array, we should remove all previous data
        delete_post_meta($post_id, $key);

        // Loop through the array adding new values to the post meta as different entries with the same name
        foreach ($value as $entry)
        add_post_meta($post_id, $key, $entry);
        }

Leave a Reply

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