Building a Dynamic Custom Post Type Plugin

Building a Dynamic Custom Post Type Plugin

Tutorial Details
  • Program: WordPress
  • Version: 3.0+
  • Difficulty: Medium
  • Estimated Completion Time: 2 hours

Often, you get to make a choice and decide how you will implement a certain functionality. WordpPress has a pretty flexible approach for almost any problem, and in this tutorial we are going to take a look at how flexible the custom post type API is.

There are many things you can do with custom post types, including generating and managing certain posts on some custom pages, slideshows, galleries, portfolio items even. Some people don’t know they exist yet, others don’t fully understand their options and how to use them. We are going to try, in the following steps, to build a specific plugin that uses custom post types at it’s best. To be more exact, we are going to build a plugin that creates one custom post type, that creates and manages dynamically, other custom post types (it’s like Inception in here!).


Step 1 The Plan

Before we even begin starting, we are going to take an in detail look at what we are going to build in this tutorial, how and why. The purpose of this tutorial is to help familiarize yourself with custom post types in WordPress.

To do this we are going to build a plugin that creates one main custom post type, then use the posts in that custom post type, with a settings meta box, to create additional, dynamic custom post types based on the meta box interface options. This will help you understand in detail all the custom post options and some of the possibilities it can give. For the purposes of this tutorial, it is implied that you have a working Apache server with PHP and MySQL running, and WordPress installed, so that you can test the plugin code on a 3.0+ version of WordPress.

Each post is going to be interpreted as a new custom post type and we are going to save the configuration options of each post in custom fields using a meta box with a lot of forms, checkboxes, dropdown boxes and textboxes that will store and show the data, making it easy for the user to modify anything.

Because the plugin has 450 lines of code, not every line of code will exist in the tutorial as most code is repeated and just the variables are different. But all of the functionality of the plugin will be explained and the source code given as an example.


Step 2 Creating and Understanding the Hooks

If we want to get to the custom post type functionality, the metabox functionality, and we want to save data on update or publish action, we need hooks, and we need to implement them specifically in order to get the desired effect.

add_action('save_post', 'cpt_save_postdata');
add_action('add_meta_boxes', 'cpt_add_meta_boxes');
add_action('init', 'init_custom_post_types');

We are only going to need three hooks in this tutorial, no filters, nothing else at the core functionality. First we need a hook to generate the custom post type in its callback function. For that we are going to use the init tag hook and the callback function by the name of 'init_custom_post_types'. This is where all the magic happens, namely this is where we declare our custom post types and where we make them dynamic by extracting the values from the database and generating dynamic custom post types in a loop. This part of the code will be discussed later on.

Another hook that we need is the 'add_meta_boxes' tag hook that points to the callback function 'cpt_add_meta_boxes' and is used to generate the meta boxes inside the main custom post type that generates all the other custom post types. This is where we create the forms that will store and update the data we need to manipulate to create our functionality.

The last hook we use is 'save_post' with the callback function of 'cpt_save_postdata' and the purpose of saving the meta box posted data. When the page of the main custom post type is submitted in the admin panel by the user, all the form fields are submitted and this is the hook that we use to grab that content and save/update it in the database for later use.


Step 3 Creating the Main Custom Post Type

First, we need to create a general custom post type that is going to handle all the dynamic content. To do this, first we create a generic custom post type using hard coded data like in the next example. First we create the labels. The labels parameter is one of the main argument values that is interpreted as an array. The array values are given by their identifiers, specifically name for the main general name of the custom post type that is usually a plural string of the custom post type name, singular_name for the custom post type object name in the singular, add_new the add new string text, add_new_item that is the default add new post/page text, edit_item as the default text for edit post or page, all_items is used for showing all the custom post type names text where requested (example: all cars), view_items and search_items are used just like the previous example just for the obviously different purposes, not_found, not_fount_in_trash, parent_item_colon are also replacement texts used for certain pages of the posts (custom post types) functionality that you might want to change for any custom post type that you create.

