Featured Posts

Custom taxonomies in WordPress 3   When I wrote about custom taxonomies just a year ago, not much was known or understood about them in the WordPress community. For most people, anything beyond “tags” and “categories”...

Read more

Custom post types in WordPress   One of the things I’ve been hoping would be implemented in WordPress for years is the ability to create custom content types. The inability to do this has been WordPress’ weakest point...

Read more

Wordpress 3 custom menu, new features!   As a theme developer, most of the support questions I get are about configuring menus. If you’re also a theme developer, you have probably run into the same questions I have. The trouble...

Read more

  • Prev
  • Next

Custom taxonomies in WordPress 3

3

Category : Uncategorized

 

When I wrote about custom taxonomies just a year ago, not much was known or understood about them in the WordPress community. For most people, anything beyond “tags” and “categories” was unneeded anyway. And, only having only taxonomies for blog posts was essentially useless.

However, with WordPress 3.0 around the corner and the introduction of custom post types, the usefulness of custom taxonomies will increase greatly.

Post types are your forms of content. Taxonomies are the glue that holds that content together, linking it in all kinds of neat ways.

As I delve deeper into the subject of post types and taxonomies in this series of posts, I’ll give more examples of how these two things are related and how they can be used to create any type of site you want with WordPress.

First, we need a primer on taxonomies.

In WordPress 3.0, taxonomies will be super-charged. While I do encourage you to go back and read my original post on custom taxonomies and my followup on how I created a movie database to gain a better understanding of taxonomies, I’ll try to cover the important details in this post.

A refresher on what taxonomies are

Taxonomies are a method for grouping content. They’re a way of intelligently creating an organizational system for data. Some examples include:

  • Finding actors (taxonomy) that have played in specific movies (content).
  • Listing musicians (taxonomy) that have performed on various albums (content).
  • Locating restaurants (content) that serve specific types of food (taxonomy).
  • Getting recipes (content) that use certain ingredients (taxonomy).
  • Searching for jobs (content) in different fields (taxonomy).
  • Visiting a forum (taxonomy) that lists forum topics (content).
  • Scanning for books (content) written by your favorite author (taxonomy).

Grouping content in this way simply isn’t possible with standard tags and categories. To understand the benefits of taxonomies, you have to open your mind to possibilities beyond a standard blog.

What’s new with taxonomies in 3.0?

Some things have changed since the major overhaul in WordPress 2.8 of taxonomies. Don’t worry; your previously-created taxonomies will still work fine. But, now you have much more control.

The biggest changes are:

  • Ability to create taxonomies for any post type (not just posts).
  • Hierarchical taxonomies now get admin screens just like non-hierarchical ones.
  • Control over the capabilities for editing, creating, deleting, and assigning terms.
  • Control over admin text for making the UI not seem so weird.

The register_taxonomy function

To register a taxonomy, we must use the register_taxonomy() WordPress function. It takes in three parameters.

register_taxonomy( $taxonomy, $objects, $arguments )

$taxonomy

The $taxonomy parameter should be a unique name for your taxonomy that’s not used by any other taxonomy.

register_taxonomy( 'division', $objects, $arguments )

$objects

The $objects parameter can be a string (single object type) or an array (multiple object types). This represents the post types that you want to register your taxonomy for.

register_taxonomy( $taxonomy, array( 'post', 'page' ), $arguments )

$arguments

The $arguments parameter is an array of arguments that help define how your taxonomy should function. I’ll cover these in more depth later.

register_taxonomy( $taxonomy, $objects, array() )

Creating a custom taxonomy

We’re going to keep everything pretty basic for this tutorial. Let’s create a taxonomy called division for your blog posts. The easiest way to do this is to add this code to your theme’s functions.php file or a plugin file.

add_action( 'init', 'register_my_taxonomies', 0 );

function register_my_taxonomies() {

	register_taxonomy(
		'division',
		array( 'post' ),
		array(
			'public' => true,
			'labels' => array(
				'name' => __( 'Divisions' ),
				'singular_name' => __( 'Division' )
			),
		)
	);
}

This will create a new item called “Divisions” for you under your “Posts” menu item in the admin.

Taxonomy screen in WordPress

Controlling your taxonomy

The arguments array (third parameter) of register_taxonomy() is the parameter that gives you fine-grain control over how your taxonomy functions in WordPress. It allows for about 10 arguments, which I’ll cover in detail here. In each section, I’ll give a basic code example of how each is used.

public

