If you are using WordPress as a blog, organizing your content is quite straight forward. You categorize and tag your posts, create nav-menus, to link the most important categories, use archive or calender widgets and order your posts by publishing date (which is the default). Using WordPress as a CMS for a common website and building the navigation, often requires a bit more structural planning. The thing is that there are multiple strategies, which might be right or wrong depending on your demands. In this article I want to present a list of the approaches I use.

Inbuilt and custom post types

But first some words about the standard post types build into WordPress. When I build a website with WordPress, I naturally use pages for all static content, but in the beginning I even tried to use the standard posts post type for all continuously updated content like news sections, upcoming events and so on.

However, after some time I realized that posts really only should be used for blog content and nothing else. All the other stuff should be implemented as custom post type. There are two simple reasons: Your client might decide to integrate a blog with the website in the future and by that time the posts section is bloated with other content. Secondly is my experience that custom post types for events or newsfeeds are just more usable and intentional, than the standard posts, especially when there is some extra functionality needed, like start/end-date for an event.

So, when you are implementing one of the following strategies, make sure that you choose your post types well.

One-level menu

The easiest variant of content structure is just a bunch of pages without any hierarchy. Typically you would create a menu, under Appearance->Menus in the admin interface, and add all relevant pages to it. Here an example how to embed a simple menu into a theme:

wp_nav_menu( array( 'theme_location' => 'main-menu' ) );

For many small businesses this content structure is appropriate. Often it is quite easy to determine the few sections of content the wesite’s user will be interested in, e.g. “General information”, “References” and “Contact information”. You will both get a easily navigated site and a very simple backend.

When not to use it: There aren’t any drawbacks. If the content structure stays as simple as described above, there will be no problems.

Multi-level menu

Now, not every website works with a simple structure and not every client is satisfied with only telling the stuff visitors want to know. Sometimes clients want there websites to present the whole company structure and in these cases you need a hierarchical navigation, perhaps with a dropdown menu.

The good thing is, that there is support for multi-level menus in WordPress and implementing them, can be quite simple. In the back-end it is as easy doing some drag&drop actions to create a hierarchical menu of your pages and the simplest way to implement it in your theme is just the same as with one-level menus. You might add a depth parameter, to limit the count of levels your for the navigation.

wp_nav_menu( array(
    'theme_location' => 'main-menu',
    'depth' => 2
) );

This would print a nested list representing your hierarchical menu and with some suckerfish magic you make it a dropdown in minutes. You can even build a nested navigation where every page contains a submenu with pages on the same level, by printing the whole menu on every page and hiding the irrelevant portions of the menu with CSS.

But there are drawbacks. The big problem I see with multi-level menus is, that your menu, doesn’t organize your content. Even if you have built a well structured menu, your pages section in the admin-interface isn’t organized at all, it’s just a very long list of pages. I see this as a real usability issue for our clients and there are only two (suboptimal) solutions I can see. The first is telling your client to use the search field, because the structure showed on the website is not represented in the pages section. The other is to hierarchically organize your pages the same way you did it with the menu and mirroring all changes in future, which could be a big amount of extra work.

When not to use it: If there are many pages and you don’t want your client to do the extra work of organizing both menus and pages. Or if you want to implement submenus/breadcrumbs without printing the irrelevant parts and hiding them with CSS.

Multi-level pages

If multi-level menus don’t work for you, you could abandon menus and only organize by page hierarchy. Compared to the really easy way you drag and drop menus, it is a somewhat clumsy method, to enter the editor of every page and choose a parent, but it works. Here is how to create a menu just from the page structure:

<ul>
    <?php
        wp_list_pages( array(
            'title_li' => null
        ) );
    ?>
</ul>

The advantage over menus is that you directly can access the pages parents and child’s and thus know on which menu level you are operating with your page template. This makes it possible to build all kinds of custom navigation elements like submenus or breadcrumbs. Following the code to print a submenu with links to pages on the same level as the current page.

<ul>
    <?php
        wp_list_pages( array(
            'title_li' => null,
            'child_of' => get_post( get_the_ID() )->post_parent
        ) );
    ?>
</ul>

One thing to remember is that you can’t add one page in multiple places like you can with menus, because you are generating the menu directly from the page hierarchy. In case you need, say a contact page, in two places on the menu you have to create two contact pages.

When not to use it: If your client doesn’t feel comfortable with the way you structure pages or you want to link pages in multiple places in your menu this approach isn’t the best.

Integrate categories with pages and menus

You can even use categories to organize your pages. You could use the built in categories, but I think it’s better to create an own taxonomy, mostly because of the reasons discussed above, why you shouldn’t use posts for something else than blogging. Following some code to add a custom taxonomy to categorize pages, to include in the functions.php:

add_action( 'init', 'add_page_categories' );