In the next example, the $labels array uses CPT in replacing the default post/posts/page/pages text. I guess it is not necessary for some readers but just to be sure I don’t miss the idea, CPT stands for Custom Post Type and is and will be used in a number of ways during the tutorial.

An important note, this code is inserted into the init_custom_post_types callback function for it to work properly.

$labels = array(
	'name' => _x('CPT', 'post type general name'),
	'singular_name' => _x('CPT', 'post type singular name'),
	'add_new' => _x('Add New CPT', 'CPT'),
	'add_new_item' => __('Add New Post type'),
	'edit_item' => __('Edit CPT'),
	'new_item' => __('New CPT'),
	'all_items' => __('All CPT'),
	'view_item' => __('View CPT'),
	'search_items' => __('Search CPT'),
	'not_found' => __('No CPT found'),
	'not_found_in_trash' => __('No CPT found in Trash'),
	'parent_item_colon' => '',
	'menu_name' => __('CPT')
);

$args = array(
	'labels' => $labels,
	'public' => true,
	'publicly_queryable' => true,
	'show_ui' => true,
	'show_in_menu' => true,
	'query_var' => true,
	'rewrite' => true,
	'capability_type' => 'post',
	'has_archive' => true,
	'hierarchical' => false,
	'menu_position' => null,
	'supports' => array('title')
);
register_post_type('CPT', $args);

The main array needed for generating the custom post type is the $args array, used for the sole purpose of setting the main options of the custom post type and managing its functionality.

  • The first array variable is named labels and we previously took care of the structure of that value.
  • public – a boolean variable, true or false, that represents the availability of the custom post type, if it is public for the admin interface or by front-end users in the theme.
  • publicly_queryable – again a boolean value that sets if the front end has the capability of querying the results of the custom post type.
  • show_ui – a boolean stating if default admin content is generated for the custom post type or not.
  • show_in_menu – yet another boolean variable that requires show_ui to be true to function, as its purpose is to show or not to show the post type in the menu of the WordPress admin panel.
  • query_var – creates a query var key for this custom post type. You can use it as boolean or string, if it’s true it’s default, false disables query var key use and string sets a custom key. In our example we use the default value and set it to true.
  • rewrite – this prevents rewrites for this post type.
  • capability_type – at last, a string that sets if the custom post type is a post or a page, in a plain text string. We are using post.
  • has_archive – this parameter enables post archives and uses post_type by default as archive slug.
  • hierarchical – a boolean that sets if the post type is hierarchical or not, i.e. if it allows parents to be specified or not.
  • menu_position – a string representing the position for the post type to show in the menu. The values go approximately from 5 up until 100.
  • supports – this value has an array value again, this time with values like title, editor, thumbnail, custom-fields, trackbacks, revisions, page-attributes and post-formats.

The main args array is used in the next register_post_type function that has the first parameter the custom post type name (in our case CPT) and the second the $args variable.

This pretty much covers creating our main custom post type, with the example given and explained above.


Step 4 Coding the Meta Box

First, we covered hooks, one of the hooks implemented a tag that had a callback function made specifically for meta box implementation. That function looks like this:

function cpt_add_meta_boxes() {
	add_meta_box('cpt_meta_id', 'Custom Post Type Settings', 'cpt_inner_custom_box', 'CPT', 'normal');
}

Inside the function we have the add_meta_box function that has the default parameters for implementing a meta box, namely, the unique meta box id, the title of it, the callback function and the custom post type where it should be applied, also last but not least, the position (we are going to set it to normal as we want it right under the editor).

That’s it for generating using the API, but what do we fill it with? Well, we need to fill it with all of the previously discussed options from step 3 and to do this, we are going to create form fields and fill them up with data depending on their type.

Some Will Be Checkboxes