The public argument is sort of a catchall argument that controls whether your taxonomy is publicly used on the site or if works behind the scenes. Depending on whether it’s set to true or false, it’ll automatically set other arguments if they aren’t defined.

  • show_ui: Whether the taxonomy should be shown in the administration interface.
  • show_tagcloud: Whether to allow the taxonomy to be chosen in the tag cloud widget.
  • show_in_nav_menus: Whether to allow terms from the taxonomy in navigation menus.
'public' => true,
'show_ui' => true,
'show_tagcloud' => true,
'show_in_nav_menus' => true,

hierarchical

The hierarchical argument decides if your taxonomy’s terms are in a non-hierarchical (flat) or hierarchical format. By default, this is set to false, so the taxonomy will behave like the post tag taxonomy. Hierarchical taxonomies will behave like the category taxonomy.

'hierarchical' => false,

capabilities

New in WordPress 3.0 is the ability to change the capabilities for who can use the taxonomy in the admin. By default, users of roles with the manage_categoriescapability can manage, edit, and delete terms, and those of roles with the edit_postscapability can assign terms to a “post.”

  • manage_terms: Ability to view terms in the administration. I don’t see any other use for this.
  • edit_terms: Grants the ability to edit and create terms.
  • delete_terms: Gives permission to delete terms from the taxonomy.
  • assign_terms: Capability for assigning terms in the new/edit post screen.

If you’re using a role management plugin like Members, you can assign which users have control over your terms. If not, I suggest not changing these capabilities.

'capabilities' => array(
	'manage_terms' => 'manage_divisions',
	'edit_terms' => 'edit_divisions',
	'delete_terms' => 'delete_divisions',
	'assign_terms' => 'assign_divisions'
),

labels

The labels array is a set of text strings that control how your taxonomy is viewed in the admin. If your taxonomy is non-hierarchical, this defaults to the post tag wording. If it is hierarchical, it defaults to the category terminology.

  • name: The plural name that represents your taxonomy.
  • singular_name: The singular name for your taxonomy.
  • search_items: Text for the search button when searching the taxonomy terms.
  • popular_items: Header for the popular cloud of terms (not used with hierarchical taxonomies).
  • all_items: Text to display all of the terms of the taxonomy.
  • parent_item: Text for displaying the parent term (not used with non-hierarchical taxonomies).
  • parent_item_colon: Text for displaying the parent term followed by a colon (not used with non-hierarchical taxonomies).
  • edit_item: Represents the text when editing a term.
  • update_item: Displayed when updating a term.
  • add_new_item: Text to display for adding a new term.
  • new_item_name: Text to display for adding a new term name.
'labels' => array(
	'name' => __( 'Divisions' ),
	'singular_name' => __( 'Division' ),
	'search_items' => __( 'Search Divisions' ),
	'popular_items' => __( 'Popular Divisions' ),
	'all_items' => __( 'All Divisions' ),
	'parent_item' => __( 'Parent Division' ),
	'parent_item_colon' => __( 'Parent Division:' ),
	'edit_item' => __( 'Edit Divison' ),
	'update_item' => __( 'Update Division' ),
	'add_new_item' => __( 'Add New Division' ),
	'new_item_name' => __( 'New Division Name' ),
),

query_var

The query_var argument allows you to get posts based on particular terms of the taxonomy through a query string in the browser URL bar or through a WordPress function like query_posts() or class like WP_Query. This will default to the name of your taxonomy, but you can also set it to false to prevent queries.

'query_var' => 'division',

rewrite

The rewrite argument gives you control over the permalink structure of your taxonomy’s term archives. You may want a structure like yoursite.com/divisions/blue-group, and this argument will give you control over that. It can be set to true, false, or an array of values. The values of the array are:

  • slug: The slug you want to prefix your term archives with.
  • with_front: Whether your term archives should use the front base from your permalinks settings.
'rewrite' => array( 'slug' => 'divisions', 'with_front' => false ),

update_count_callback

update_count_callback allows you to write a custom function that will be called when the term count is updated. Most users shouldn’t need this and shouldn’t bother setting this.

'update_count_callback' => 'my_custom_count_callback',

To answer the 18 billion questions from the last year

Since I first published an article on taxonomies last year, I’ve gotten numerous questions on using them. The two questions that crop up the most:

  • Can I create a hierarchical taxonomy like categories?
  • Can I use my taxonomy with pages (or other post types)?

It’s been a long time coming, but I can finally say, “Yes! And. Yes!”

I didn’t want to overwhelm everyone with too much information in this tutorial. I mostly wanted to give a refresher on taxonomies and cover some of the new features. I encourage you to read my previous posts on the subject for a deeper understanding of taxonomies.

