WordPress as a CMS: Posts as content elements

I started writing a comment for the DevLounge article “Things To Consider When Using WordPress as a CMS” but it turns out I had a lot more to say.  I’ve been working with WordPress for a few years now and I want to share one of the toughest challenges I’ve personally faced when using WordPress as a CMS: jamming content into a complex design and still enabling the client to easily update it.  The operative word here is easily.  The client needs the WYSIWYG editor for all their copy editing.

To achieve this, we need to isolate content elements that make up the complex design.  A “content element” is CMS jargon but in WordPress terms, content elements can be posts.  For example, this page from the web site I built a couple months ago contains several content elements.  In addition to the “Myths, Fears, and Facts” article (which is a content element itself), there are two content elements in the sidebar with titles “Jo Krombholz’s Story” and “There’s No Excuse.”  The following screenshot highlights all content elements in blue:

If you’re familiar with custom fields, you may be wondering why I didn’t just dump the content into custom fields for these content elements.  There are actually a couple of reasons: a) custom fields are not WYSIWYG-enabled and b) custom fields can only relate to a single WordPress page (or post) while some content elements are related to several different pages.  For example, the content element “Jo Krombholz’s Story” is also featured on its own page in addition to being shown in the sidebar of the “Myths, Fears, and Facts” page.

So, how do you get WordPress posts to behave as content elements?  By using custom fields to create relationships between pages and posts.

We add a custom field named “feature_story” with the value “23” to the page “Myths & Facts.”  The value “23” is actually the ID of the post “Jo Krombholz’s Story”.  Now we can use this relationship in our theme template.

In the WordPress theme template used by “Myths & Facts” we get the value of the “feature_story” custom field.  To do this, we get all the custom fields for the “Myths & Facts” page:

if (have_posts()) :
    $article_custom = get_post_custom();
    // ...

This will load the value “23” into the variable $article_custom['feature_story'][0].  Now we can use this value to retrieve the post data for the post “Jo Krombholz’s Story”.  Fortunately, the get_post() function is handy for retrieving a post object without affecting the loop in the current template:

$story =& get_post($page_custom['feature_story'][0]);

If we do a print_r($story) we get the following output:

stdClass Object
    [ID] => 23
    [post_author] => 1
    [post_date] => 2008-03-25 14:48:37
    [post_date_gmt] => 2008-03-25 22:48:37
    [post_content] => I never entertained the idea...
    [post_title] => Jo Krombholz's Story
    [post_category] => 0
    [post_excerpt] => I never entertained the idea...
    [post_status] => publish
    [comment_status] => open
    [ping_status] => open
    [post_password] =>
    [post_name] => jo-krombholz
    [to_ping] =>
    [pinged] =>
    [post_modified] => 2008-04-29 12:08:40
    [post_modified_gmt] => 2008-04-29 20:08:40
    [post_content_filtered] =>
    [post_parent] => 0
    [guid] =>
    [menu_order] => 0
    [post_type] => post
    [post_mime_type] =>
    [comment_count] => 1
    [ancestors] => Array


You can use this object directly however, if you want to use template functions like the_content() to format the post content, you can pass the post object $story to the setup_postdata() function.  Careful though, this will affect the loop.

At this point, it probably seems cumbersome to manage content elements using WordPress’ core functionality. And I admit, it certainly is at first.  However, once you fully understand this technique and realize its flexibility, you will be a happy developer.

Of course, there is still lots of room for improvement here. Using custom fields to maintain relationships between content elements and pages is not intuitive at all. In fact, looking up IDs and copying them into custom fields is a management nightmare. An interface that would enable visual mapping of these relationships is really needed. I may just have to write such a plugin in the future.  If you’re thinking of writing such a plugin yourself, let me know.  I’ve been hashing out the design in my head for a while now.

  • Chris

    I’m a bit late to comment, I know – but better late than never 🙂
    I really like your idea but if you compare this technique to content elements in TYPO3 (or other CMSs) this is weak.
    I really love WordPress and to a lot of sites with WP but the missing content elements are sometimes a show stopper. Hiroaki’s Custom Field Template is a big step in the right direction, maybe it helps you checking that out.

  • Thanks! This problem has been bugging me for a while, indeed it is one of tough challenges when configuring WordPress as a CMS for clients. I’ll give your suggestion a try.

    If you ever write that plugin, let me know!

  • I am actually writing a plugin you guys might find interesting and it is OpenSource. You may find it on GitHub deployed as a WordPress plugin. It has a workspace very similar to what Typo3 has meaning only that each page is made up of Content Element blocks and something I call “Layout rows” for multi column output like TemplaVoila flexible content. Have a peak at the screenshot on the bottom of the github page and just let me know if there is any cool feature you think would be useful.