We are using checkboxes for the array arguments that need boolean values. Checked is true and unchecked is false.

	<td><input type="checkbox" <?php
		if ($cp_publicly_queryable == "on") {
			echo "checked";
		}
	?> name="cp_publicly_queryable" /> Publicly Queryable </td>

Others Will Be Drop Down Boxes

Some array arguments require multiple elements to choose from. For this we are using drop down boxes with hardcoded values that fit our needs.

<td>Menu Position:<br/>
	<select name="cp_menu_position">
		<option value="post" <?php
		if ($cp_menu_position == "post") {
			echo "selected";
		}
		?>>Post</option>
		<option value="page" <?php
		if ($cp_menu_position == "page") {
			echo "selected";
		}
		?>>Page</option>
	</select>
</td>

And Others Text Fields

We are going to store string values in these form fields.

<td>General name:<br/> <input type="text" name="cp_general_name" value="<?php echo $cp_general_name; ?>"/></td>

You may have noticed that they are filled with PHP variables and are functioning with data. But where are these variables coming from you may ask yourself, and what about the data? To answer this question we must go to the next step and save the form fields created just now. But because I don’t want to make you go back and forward through the steps, I will ask you to assume that all the data is saved somehow in the database, I will show you how, and all we need to do is extract it into variables like in the following example:

global $post;

$cp_public = get_post_meta($post->ID, 'cp_public', true);

In our meta box callback function we declare the global variable $post to get the current post id later and because the data is stored as a custom post, we are going to use the get_post_meta function to get the meta key value stored for each variable like the example above, where the first parameter is the post id, the second is the meta key and the third is a boolean telling the function to return a string and not an array.

There are a number of 27 variables used in this tutorial stored as custom posts and they look like this:

	$cp_public = get_post_meta($post->ID, 'cp_public', true);
	$cp_publicly_queryable = get_post_meta($post->ID, 'cp_publicly_queryable', true);
	$cp_show_ui = get_post_meta($post->ID, 'cp_show_ui', true);
	$cp_show_in_menu = get_post_meta($post->ID, 'cp_show_in_menu', true);
	$cp_query_var = get_post_meta($post->ID, 'cp_query_var', true);
	$cp_rewrite = get_post_meta($post->ID, 'cp_rewrite', true);
	$cp_has_archive = get_post_meta($post->ID, 'cp_has_archive', true);
	$cp_hierarchical = get_post_meta($post->ID, 'cp_hierarchical', true);
	$cp_capability_type = get_post_meta($post->ID, 'cp_capability_type', true);
	$cp_menu_position = get_post_meta($post->ID, 'cp_menu_position', true);
	$cp_s_title = get_post_meta($post->ID, 'cp_s_title', true);
	$cp_s_editor = get_post_meta($post->ID, 'cp_s_editor', true);
	$cp_s_author = get_post_meta($post->ID, 'cp_s_author', true);
	$cp_s_thumbnail = get_post_meta($post->ID, 'cp_s_thumbnail', true);
	$cp_s_excerpt = get_post_meta($post->ID, 'cp_s_excerpt', true);
	$cp_s_comments = get_post_meta($post->ID, 'cp_s_comments', true);
	$cp_general_name = get_post_meta($post->ID, 'cp_general_name', true);
	$cp_singular_name = get_post_meta($post->ID, 'cp_singular_name', true);
	$cp_add_new = get_post_meta($post->ID, 'cp_add_new', true);
	$cp_add_new_item = get_post_meta($post->ID, 'cp_add_new_item', true);
	$cp_edit_item = get_post_meta($post->ID, 'cp_edit_item', true);
	$cp_new_item = get_post_meta($post->ID, 'cp_new_item', true);
	$cp_all_items = get_post_meta($post->ID, 'cp_all_items', true);
	$cp_view_item = get_post_meta($post->ID, 'cp_view_item', true);
	$cp_search_items = get_post_meta($post->ID, 'cp_search_items', true);
	$cp_not_found = get_post_meta($post->ID, 'cp_not_found', true);
	$cp_not_found_in_trash = get_post_meta($post->ID, 'cp_not_found_in_trash', true);
	$cp_parent_item_colon = get_post_meta($post->ID, 'cp_parent_item_colon', true);