The problem I see now is that there’s one more question that needs answering — how to merge taxonomies and post types. I’ve touched on this a bit in this post, but you can expect a real-world example from me in the near future.

Justin Tadlock

Custom post types in WordPress

Category : Uncategorized

 

One of the things I’ve been hoping would be implemented in WordPress for years is the ability to create custom content types. The inability to do this has been WordPress’ weakest point when compared to rivals in the CMS market.

In WordPress 3.0, we’ll have the capability to easily create and manage content viacustom post types. Not only that, but you won’t have to rely on a plugin to do this for you. It can be done via your theme’s functions.php file with a few lines of code.

There are other 3.0 features such as menu management and multi-site, but this is the most promising feature coming. In this tutorial, I’ll walk you through the creation of custom post types and how they can be used for your blog.

Note that I’ll use “post” and “posts” a lot to refer to custom post types in this tutorial. I’ll try to separate this from what you likely know as a post by calling it a “blog post.”

What are custom post types?

Don’t be confused by the term “post” in the name. It is actually an extremely generic term and should not be considered the same thing as a blog post. If you prefer, you can replace it with “content” instead.

Custom post types don’t have any strict rules that define what they are. They can represent any type of content you want. For example, WordPress ships with several default post types.

  • Blog Posts
  • Pages
  • Attachments
  • Revisions
  • Nav Menus (WordPress 3.0)

You should think of them as a way to create, edit, and store information in the same way as blog posts but with much more creative control.

One thing I would warn against is trying to separate your blog posts in this way. You have categories, tags, and custom taxonomies at your disposal if you’re just looking for a way to label them.

Ideas for custom post types

While WordPress ships with some good default post types that are great for most sites, some of us need alternatives. I’ll list some things below that I think would be useful and link to examples if I can.

Don’t let your imagination be limited by my list of examples. Also, look for some information on the forum and ticket system ideas from me in the future. Those two are projects I’ve been building and would love to get some feedback on.

Custom post types in the admin

Once you create a custom post type, WordPress can handle all of the admin stuff for you. By default, the administration interface will be the same as what you get with blog posts and pages. Of course, you’re welcome to get more advanced with it and change it into whatever you like.

In this tutorial, I’m creating a post type called Super Duper. With the minimum post type settings, the admin will look like the screenshot below (click image for more detailed view):

Add new post with a custom post type

Creating custom post types (basics)

WordPress 2.9 introduced the register_post_type() function. It didn’t do a lot at the time, but WordPress 3.0 will make this a powerful tool.

To get the basic functionality of a custom post type working, we hardly have any code to input. Before you start, you at least need a few things: a name, two labels, and whether your post type will be public (you’ll likely want this).

You can either create a plugin file or use your theme’s functions.php file to add the code. I will assume at this point of the tutorial that you know how to work with at least one of those two things.

Let’s set up our Super Duper post type.

add_action( 'init', 'create_my_post_types' );

function create_my_post_types() {
	register_post_type( 'super_duper',
		array(
			'labels' => array(
				'name' => __( 'Super Dupers' ),
				'singular_name' => __( 'Super Duper' )
			),
			'public' => true,
		)
	);
}

You’ll notice that there’s not a lot going on there. We added two parameters: a post type name and an array of arguments. All of the possible arguments are detailed in the next section.

If all you’ll ever want to do is something as basic as having a title field and content textarea, you can skip over the next portion of this tutorial.

Creating custom post types (in detail)

In the basic section above, we used two arguments to create our custom post type. However, the register_post_type() function has well over 20 arguments you can use. It gives you a lot of control over the specifics of your post type without a lot of hassle. You can mix and match these in all sorts of ways that I can’t even come close to covering in this tutorial.

Below, I’ll describe each of the arguments available for use. Each section will have an example of how to add the argument to the arguments array.

labels

The labels argument is an array of strings that represents your post type in the admin. Each string is a bit of text shown for particular function in the admin. By default, non-hierarchical post types will have text with “post” in them and hierarchical post types will have text with “page” in them.

It is particularly important that you make these strings translatable if you’re creating a plugin for public use.

