WordPress as CMS – New Features Part 1: Content Types

By Sol in Lab

One of the best things to come out of beta testing this plugin in a real-world situation is the advent of new features. Had I been developing the plugin in complete isolation, it’s quite likely these new features could have been implemented completely differently (or not at all).

There are several little enhancements and optimizations all over, but there are two new features that I believe have the most impact:

Content Types

Different types of content have different attributes. While most content types share some attributes (i.e. title, main content text, categories, etc.), they often diverge from each other in their “supporting” attributes (aka metadata). In the case of Cinema Paradise, a film would have a certain set of metadata (director, length, country, etc.), while an event would have completely different set of metadata (time/date, location, etc.).

For a site needing to manage several different content types, there are two important questions:

  • How is the metadata added to a post (and how is it stored)?
  • How is the metadata displayed?

Adding metadata to a post

Generally, additional metadata is added to a post via custom fields and stored in the wp_postmeta table. When you write a new post, simply fill in the appropriate custom fields (or add new ones), and you’re good to go. This is fine for blog sites (where blog posts are the only content type), but for a content-heavy site where several different types of content are added regularly (articles, blog posts, etc.), this just isn’t acceptable. Not only would a large list of custom fields be disorganized and hard to manage, but on a site with multiple users (each of whom may only need to work with certain content types), there is a good chance that mistakes will be made (e.g. typing metadata into the wrong custom field, etc.).

To make the creation and management of different content types simple and effective, the following functionality was (or will be) introduced into the plugin:

  • Add new content types
  • Users are able to create new content types and define its attributes. For each attribute, users may define the different characteristics such as data type, default values, etc. Some examples of data type are:

    • Date
    • Address
    • Phone Number
    • Database Lookup – (Creates a drop-down list of values fetched from the DB. Used mostly to create relationships with other content types)
    • File Upload – (image/video uploads, etc.)

    The order and layout of the content type’s attributes can also be set.
    As an example, three content types from the Cinema Paradise site were “Director”, “Film”, and “Event”. Here is a breakdown of each content type:


    • Name – Plain Text
    • Country – DB Lookup (List of Countries)


    • Title – Post Title
    • Description – Post Content
    • Country – DB Lookup (List of Countries)
    • Director – DB Lookup (Items matching “Director” content type)
    • Genre(s) – Post Categories


    • Event Title – Post Title
    • Event Description – Post Content
    • Start Time – Date
    • End Time – Date
    • Location – DB Lookup (Items matching “Location” content type)
  • Select content type for a post
  • Once a content type has been created, it may be selected from a drop-down list in the Write Post form when creating or editing a post. When a content type is selected, a form containing a field for each of the content type’s attributes will appear below the post content text box. The user can then fill in this form with the appropriate metadata.

    Each field in the form is not just a simple text box either. A specially formatted form field will be displayed depending on the data type for each attribute. For instance, a date field will have a field where a date (month/day/year) may be entered, along with a popup calendar for quick and easy date selection, and an address data type will have text fields for Street, City, State, Zipcode, and Country data to be entered.

    This makes it simple to enter metadata for different content types, and because only the form fields necessary for that content type are displayed, the likelihood of user-error is greatly minimized.

A note on metadata storage

For the first implementation of this feature on Cinema Paradise’s site, a new table is created for each content type. Since there were a finite amount of different content types to manage, I felt this was the best solution (faster/more specific queries, etc.). However, I am currently reevaluating the implementation of how metadata is stored to best accommodate the creation of an unlimited number of different content types.

Displaying metadata for a post

Template Hierarchy

Once a post has been assigned a content type, the focus now moves onto how to display this extra data. First, when creating a new content type, a default template may be defined. This template will be used if no templates have been set for a content type in the template directory. If a template for a content type has been defined in the template directory, it will override the default template. Currently, content type templates are defined by creating a file with the same name as the content type (this may change in the future to better differentiate content type template files from other template files). Furthermore, content type templates may be defined on a per-section basis. This means that content of a specific type (e.g. an article or an event) can be made to look different from one section to another. Again, if a section-specific content type template is present, it will override both the global content type template file and the default content type template (only for posts in that section, of course).

Custom Template Tags (Conceptual)

Currently, metadata may be displayed simply by inserting $post->attribute-name into a template. This works and is quite simple, but I would like to align the display of a post’s metadata with the main data of a post which can be displayed using template tags such as the_title(), the_content(), etc. So for an event, a user could create template tags such as event_location(), event_start(), and event_end().

Honestly, I don’t know whether this is practical to implement, or if it is even possible. I need to look into this more.