What you need to understand is that they are all extracted the same way, there’s nothing special or different on this long list of variables except their values. Of course, the idea is that this code gets the data from the database and is used later on in each form field to show that data in the admin panel meta box as a selected value, as a string, or as a checked checkbox for boolean values. All the functionality can be seen better in the attached downloadable files.

As a result so far, this is how a custom post of the custom post type meta box content looks like based on our implementation.


Step 5 Saving the Data

All that form data submitted from the meta box needs to be saved into the database so that it may be used later to make the custom post type dynamic and also in the functionality of the meta box. To save the data we have the cpt_save_postdata function as a callback function that we created to do just that. But this function needs to be filled with functionality that actually saves the data. So, how do we save the data for all of these elements. The easy and most obvious answer is custom fields. We are going to store all these values in custom fields of the main custom post type individual post, as it is much easier to manage later when we extract them based on a certain queried post.

Here is all the code required to run in the previously specified function in order to save all the data we need.

global $post;
if ($_POST['cpt-hidd'] == 'true') {
	$cp_public = get_post_meta($post->ID, 'cp_public', true);
	$cp_publicly_queryable = get_post_meta($post->ID, 'cp_publicly_queryable', true);
	$cp_show_ui = get_post_meta($post->ID, 'cp_show_ui', true);
	$cp_show_in_menu = get_post_meta($post->ID, 'cp_show_in_menu', true);
	$cp_query_var = get_post_meta($post->ID, 'cp_query_var', true);
	$cp_rewrite = get_post_meta($post->ID, 'cp_rewrite', true);
	$cp_has_archive = get_post_meta($post->ID, 'cp_has_archive', true);
	$cp_hierarchical = get_post_meta($post->ID, 'cp_hierarchical', true);
	$cp_capability_type = get_post_meta($post->ID, 'cp_capability_type', true);
	$cp_menu_position = get_post_meta($post->ID, 'cp_menu_position', true);
	$cp_s_title = get_post_meta($post->ID, 'cp_s_title', true);
	$cp_s_editor = get_post_meta($post->ID, 'cp_s_editor', true);
	$cp_s_author = get_post_meta($post->ID, 'cp_s_author', true);
	$cp_s_thumbnail = get_post_meta($post->ID, 'cp_s_thumbnail', true);
	$cp_s_excerpt = get_post_meta($post->ID, 'cp_s_excerpt', true);
	$cp_s_comments = get_post_meta($post->ID, 'cp_s_comments', true);
	$cp_general_name = get_post_meta($post->ID, 'cp_general_name', true);
	$cp_singular_name = get_post_meta($post->ID, 'cp_singular_name', true);
	$cp_add_new = get_post_meta($post->ID, 'cp_add_new', true);
	$cp_add_new_item = get_post_meta($post->ID, 'cp_add_new_item', true);
	$cp_edit_item = get_post_meta($post->ID, 'cp_edit_item', true);
	$cp_new_item = get_post_meta($post->ID, 'cp_new_item', true);
	$cp_all_items = get_post_meta($post->ID, 'cp_all_items', true);
	$cp_view_item = get_post_meta($post->ID, 'cp_view_item', true);
	$cp_search_items = get_post_meta($post->ID, 'cp_search_items', true);
	$cp_not_found = get_post_meta($post->ID, 'cp_not_found', true);
	$cp_not_found_in_trash = get_post_meta($post->ID, 'cp_not_found_in_trash', true);
	$cp_parent_item_colon = get_post_meta($post->ID, 'cp_parent_item_colon', true);

	update_post_meta($post->ID, 'cp_public', $_POST['cp_public'], $cp_public);
	update_post_meta($post->ID, 'cp_publicly_queryable', $_POST['cp_publicly_queryable'], $cp_publicly_queryable);
	update_post_meta($post->ID, 'cp_show_ui', $_POST['cp_show_ui'], $cp_show_ui);
	update_post_meta($post->ID, 'cp_show_in_menu', $_POST['cp_show_in_menu'], $cp_show_in_menu);
	update_post_meta($post->ID, 'cp_query_var', $_POST['cp_query_var'], $cp_query_var);
	update_post_meta($post->ID, 'cp_rewrite', $_POST['cp_rewrite'], $cp_rewrite);
	update_post_meta($post->ID, 'cp_has_archive', $_POST['cp_has_archive'], $cp_has_archive);
	update_post_meta($post->ID, 'cp_hierarchical', $_POST['cp_hierarchical'], $cp_hierarchical);
	update_post_meta($post->ID, 'cp_capability_type', $_POST['cp_capability_type'], $cp_capability_type);
	update_post_meta($post->ID, 'cp_menu_position', $_POST['cp_menu_position'], $cp_menu_position);
	update_post_meta($post->ID, 'cp_s_title', $_POST['cp_s_title'], $cp_s_title);
	update_post_meta($post->ID, 'cp_s_editor', $_POST['cp_s_editor'], $cp_s_editor);
	update_post_meta($post->ID, 'cp_s_author', $_POST['cp_s_author'], $cp_s_author);
	update_post_meta($post->ID, 'cp_s_thumbnail', $_POST['cp_s_thumbnail'], $cp_s_thumbnail);
	update_post_meta($post->ID, 'cp_s_excerpt', $_POST['cp_s_excerpt'], $cp_s_excerpt);
	update_post_meta($post->ID, 'cp_s_comments', $_POST['cp_s_comments'], $cp_s_comments);
	update_post_meta($post->ID, 'cp_general_name', $_POST['cp_general_name'], $cp_general_name);
	update_post_meta($post->ID, 'cp_singular_name', $_POST['cp_singular_name'], $cp_singular_name);
	update_post_meta($post->ID, 'cp_add_new', $_POST['cp_add_new'], $cp_add_new);
	update_post_meta($post->ID, 'cp_add_new_item', $_POST['cp_add_new_item'], $cp_add_new_item);
	update_post_meta($post->ID, 'cp_edit_item', $_POST['cp_edit_item'], $cp_edit_item);
	update_post_meta($post->ID, 'cp_new_item', $_POST['cp_new_item'], $cp_new_item);
	update_post_meta($post->ID, 'cp_all_items', $_POST['cp_all_items'], $cp_all_items);
	update_post_meta($post->ID, 'cp_view_item', $_POST['cp_view_item'], $cp_view_item);
	update_post_meta($post->ID, 'cp_search_items', $_POST['cp_search_items'], $cp_search_items);
	update_post_meta($post->ID, 'cp_not_found', $_POST['cp_not_found'], $cp_not_found);
	update_post_meta($post->ID, 'cp_not_found_in_trash', $_POST['cp_not_found_in_trash'], $cp_not_found_in_trash);
	update_post_meta($post->ID, 'cp_parent_item_colon', $_POST['cp_parent_item_colon'], $cp_parent_item_colon);
}