This list is a set of general examples of when each string is used. However, each may be used in multiple places in the admin.

  • name: The plural form of the name of your post type.
  • singular_name: The singular form of the name of your post type.
  • add_new: The menu item for adding a new post.
  • add_new_item: The header shown when creating a new post.
  • edit: The menu item for editing posts.
  • edit_item: The header shown when editing a post.
  • new_item: Shown in the favorites menu in the admin header.
  • view: Used as text in a link to view the post.
  • view_item: Shown alongside the permalink on the edit post screen.
  • search_items: Button text for the search box on the edit posts screen.
  • not_found: Text to display when no posts are found through search in the admin.
  • not_found_in_trash: Text to display when no posts are in the trash.
  • parent: Used as a label for a parent post on the edit posts screen. Only useful for hierarchical post types.
'labels' => array(
	'name' => __( 'Super Dupers' ),
	'singular_name' => __( 'Super Duper' ),
	'add_new' => __( 'Add New' ),
	'add_new_item' => __( 'Add New Super Duper' ),
	'edit' => __( 'Edit' ),
	'edit_item' => __( 'Edit Super Duper' ),
	'new_item' => __( 'New Super Duper' ),
	'view' => __( 'View Super Duper' ),
	'view_item' => __( 'View Super Duper' ),
	'search_items' => __( 'Search Super Dupers' ),
	'not_found' => __( 'No super dupers found' ),
	'not_found_in_trash' => __( 'No super dupers found in Trash' ),
	'parent' => __( 'Parent Super Duper' ),
),

description

The description argument allows you to write a text string of your post type. Thus far, I haven’t seen this used anywhere in the WordPress admin, but I’m sure custom post type plugins could take advantage of this.

'description' => __( 'A super duper is a type of content that is the most wonderful content in the world. There are no alternatives that match how insanely creative and beautiful it is.' ),

public

The public argument is a kind of catchall argument for several other arguments and defaults to false. Depending on whether it’s set to true or false, it’ll automatically decide what other arguments should be unless they’re specifically defined. If you’re looking for finer control over the public arguments, there are three specific arguments you may set:

  • show_ui: Whether to show the administration screens.
  • publicly_queryable: Whether queries for this post type can be performed from the front end.
  • exclude_from_search: Whether the posts should appear in search results.
'public' => true,
'show_ui' => true,
'publicly_queryable' => true,
'exclude_from_search' => false,

menu_position

By default, a new post type is added after the Comments menu item in the admin. But, you have to ability to move it to a position more suitable for you. Default WordPress menu items are set apart by integrals of 5. For example, using 20 will add your menu item after Pages.

'menu_position' => 20,

menu_icon

New post types will default to the Posts menu icon, but if you want to mix it up a bit or give your post type some separation from other elements, you can define a custom icon. You only have to input a a custom URL to an image file.

'menu_icon' => get_stylesheet_directory_uri() . '/images/super-duper.png',

hierarchical

The hierarchical argument allows you to choose whether you want your post type to be hierarchical. It defaults to false. If you set it to true, your posts will behave like pages in WordPress.

'hierarchical' => true,

query_var

The query_var argument allows you to control the query variable used to get posts of this type. For example, you could use it with the query_posts() function or WP_Queryclass. This will default to the name of your taxonomy.

'query_var' => true,

capability_type / capabilities

The capability_type argument is another catchall argument for several more specific arguments and defaults to post. It allows you to define a custom set of capabilities, which are permissions to edit, create, and read your custom post type. If you’re unfamiliar with capabilities, I highly recommend reading my guide on users, roles, and capabilities.

If you just want to keep the same permissions you have with blog posts, leave this at the default. Otherwise, you can either set capability_type to something custom or define each specific capability in the capabilities array.

  • edit_post: Whether someone can create and edit a specific post of this post type.
  • edit_posts: Capability that allows editing posts of this post type.
  • edit_others_posts: Capability that allows editing of others posts.
  • publish_posts: Capability to grant publishing of these types of posts.
  • read_post: Capability that controls reading of a specific post of this post type.
  • read_private_posts: Capability to allow reading of private posts.
  • delete_post: Capability that grants the privelege of deleting posts.

For most people that need control over these things, it’s easier to just changecapability_type to something like super_duper. WordPress will automatically switch the other caps to follow this pattern. For example, the edit_post capability would becomeedit_super_duper.

Of course, capability control means nothing without being able to choose who has the capabilities. That’s what my Members plugin was created for. It’s ideal for this scenario.

/* Global control over capabilities. */
'capability_type' => 'super_duper',

/* Specific control over capabilities. */
'capabilities' => array(
	'edit_post' => 'edit_super_duper',
	'edit_posts' => 'edit_super_dupers',
	'edit_others_posts' => 'edit_others_super_dupers',
	'publish_posts' => 'publish_super_dupers',
	'read_post' => 'read_super_duper',
	'read_private_posts' => 'read_private_super_dupers',
	'delete_post' => 'delete_super_duper',
),