function add_page_categories() {
   register_taxonomy(
      'page-category',
      'page',
      array(
         'label' => 'Page Category',
         'rewrite' => array( 'slug' => 'page_cat' ),
         'hierarchical' => true
      )
   );
}

Now you can select the categories for every page and add them to a (multi-level) menu. The advantage over simple multi-level menus is that the categories add some structure to the pages section, even if you don’t get the whole hierarchy. In my opinion the checkbox to select the category is slightly more usable than the child/parent selection lists, which are building the page hierarchy.

And there is another thing about this way of building a menu: you can list multiple pages under one menu-item, which is kind of sabotaging the static content thought. However, it can make sense in some situations, for example a contact page which is intended to list all employees and you add one page for everyone instead of listing them in one pages content block.

When not to use it: If your client isn’t familiar with the WordPress UI it might be one more hurdle to learn not only page editing and building menus, but also using the category checkboxes.

One-level menu plus page-hierarchy

This last approach to multi-level navigation uses both menus and page hierarchy. The idea is to only use a menu for the first navigation level, so you can easily rearrange and fully control your main menu. Then, all the pages linked in your main menu are used as parents for subpages, so the multiple levels get implemented by the page hierarchy. The next two pieces of code show how to print the main navigation with the wp_nav_menu function and how to output a submenu by using wp_list_pages.

<!-- main-menu, only add parents -->
<?php
    wp_nav_menu( array(
        'theme_location' => 'main-menu',
        'depth' => 1
    ) );
?>
<!-- end main-menu -->
...
<!-- sub-menu -->
<ul>
    <?php
        wp_list_pages( array(
            'title_li' => null,
            'child_of' => get_post( get_the_ID() )->post_parent
        ) );
    ?>
</ul>
<!-- end sub-menu -->

This solution I use very much because it solves a whole bunch of problems I discussed earlier in this article:

  • you get the flexibility of menus for your main navigation
  • you get the structural advantages of hierarchical pages
  • you don’t have to build the hierarchy two times
  • you can present a clean and logical structure to your clients

When not to use it: If you want to build a simple dropdown-menu and can be sure that there wont be any more complicated navigation requirements, multi-level menus would be the better choice.

Bottom line

WordPress as CMS has quite a few possibilities to organize your content and build a navigation. Of all approaches I’ve shown I think I would prefer the last one, mainmenu plus page hierarchy, in the most cases where a multi-level navigation is needed. It uses both the strengths of menus and page hierarchy, is easy to implement with the WordPress API and extendable if new navigation functionality is needed. From a usability point of view it makes use of the WordPress UI in the most common and intuitive way.

In the past WordPress has grown from a powerful blog-system to a powerful CMS and, more recently, to a powerful framework for web applications. In fact, using WordPress customization features and the WordPress API, there are not many applications I can think of, you couldn’t build with WordPress as framework. However, there are a lot of applications you shouldn’t build with WordPress. Choosing which framework to use (or choosing not to use one) is balancing between many pros and cons affecting architecture, performance, security, scalability and so on.

I found WordPress extremely useful as base for medium sized web apps, without too much traffic. Building a small application, for example a restaurant table booking system, from scratch or even with a framework like Rails or CakePHP, would involve thinking about database scheme, controller structure, authentication, user interfaces etc. A lot of this stuff WordPress is already doing: you already have rough user management, a working admin interface and you only have to think about how to map your data-model to the already existing WordPress database structure.

Our use case: A recipe database

Now, I want to show you how to implement a simple recipe database with WordPress as framework. Requirements are really basic:

  1. Allows adding recipes and editing them just like ordinary posts or pages
  2. Allows categorizing recipes in hierarchical categories like Healthy -> Chicken -> Marinated Chicken Breasts
  3. Allows adding ingredients to a recipe and finding recipes by ingredients
  4. Allows adding quantities to ingredients of a recipe, e.g. 500ml milk, 20g sugar, 3 tablespoons olive oil
I will focus on how to customize WordPress to adjust it to your data model, mainly by showing you how to use the essentials to build every WordPress powered web app:
  • Custom post types
  • Custom taxonomies
  • Custom fields

Setup custom post type for recipes

In WordPress the base of every content holding entity is a post. The two post types you surely are familiar with are posts and pages. For our recipe database we will create a new type: recipes.

register_post_type('recdb_recipe',
	array(
		'labels' => array(
			'name' => 'Recipes',
		),
		'public' => true,
		'has_archive' => true,
		'supports' => array('title','editor','custom-fields')
	)
);

The new post type will show up in the admin interface along with posts and pages. It supplies a field for the recipe title and a editor field which is meant for the recipes description part. We even added support for custom fields, which will be necessary later on.

Setup custom taxonomies for recipe categories and ingredients

In WordPress, taxonomies are not for holding content, like posts, they are for organizing it. You should be used to the two default taxonomies: categories (hierarchical) and tags (not hierarchical). However, like with post types, you can add your own kinds of taxonomies. For our recipes database you could use categories and tags, but they are meant to be used for posts really, so we create our own recipe categories and link them to the recipe post type:

register_taxonomy(
	'recdb_categories',
	array('recdb_recipe'),
	array(
		'label' => 'Recipe categories',
		'sort' => true,
		'rewrite' => array('slug' => 'recipe-categories'),
		'hierarchical' => true,
		'show_in_nav_menus' => true
	)
);

In the admin interface they will show up under the recipes-menu and furthermore there will be a checkbox-list on every recipe to sort it into categories. The same way we want it with ingredients, but with a slight difference: they don’t have to be hierarchical, because every recipe will have just a plain list of ingredients. Here is how to create an ingredients-taxonomy, that will work just like ordinary tags. You can manage it from your admin interface and add it to any recipe:

register_taxonomy(
	'recdb_categories',
	array('recdb_recipe'),
	array(
		'label' => 'Recipe categories',
		'sort' => true,
		'rewrite' => array('slug' => 'recipe-categories'),
		'hierarchical' => true,
		'show_in_nav_menus' => true
	)
);

Setup custom fields for ingredient units

For now we can create new recipes, categorize them and add ingredients. The last missing feature is to add some sort of quantities to the ingredients, because the information that you will need milk, while cooking your dinner, is useless if you don’t know how much. Here are custom fields coming into the picture. For all ingredient-tags you are adding to a recipe, you have to add a custom filed as well. The name of the field is always quantities, that will allow us to read them as an array later on. The value has to be formatted like this: taxonomy-term-slug:string. Here some concrete examples for the custom fields on our recipes:

  1. quantities -> water:100ml
  2. quantities -> milk:200ml
  3. quantities -> sugar:20g

Embedding recipes in your theme

I am assuming you have a working theme and now want to add special templates for recipes. Begin with adding recipe-categories to your menus. Are you using custom menus, they will show up in the menu editor just like ordinary categories (you might have to activate them in your screen options panel). Now you should be able to navigate to the added recipe categories on your website. The containing recipes getting displayed with your index.php or another matching template.

The next step is to build a custom loop for recipes. We will generally build quite an ordinary loop, including the_title and the_content template tags. Building the ingredients list is a bit special, though. For this, we first have to get the quantities meta-value, using get_post_meta. Then we are looping through the quantities, reading both the quantity and the ingredient and finally we provide an ingredient link, which leads to a site listing recipes with the same ingredient. Create a file called loop-recipes.php in your template directory and add the following loop:

<?php if (have_posts()): while (have_posts()): the_post(); ?>
	<div class="recipe">
		<h2><?php the_title(); ?></h2>
		<ul class='ingredients'>
			<?php
				if (is_single()):
					$quantities = get_post_meta(get_the_ID(),'quantities');
					foreach ($quantities as $quantity):
						$quantity = explode(':',$quantity); ?>
						<li>
							<?php echo $quantity[1]; ?> <a href='<?php echo get_term_link($quantity[0],'recdb_ingredients'); ?>'>
								<?php echo $quantity[0]; ?>
							</a>
						</li><?php
					endforeach;
				endif;
			?>
		</ul>
		<?php
			if (is_single()):
				the_content();
			else:
				the_excerpt();
				?><a href="<?php the_permalink(); ?>">Read recipe</a><?php
			endif; ?>
	</div>
<?php endwhile; endif; ?>

Now it is only left to embed the loop in the template files for recdb_categories and recdb_ingredients and adding a template to show a full recipe. Create three files called taxonomy-recdb_categories.phptaxonomy-recdb_ingredients.php and single-recdb_recipe.php in your template directory. The following codes goes into the category-template:

<?php get_header(); ?>
<h1>Category: <?php single_cat_title(); ?></h1>
<p>List of recipes in category <?php single_cat_title(); ?></p>
<?php get_template_part('loop','recipes'); ?>
<?php get_footer(); ?>

Here the code for the ingredients-template:

<?php get_header(); ?>
<h1><?php single_cat_title(); ?></h1>
<p>List of recipes, which use <?php single_cat_title(); ?></p>
<?php get_template_part('loop','recipes'); ?>
<?php get_footer(); ?>

And finally the single recipe template:

<?php get_header(); ?>
<?php get_template_part('loop','recipes'); ?>
<?php get_footer(); ?>

WordPress as framework for web-apps: Conclusion

If you followed all the steps, you should have a really basic, but working recipe database running. Of course, the way to add ingredients is really horrifying, from a users point of view, but this tutorial isn’t about usability. It is a starting point for one who wants to take WordPress as framework for web apps that aren’t blogs or ordinary websites. The vital point, I think, is to really understand the WordPress customization abilities and learn to map them to your own use-case.

Surely there are quite some drawbacks using WordPress for your web-app and you shouldn’t ignore them. However, once you have decided to go the WordPress way, you get a lot of cool features to defeat the disadvantages.