First, we extract the variables like we previously did in the top of the meta box functionality, and then we update them using the update_post_meta function, that we give the parameters: post id, meta key name, new value, old value. Voila, we have updated the custom field of one value. We need to repeat the process as you see in the above example to cover all the values and all the options we need.

That’s it for saving the data.


Step 6 Creating the Dynamic Custom Post Types

So how do we take all that data we just saved and make it dynamic? how do we use it to generate custom post types? Easy, we query the main custom post type, and for each loop post we extract the custom fields and place the data inside the array accordingly.

Let’s take a look at how to do that. First, we place this code right under the main custom post type code, inside the init_custom_post_types function. And so, we start by creating the query:

$the_query = new WP_Query(array('post_type' => array('CPT')));
while ($the_query->have_posts()) : $the_query->the_post();

We create a variable named $the_query in which we store the contents of the invoked main class function wp_query with the parameters of an array that has the value of the post_type the name of the main custom post type, namely, CPT. Then we start the loop. Inside the loop we generate the variables that we want to hold the values we need by using the same approach in extracting them from the database as custom fields:

global $post;
//*************************get the values
$cp_public = get_post_meta($post->ID, 'cp_public', true);
if ($cp_public == "on") {
	$cp_public = true;
}
else {
	$cp_public = false;
}
$cp_publicly_queryable = get_post_meta($post->ID, 'cp_publicly_queryable', true);
if ($cp_publicly_queryable == "on") {
	$cp_publicly_queryable = true;
}
else {
	$cp_publicly_queryable = false;
}
$cp_show_ui = get_post_meta($post->ID, 'cp_show_ui', true);
if ($cp_show_ui == "on") {
	$cp_show_ui = true;
}
else {
	$cp_show_ui = false;
}
$cp_show_in_menu = get_post_meta($post->ID, 'cp_show_in_menu', true); //
if ($cp_show_in_menu == "on") {
	$cp_show_in_menu = true;
}
else {
	$cp_show_in_menu = false;
}
$cp_query_var = get_post_meta($post->ID, 'cp_query_var', true); //
if ($cp_query_var == "on") {
	$cp_query_var = true;
}
else {
	$cp_query_var = false;
}
$cp_rewrite = get_post_meta($post->ID, 'cp_rewrite', true); //
if ($cp_rewrite == "on") {
	$cp_rewrite = true;
}
else {
	$cp_rewrite = false;
}
$cp_has_archive = get_post_meta($post->ID, 'cp_has_archive', true); //
if ($cp_has_archive == "on") {
	$cp_has_archive = true;
}
else {
	$cp_has_archive = false;
}
$cp_hierarchical = get_post_meta($post->ID, 'cp_hierarchical', true);
if ($cp_hierarchical == "on") {
	$cp_hierarchical = true;
}
else {
	$cp_hierarchical = false;
}
$cp_capability_type = get_post_meta($post->ID, 'cp_capability_type', true);
$cp_menu_position = get_post_meta($post->ID, 'cp_menu_position', true);
$cp_s_title = get_post_meta($post->ID, 'cp_s_title', true);
if ($cp_s_title == "on") {
	$cp_s[] = 'title';
}
$cp_s_editor = get_post_meta($post->ID, 'cp_s_editor', true);
if ($cp_s_editor == "on") {
	$cp_s[] = 'editor';
}
$cp_s_author = get_post_meta($post->ID, 'cp_s_author', true);
if ($cp_s_author == "on") {
	$cp_s[] = 'author';
}
$cp_s_thumbnail = get_post_meta($post->ID, 'cp_s_thumbnail', true);
if ($cp_s_thumbnail == "on") {
	$cp_s[] = 'thumbnail';
}
$cp_s_excerpt = get_post_meta($post->ID, 'cp_s_excerpt', true);
if ($cp_s_excerpt == "on") {
	array_push($cp_s, 'excerpt');
}
$cp_s_comments = get_post_meta($post->ID, 'cp_s_comments', true);
if ($cp_s_comments == "on") {
	array_push($cp_s, 'comments');
}
$cp_general_name = get_post_meta($post->ID, 'cp_general_name', true);
$cp_singular_name = get_post_meta($post->ID, 'cp_singular_name', true);
$cp_add_new = get_post_meta($post->ID, 'cp_add_new', true);
$cp_add_new_item = get_post_meta($post->ID, 'cp_add_new_item', true);
$cp_edit_item = get_post_meta($post->ID, 'cp_edit_item', true);
$cp_new_item = get_post_meta($post->ID, 'cp_new_item', true);
$cp_all_items = get_post_meta($post->ID, 'cp_all_items', true);
$cp_view_item = get_post_meta($post->ID, 'cp_view_item', true);
$cp_search_items = get_post_meta($post->ID, 'cp_search_items', true);
$cp_not_found = get_post_meta($post->ID, 'cp_not_found', true);
$cp_not_found_in_trash = get_post_meta($post->ID, 'cp_not_found_in_trash', true);
$cp_parent_item_colon = get_post_meta($post->ID, 'cp_parent_item_colon', true);