supports

The supports argument allows you to define what meta boxes and other fields will appear on the screen when editing or creating a new post. This defaults to title andeditor. There are several available options:

  • title: Text input field to create a post title.
  • editor: Content input box for writing.
  • comments: Ability to turn comments on/off.
  • trackbacks: Ability to turn trackbacks and pingbacks on/off.
  • revisions: Allows revisions to be made of your post.
  • author: Displays a select box for changing the post author.
  • excerpt: A textarea for writing a custom excerpt.
  • thumbnail: The thumbnail (featured image in 3.0) uploading box.
  • custom-fields: Custom fields input area.
  • page-attributes: The attributes box shown for pages. This is important for hierarchical post types, so you can select the parent post.
'supports' => array( 'title', 'editor', 'excerpt', 'custom-fields', 'thumbnail' ),

rewrite

The rewrite argument allows you to define the permalink structure of your posts when viewing the single post. For example, you may want to have a structure likeyoursite.com/cool/post-name. WordPress will set up a default structure based on your taxonomy name. The rewrite argument can be set to truefalse, or an array of values. It takes two arguments:

  • slug: The slug you’d like to prefix your posts with.
  • with_front: Whether your post type should use the front base from your permalink settings (for example, if you prefixed your structure with /blog or/archives).
'rewrite' => array( 'slug' => 'cool', 'with_front' => false ),

taxonomies

If you have some preexisting taxonomies, you can allow posts of this type to also use those taxonomies. You just have to set an array of taxonomy names that you’d like for it to use. WordPress will handle all the administration features for you.

Note that I’ll be covering the integration of post types and taxonomies in more depth in a future tutorial.

'taxonomies' => array( 'post_tag', 'category '),

can_export

You can use the can_export argument to decide whether posts of your post type can be exportable via the WordPress export tool. By default, this is set to true.

'can_export' => true,

register_meta_box_cb

This feature will likely only be useful to developers. You can create a custom callback function that is called when the meta boxes for the post form are set up.

'register_meta_box_cb' => 'your_callback_function_name',

permalink_epmask

I won’t pretend to know much about permalink endpoint masks. I just know you can define a custom one for your post type. Most of you won’t need this. For the purposes of this tutorial, I’ll leave this at the default.

'permalink_epmask' => EP_PERMALINK,

Viewing a custom post type

WordPress will show the singular view of your custom post types without any extra work. Once you create a new post, you’ll be able to view it by clicking on the View Post link.

View post link in the WordPress admin

If your WordPress theme has a single.php template, this will be used to display your custom post type. If not, it will fall back to the index.php template. Since this is a “custom” post type, I’ll assume you want to customize how it’s output. To overwrite the default, you can create a custom template. Our template will be called single-super_duper.php.

You can go as crazy as you like with this template. All of the standard WordPress template tags will work just fine here as well. I could give you endless pages of examples of how to customize this, but I won’t. I’d rather allow you to get creative on your own.

If you’re using a smart theme like Hybrid, this template will be super_duper.phpHybrid has long supported custom post types and uses a different template hierarchy, which is detailed in its tutorials. WordPress 3.0 will be a fun time to use this theme because of the ultimate control it gives you over templates like this.

Showing multiple posts from our custom post type

Let’s suppose I wanted to show the 10 latest “super dupers” I’ve published. We’ll use the standard WordPress loop for this and customize it however we like. Here’s a basic example:

<?php $loop = new WP_Query( array( 'post_type' => 'super_duper', 'posts_per_page' => 10 ) ); ?>

<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>

	<?php the_title( '<h2 class="entry-title"><a href="' . get_permalink() . '" title="' . the_title_attribute( 'echo=0' ) . '" rel="bookmark">', '</a></h2>' ); ?>

	<div class="entry-content">
		<?php the_content(); ?>
	</div>
<?php endwhile; ?>

Obviously, this is an extremely simple example. Understanding what you can do with the loop is outside the scope of this tutorial. The most important part is giving thepost_type argument the name of our post type.

Getting the post type of a post

An old, yet useful, function in WordPress is get_post_type(). It allows you to check the current (if no post object or ID input) or a specific post’s post type. It will return the name of the post type for the post as a string.

$post_type = get_post_type( $post_id );

Checking if a post type exists

WordPress 3.0 will introduce a conditional tag called is_post_type() whose purpose is twofold. Its first purpose is to check whether a post type or types exist. In order to use it, you can input a custom post type name or array of names into the function call.

