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. 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. Requirements are really basic:
- Allows adding recipes and editing them just like ordinary posts or pages
- Allows categorizing recipes in hierarchical categories like Healthy -> Chicken -> Marinated Chicken Breasts
- Allows adding ingredients to a recipe and finding recipes by ingredients
- 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'),
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:
-
quantities -> water:100ml
-
quantities -> milk:200ml
-
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.php, taxonomy-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();?>
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 base 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.