Because we are now inside the query loop, we can use a global $post variable to get the ID we need. Also you might have noticed a few conditions set by an if here and there for most variables. These exist because the true boolean value or certain other string values need to be converted correctly from the "on" string they represent into the true boolean value they need to be.

After all of this is taken care of, we will insert the variables into the array of the dynamic custom post type implementation:

	$labels = array(
		'name' => _x(get_the_title($post->ID), 'post type general name'),
		'singular_name' => _x($cp_singular_name, 'post type singular name'),
		'add_new' => _x($cp_add_new, get_the_title($post->ID)),
		'add_new_item' => __($cp_add_new_item),
		'edit_item' => __($cp_edit_item),
		'new_item' => __($cp_new_item),
		'all_items' => __($cp_all_items),
		'view_item' => __($cp_view_item),
		'search_items' => __($cp_search_items),
		'not_found' => __($cp_not_found),
		'not_found_in_trash' => __($cp_not_found_in_trash),
		'parent_item_colon' => __($cp_parent_item_colon),
		'menu_name' => __(get_the_title($post->ID))
	);

	$args = array(
		'labels' => $labels,
		'public' => $cp_public,
		'publicly_queryable' => $cp_publicly_queryable,
		'show_ui' => $cp_show_ui,
		'show_in_menu' => $cp_show_in_menu,
		'query_var' => $cp_query_var,
		'rewrite' => $cp_rewrite,
		'capability_type' => 'post',
		'has_archive' => $cp_has_archive,
		'hierarchical' => $cp_hierarchical,
		'menu_position' => $cp_menu_position,
		'supports' => $cp_s
	);
	register_post_type(get_the_title($post->ID), $args);