if ( is_post_type( 'super-duper' ) )
	echo 'Super Dupers are working!';
else
	echo 'Super Dupers are not working!';

Checking if a post is of specified post type

The second purpose of the is_post_type() function allows you to check a specific post against a specific post type(s). Let’s assume we want to check if one of our posts has the super_duper post type.

if ( is_post_type( 'super_duper', $post_id ) )
	echo 'This is a not a blog post.  It is a super duper!';
else
	echo 'This is not a super duper. [insert sad face]';

Checking if a post type is hierarchical

You may want to treat hierarchical post types differently than other post types. To figure out if a post type is hierarchical, you can use the is_post_type_hierarchical()conditional tag. It will take in a post type name, post ID, or post object as its single parameter.

For example, let’s check if our super duper post type is hierarchical:

if ( is_post_type_hierarchical( 'super_duper' ) )
	'Super Dupers should not be hierarchical!';
else
	'Super Dupers are definitely not hierarchical! We stick it to the man!';

Getting a post type object

In some scenarios, you may want to get the arguments (all those things we went over earlier) for a specific post type. It is extremely important for plugin/theme authors to respect these arguments when creating plugins/themes that interact with custom post types.

Let’s suppose we want to call a specific function if the super duper post type has setshow_ui to true.

$post_type = get_post_type_object( 'super_duper' );

if ( $post_type->show_ui )
	custom_function_name();

Adding and removing support for post type features

The add_post_type_supprt() function is no different than using the supports argument when first creating your post type. This is likely more useful if you’re using a plugin/theme that has defined a custom post type.

So, let’s suppose you’re using a plugin that creates a new post type for you. Your post type doesn’t have support for thumbnails, but you think this feature would work well on your site.

add_post_type_support( 'post_type', 'thumbnail' );

The opposite of this function is remove_post_type_support(). So, let’s further suppose that your plugin author added support for excerpts, but you don’t want to use this feature.

remove_post_type_support( 'post_type', 'excerpt' );

Checking if a post type supports a specific feature

As a plugin/theme author, this will likely be useful. You wouldn’t want to try and display stuff that doesn’t exist for a custom post type. For example, your theme may wrap post content with a <div> or something of that sort. This is fairly common. But, you may want to remove it if the post type doesn’t have written content.

<?php if ( post_type_supports( 'super_duper', 'editor' ) ) { ?>

	<div id="post-<?php the_ID(); ?>" <?post_class(); ?>>
		<?php the_content(); ?>
	</div>

<?php } ?>

Be careful with this though. A post type may have other means of defining something like the content, and this should only be taken as an example of how to use thepost_type_supports() function.

Getting registered post types for use in PHP

As a plugin/theme developer, you may need to get all the registered post types for use in a function of your plugin/theme. You’d use the get_post_types() function for this.

In the below example, I’ll output a list of post types by singular label that are shown in search results.

<?php $types = get_post_types( array( 'exclude_from_search' => false ), 'objects' ); ?>

<ul>
	<?php foreach ( $types as $type )
		echo '<li>' . $type->singular_label . '</li>';
	?>
</ul>

Help! I’m getting a 404!

If you’re getting a 404 message when trying to view a post, don’t worry. This is supposed to happen when setting up new post types. The easiest way to fix this is to simply visit your Settings > Permalinks page. You don’t have to save your permalinks but just visit the page. This will flush your rewrite rules.

If you’re a plugin author, you can save yourself some support questions by flushing the rewrite rules on activation of your plugin.

Is this a theme or plugin feature?

I’ve had a hard time trying to decide which to call it, and have ultimately decided that it’s both. It’s a marriage of the two because both need to be in sync to fully enjoy the benefits of custom post types.

More than likely, you’ll see post types registerd from within a plugin. But, they have to be displayed by your theme. If you’re creating this all yourself, you can simply drop it all in your theme.

If you’re a theme author, you should be aware that plugins may add new post types. Do yourself and your users a favor by not assuming too much. Keep your code flexible enough to give a default view for custom post types and easy enough to handle when creating custom templates for those post types.

The tip of the iceberg

I haven’t even scratched the surface of what’s possible with custom post types. Even the new navigation menus feature of WordPress 3.0 will be built with them. While I know some people in the community don’t agree with this decision, I wanted to point it out because it’s a unique example of what’s possible.

Of my list of about 1,000 things I wanted to share in this tutorial, I might have covered about 20 of them. Given enough free time, I could write a book on using custom post types. Some stuff should be left open to exploration though, and I encourage you to try everything I’ve written about and move beyond this tutorial to creating something unique for your site.