endwhile;

The post title is being used as the main name of the custom post type and the meta box settings as the rest of the properties. That is all, all that is needed to implement the dynamic custom post types into WordPress. What you might have noticed is that we also close the loop at the end of the previous code.


Conclusion

Custom post types are not hard to handle and they are pretty flexible in any functionality that you might require even with other hooks, filters or custom functions. In this tutorial we managed to cover a specific dynamic implementation of custom post type management in a single plugin, explained, with code and files, for your needs. Of course, the use of custom post type does not limit to these examples as it can be used in many types of implementations, plugins and themes tangled in many hooks, queried in different ways, filtered or manipulated in a lot of ways.

Ciprian Turcu is CiprianTurcu on Themeforest
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.leachcreative.com/ Andrew

    Great job with this. This would definitely make CPT management easier.

  • http://wp.tutsplus.com/author/leepham/ Lee Pham

    Hi Ciprian,

    Thanks for tutorial. I sure that you can make your code more concise. You can see checked and selected. For example, using:

    <td><input type="checkbox" <?php check( $cp_publicly_queryable, ‘on’, true ); ?> name="cp_publicly_queryable" /> Publicly Queryable </td>

    instead of:

    <td><input type="checkbox" <?php
    if ($cp_publicly_queryable == "on") {
    echo "checked";
    }
    ?> name="cp_publicly_queryable" /> Publicly Queryable </td>

    and we have so much variables (up to 27). Why don’t you pass them into a array variable? It’s really faster, right? Thanks again for this post.

  • http://www.uxde.net Toan Nguyen Minh

    Great tutorial. I have a small question. Can we setting the URL of Custom Post Type?

    • http://cloudofthemes.com Connor Crosby

      Yes, add the following:
      ‘rewrite’ => array(‘slug’ => ‘your-slug’, ‘with_front’ => ‘before-your-slug’),

  • http://www.customicondesign.com Custom Icon Design

    This is awosome tutorial especially it provides download function. Good job.

  • Pingback: Building a Dynamic Custom Post Type Plugin in WordPress « TECH STUFFS

  • http://sdmmovies.com Rahul Kashyap

    Awesome tutorial thanks for sharing this :)

  • trkiwp

    Very nice tutorial … i have question.. little be out of this theme but if someone would want to help me i would be glad. So … I created own CPT … there i created collum with name: ‘likes’ and know… i want to at my web create to example some ‘like style’ button and when i click it my collum ‘likes’ in CPT with update +1… hm… any ideas? :)

    I am just noob in WP.

    Normally i would do it easily just make form or some script and on click i would call mysql_query(Update junks junks junks and likes=likes+1 … but how here :P thx :)

  • trkiwp

    Oh yea and i forget you have mistake in your download file in name: ‘dinamic? ‘ :)

  • Adam

    Good tutorial and an interesting approach, to using Custom Post Types.

    I’m curious though as to why you chose to use the Custom Post Type API versus the Settings API/Options API?

    Having a post type define other post types in the post and post meta tables doesn’t seem like the best approach.

    Also, should the parent custom post type “CPT” not have its publicly_queryable value set to false instead of true?

  • http://posttypefactory.com Dave

    Interesting approach. I’ve developed a plugin for this as well so it’s always good to see how other people approach the same idea.

    I went a different route and made each post type a separate instance. Saving each post type property as a meta value will add a lot of data to the post_meta table if a site uses custom post types heavily.

    If anybody is interested in another approach to this, check out http://posttypefactory.com.

  • Steffo

    The idea behind this is awesome, but I can’t seem to get it to work.
    I’ve got the plugin running, and created a new post type with it called “news”. It’s public and publicly queryable, however when I try to run a wp_query with post_type => ‘news’, it just returns posts from default post_type ‘post’.

    In admin when creating new posts in my new CPT, and I take “View”, the page doesn’t reflect the content of that post, instead the content is from a ‘post’.

    Any ideas what could be wrong?

  • Pingback: Useful Tutorials For Creating Your First WordPress Plugin | DesignWoop

  • oumz

    Have been trying for over 2 hours now, but it seems that the code does not work..throws various errors ..Anybody facing similar issues?

  • Pingback: Tutorials Που Θα Σας Βοηθήσουν Να Δημιουργήσετε Το Πρώτο Σας WP Plugin | Ελληνική Κοινότητα WordPress

  • Pingback: 30 Useful Tutorials to Create WordPress Plugin | Doublemesh

  • thatFunkymunkey

    You may want to check your source. The Capability Type and Menu Position are switched.

    This also doesn’t really plan for using a user management plugin like the popular “Members” plugin so the individual capabilities must be added in as an array after changing the Capability Type input to a text field or using javascript to mirror what’s in the post title field.

    Just friendly suggestions on how to improve the code. :)

  • Pingback: WordPress Tutorials – Feedback Welcome | Lionpath – Tutorial and Examples

  • Pingback: Top 160 Tutoriais WordPress – incluindo Basico, Desenvolvimento e Plugins – Site para Empresas – Blog sobre Internet e Criação de Site

  • http://www.facebook.com/nathan.simpson1 Nathan Simpson

    Has anyone requested to see in action or play with a n example live – would be nice? I always think that should be first then the explanation – sort of a kind gesture – but either way thank you for sharing and your time in explaining – the info is greatly appreciated…

  • http://www.facebook.com/nathan.simpson1 Nathan Simpson

    Ok – I see the download i guess i’ll set up and view and post link so others can to – thanks! sorry no coffee lots of “to do’s ” thanks again for posting.