Justin Tadlock

WordPress 3 custom menu, new features!

4

Category : Uncategorized

 

As a theme developer, most of the support questions I get are about configuring menus. If you’re also a theme developer, you have probably run into the same questions I have.

The trouble is that a large majority of users want custom menus and no two menus are the same. There are tons of plugins that fix this problem in their own way. Even some theme developers have integrated menus systems into their themes.

Unfortunately, all of these solutions are different. We haven’t had a standard to go by, at least until now. WordPress 3.0 will introduce a new navigation menu system. Sure, there are some limitations with this system. However, with a set standard, new plugins will likely emerge to fill in the gaps.

In this tutorial, I’ll walk you through the features of the new system and how to build this into your theme if you’re a developer.

What the menu system offers

In WordPress 3.0, you’ll gain another admin screen under your Appearance menu called Menus. In the screenshot below, I’ve highlighted four key elements of the page.

  • Theme Locations: If your theme supports nav menus, it’ll register new locations for you to add your custom-created menus.
  • Individual Menus: This is where the names of your menus will appear after you’ve created them. (Note that the “+” sign will create a new menu.)
  • Add Menu Items: There’ll be several meta boxes containing pages, other post types, categories, other taxonomies, and custom links to your menus.
  • Menu Items: Once you’ve added menu items to your menu, they will appear under the menu for your configuration.

WordPress Nav Menus

Each menu item can has its own configuration section too. Once the item has been added to the menu, you can open it and edit its attributes, which are standard things you might want to change about any menu.

  • URL
  • Navigation Label
  • Title Attribute
  • CSS Classes
  • Link Relationship (XFN)
  • Description
  • Link Target (Please note that a kitten dies every time a link is opened in a new window/tab.)

Nav Menu Item

Registering a menu for a theme (theme location)

To associate specific menus with locations within our themes, we need to register these locations. Otherwise, we won’t know which menu goes where. There are two functions we can use for this:

  • register_nav_menu(): Registers a single theme location.
  • register_nav_menus(): An array of locations we want to register.

In this example, we’ll register a single menu called Primary Menu from our theme’sfunctions.php file.

add_action( 'init', 'register_my_menu' );

function register_my_menu() {
	register_nav_menu( 'primary-menu', __( 'Primary Menu' ) );
}

primary-menu is the slug we’ll use to identify the menu in code. Primary Menu is the label we’ll use to identify the menu in the admin.

Building off that example, we’ll create multiple menus, which is not much different than registering a single menu.

add_action( 'init', 'register_my_menus' );

function register_my_menus() {
	register_nav_menus(
		array(
			'primary-menu' => __( 'Primary Menu' ),
			'secondary-menu' => __( 'Secondary Menu' ),
			'tertiary-menu' => __( 'Tertiary Menu' )
		)
	);
}

Displaying a nav menu

There are two ways to display a nav menu. One is by calling wp_nav_menu() within a theme template file. The other is by using the Navigation Menu widget.

Displaying a menu within a theme template

Most themes will call a menu from their header.php template, but menus can be placed anywhere. The simplest form of calling a nav menu in a theme will look like this:

<?php wp_nav_menu(); ?>

That will load the first menu the user created or fall back on a standard page list if no menus exist.

We want to have a bit more control than that though. Let’s call our menu from the previous section (Primary Menu).

<?php wp_nav_menu( array( 'theme_location' => 'primary-menu' ) ); ?>

You’re allowed even more control. wp_nav_menu() has several parameters you can use when displaying a menu.

  • theme_location: The menu to call that is associated with the specific theme location.
  • menu: Call a specific menu ID, slug, or name.
  • container: The element that wraps around the list. The default is div but can be changed to nav if you’ve moved on to HTML 5.
  • container_class: The CSS class of the container.
  • menu_class: The CSS class given to the unordered list. This defaults to menu.
  • fallback_cb: A function to call in the event that no menu items have been given. By default, wp_list_pages() will be called.
  • before: Text that is displayed before the link text but within the link.
  • after: Text that is displayed after the link text but within the link.
  • link_before: Text that is displayed before the link.
  • link_after: Text that is displayed after the link.
  • depth: How many levels the menu should display, which is useful for things like drop-down menus. This is set to 0 (any level) by default.
  • walker: Allows a custom walker PHP class to be defined to create the menu.
  • echo: Whether to display the menu or return it for use in PHP. This defaults to true and displays the menu.

Displaying a menu using the Navigation Menu widget

By default, WordPress will give you a simple menu widget that will allow you to select any of your custom menus to display. All you need is a widget-ready theme.

Since using widgets is fairly self-explanatory and the new widget is simple, I’m going to use this opportunity for a little shameless self promotion.

For those of you that use my Hybrid theme, you know you have the coolest widgets ever because they give you complete control. Version 0.8 will have a much more advanced Navigation Menu widget that overwrites the WordPress default. Here’s a look at what controls you’ll have.

Navigation Menu Widget

Styling nav menus

I won’t be covering how to style menus here. That’s a tutorial in and of itself, and there are tons of different ways to style menus. I do have a couple of tips though.

Use the current-menu-item class to style a menu item whose page is currently being viewed. This will allow you to highlight the item so the reader will know which page they’re on. Here’s an example from one of my style.css files:

#primary-menu li.current-menu-item a {
	background: #fff url(images/primary-menu-active.png) repeat-x 0 0;
	border-top: none;
	border-bottom: 2px solid #fff;
	}

A solid base to start with is the Superfish jQuery plugin. It allows some subtle, but cool, JavaScript functionality and fixes drop-downs in Internet Explorer 6 without having to resort to hacks.

Here’s a screenshot of a menu I’ve been working on for a new theme.

Navigation menu frontend

At this point, you should know everything you need to know about handling menus in WordPress. But, if you continue reading, I have a few more tips that you can use.

Collapsible menus

Let’s suppose you only want a menu to appear when a user has added menu items. This can allow for a variety of layouts. In the screenshot below, I’m using two menus. But, this allows for up to four different layouts.

Collapsible menus

The trick here is to make sure there’s no fallback called. Let’s return to our original menu (Primary Menu) and the code for it.

<?php wp_nav_menu( array( 'theme_location' => 'primary-menu', 'fallback_cb' => '' ) ); ?>

What I’ve done is simply tell WordPress that I don’t want my menu to fall back to another menu if the user hasn’t given the menu any items.

Checking if a theme location has a menu

Update: Props to Andrew Nacin for adding the has_nav_menu() function after reading this section of the article.

WordPress currently has no conditional tag to check if a menu has been set to a specific theme location. WordPress has a conditional tag called has_nav_menu() to check if a menu has been set to a specific theme location. Let’s suppose we’re creating a container with a menu and a search form. But, if no menu is set for the theme location, we don’t want either to appear.

In the screenshot, you can see that neither appear in one scenario and both appear in the other.

Collapsible menu container

When you call your menu by theme location, you can first check to see if a menu is associated with the location. Note that we’re checking the theme location slug and not a menu name or ID.

<?php if ( has_nav_menu( 'primary-menu' ) ) { ?>

	<div class="nav-container">
		<?php wp_nav_menu( array( 'theme_location' => 'primary-menu' ) ); ?>
		<?php get_search_form(); ?>
	</div>

} ?>

Allowing more menu containers

The menu system will only allow for <div> and <nav> as a menu container by default. This is likely all you’ll ever need. If for some reason your menu needs to be wrapped by something else, you can allow for new containers.

add_filter( 'wp_nav_menu_container_allowedtags', 'my_menu_allowed_tags' );

function my_menu_allowed_tags( $tags ) {
	$tags[] = 'p';
	return $tags;
}

Note the the <p> tag isn’t something I’d recommend using to wrap a list. It’s just an example.

Getting a list of all theme locations

If you need to list your theme’s menu locations, use the code below. It will return an array of the locations.

$locations = get_nav_menu_locations();

Creating a menu

Most theme authors shouldn’t have a need to use this function, but there may be cases when it’s needed. In most situations, you should use the theme location feature (register_nav_menu()) rather than this. But, if you need to programmatically create a menu, do so using the wp_create_nav_menu() function.

wp_create_nav_menu( 'Menu Name', array( 'slug' => 'menu-slug' ) );

Checking if a specific menu exists

This is another function not likely needed by theme developers but may come in handy. It allows you to check if a menu exists by ID, name, or slug.

if ( is_nav_menu( 'menu-slug' ) )
	/* Do something if the menu exists. */
else
	/* Do something if the menu doesn't exist. */

Have fun with your menus

While there are certainly other features I love about WordPress 3.0 more, the new menu system is the feature that’ll help me the most as a theme developer. There’s also a ton of stuff you can do with menus that I couldn’t possibly cover in this tutorial. I’m going to leave that up to your imagination.

I do have one request from any plugin developer that’s up for a challenge: a “menu logic” plugin akin to Alan Trewartha’s awesome Widget Logic plugin.

Justin Tadlock