WP Smith

Creating WordPress & Genesis Websites Since 2010

  • Home
  • About
  • Services
  • Blog
  • Contact

Jan 02 2012

Developing a Custom Post Type and a Custom Taxonomy in Genesis with Custom Pages, Part 1

Recently, someone contacted me to develop a custom post type setup for their website, and they were lamenting how there is nothing on the web that succinctly walks them through the process: soup to nuts. So here's my attempt! However, I am going to assume basic knowledge of custom post types. If you haven't read through my Understanding Custom Post Types series yet, you may want to do that.

First, I created a new php file called wps-admin-functions.php. This is where we will house our Custom Post Types, Taxonomies, and Metaboxes. We could have added this to our theme’s function.php file but this will allow us to have a separate file dedicated to our newly added features. To do this, simply create a new text document in your favorite text editor and save as wps-admin-functions.php.

1. Register your Custom Post Type

[php]<?php
// registration code for discbrakes post type
function wps_register_discbrakes_posttype() {
$labels = array(
'name' => _x( 'Disc Brakes', 'post type general name' ),
'singular_name' => _x( 'Disc Brake', 'post type singular name' ),
'add_new' => _x( 'Add New', 'Disc Brake'),
'add_new_item' => __( 'Add New Disc Brake '),
'edit_item' => __( 'Edit Disc Brake '),
'new_item' => __( 'New Disc Brake '),
'view_item' => __( 'View Disc Brake '),
'search_items' => __( 'Search Disc Brakes '),
'not_found' => __( 'No Disc Brake found' ),
'not_found_in_trash' => __( 'No Disc Brakes found in Trash' ),
'parent_item_colon' => ''
);

$supports = array( 'title' , 'editor' , 'thumbnail' , 'excerpt' , 'revisions' );

$post_type_args = array(
'labels' => $labels,
'singular_label' => __( 'Disc Brake' ),
'public' => true,
'show_ui' => true,
'publicly_queryable' => true,
'query_var' => true,
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'rewrite' => array( 'slug' => 'discbrakes' ),
'supports' => $supports,
'menu_position' => 5,
'taxonomies' => array( 'wps_axlesizes' ),
'menu_icon' => 'http://mydomain.com/wp-content/themes/lib/images/discbrakes-icon.png'
);
register_post_type( 'wps_discbrakes' , $post_type_args );
}
add_action( 'init', 'wps_register_discbrakes_posttype' );
[/php]

Notice in this code that I associate my custom post type with my coming custom taxonomy: 'taxonomies' => array( 'wps_axlesizes' ),. Also, note that I am using a prefix on both my custom post type and taxonomy. The reason this is done is that there may be a naming conflict with a plugin or other code in your theme. The prefix uniquely identifies it to prevent this. It is a best practice, and make sure you do not use the wp_ or genesis_ prefixes.

2. Register your Custom Taxonomy

[php]<?php
// registration code for AxleSizes taxonomy
function wps_register_axlesizes_tax() {
$labels = array(
'name' => _x( 'Axle Sizes', 'taxonomy general name' ),
'singular_name' => _x( 'Axle Size', 'taxonomy singular name' ),
'add_new' => _x( 'Add New Axle Size', 'Axle Size'),
'add_new_item' => __( 'Add New Axle Size' ),
'edit_item' => __( 'Edit Axle Size' ),
'new_item' => __( 'New Axle Size' ),
'view_item' => __( 'View Axle Size' ),
'search_items' => __( 'Search Axle Sizes' ),
'not_found' => __( 'No Axle Size found' ),
'not_found_in_trash' => __( 'No Axle Size found in Trash' ),
);

$pages = array( 'wps_discbrakes' );

$args = array(
'labels' => $labels,
'singular_label' => __( 'Axle Size' ),
'public' => true,
'show_ui' => true,
'hierarchical' => false,
'show_tagcloud' => false,
'show_in_nav_menus' => true,
'rewrite' => array('slug' => 'axle-sizes'),
);
register_taxonomy( 'wps_axlesizes' , $pages , $args );
}
add_action( 'init' , 'wps_register_axlesizes_tax' );[/php]

Custom Post TypeNotice in the registration, the taxonomy is associated with my custom post type: $pages = array( 'wps_discbrakes' );.

Once these are registered, you should see your custom post type to the left under POST.

3. Create my Metaboxes
With metaboxes, you can go the long way; however, I prefer to use a class. Soon WordPress will have a metabox class, hopefully in WordPress 3.3, so this section will be rendered "obsolete" yet still usable. First, download the custom metabox code from GitHub. For a great explanation of the code, see Bill Erickson's tutorial. Because of the tutorial, I won't break down this section.

Once downloaded, place the metabox folder in your lib folder in the child theme folder so that: CHILD_URL . '/lib/metabox/init.php'

So the file structure is
CHILD-THEME-FOLDER

  • IMAGES FOLDER
  • LIB FOLDER
    • METABOX FOLDER
    • IMAGES FOLDER
    • wps-admin-functions.php
  • functions.php
  • style.css
  • readme.txt

[php]<?php
// Create Metaboxes
$prefix = '_wps_';
add_filter( 'cmb_meta_boxes', 'wps_create_metaboxes' );
function wps_create_metaboxes() {
global $prefix;

$meta_boxes[] = array(
'id' => 'disk-brakes-info',
'title' => 'Disk Brakes Information',
'pages' => array( 'wps_discbrakes' ), // post type
'context' => 'normal',
'priority' => 'low',
'show_names' => true, // Show field names left of input
'fields' => array(
array(
'name' => 'Instructions',
'desc' => 'In the right column upload a featured image. Make sure this image is at least 900x360px wide. Then fill out the information below.',
'id' => $prefix . 'title',
'type' => 'title',
),
array(
'name' => 'Part Number',
'desc' => 'Enter the part number (e.g., XXXXXXX)',
'id' => $prefix . 'part_number',
'type' => 'text'
),
array(
'name' => 'Rotor',
'desc' => '',
'id' => $prefix . 'rotor',
'type' => 'select',
'options' => array(
array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
array('name' => 'Option Three', 'value' => 'none')
)
),
array(
'name' => 'Caliper',
'desc' => '',
'id' => $prefix . 'caliper',
'type' => 'select',
'options' => array(
array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
array('name' => 'Option Three', 'value' => 'none')
)
),
array(
'name' => 'Mounting Bracket',
'desc' => '',
'id' => $prefix . 'mounting_bracket',
'type' => 'select',
'options' => array(
array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
array('name' => 'Option Three', 'value' => 'none')
)
),
array(
'name' => 'Weight per Axle Set',
'desc' => 'e.g., 45 LBS.',
'id' => $prefix . 'weight_per_axle_set',
'type' => 'text'
),
),
);

return $meta_boxes;
}

// Initialize the metabox class
add_action( 'init', 'be_initialize_cmb_meta_boxes', 9999 );
function be_initialize_cmb_meta_boxes() {
if ( !class_exists( 'cmb_Meta_Box' ) ) {
require_once(CHILD_DIR . '/lib/metabox/init.php');
}
}
[/php]

This will create the metaboxes for the custom post type.
Custom Post Type Metaboxes

4. Clear Permalinks
Now in your admin area, navigate to Settings > Permalinks and click Save Changes. This will flush and clear your permalinks. This is important if you are getting strange 404 Page Not Found errors.

So our finished product is this: wps-admin-functions.php

[php]
<?php

/**
* Admin Functions
*
* This file is responsible for registering the
* custom post types, taxonomies, and metaboxes.
*
* @author Travis Smith <[email protected]>
* @copyright Copyright (c) 2011, Travis Smith
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
*
*/

// registration code for discbrakes post type
// registration code for discbrakes post type
function wps_register_discbrakes_posttype() {
$labels = array(
'name' => _x( 'Disc Brakes', 'post type general name' ),
'singular_name' => _x( 'Disc Brake', 'post type singular name' ),
'add_new' => _x( 'Add New', 'Disc Brake'),
'add_new_item' => __( 'Add New Disc Brake '),
'edit_item' => __( 'Edit Disc Brake '),
'new_item' => __( 'New Disc Brake '),
'view_item' => __( 'View Disc Brake '),
'search_items' => __( 'Search Disc Brakes '),
'not_found' => __( 'No Disc Brake found' ),
'not_found_in_trash' => __( 'No Disc Brakes found in Trash' ),
'parent_item_colon' => ''
);

$supports = array( 'title' , 'editor' , 'thumbnail' , 'excerpt' , 'revisions' );

$post_type_args = array(
'labels' => $labels,
'singular_label' => __( 'Disc Brake' ),
'public' => true,
'show_ui' => true,
'publicly_queryable' => true,
'query_var' => true,
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'rewrite' => array( 'slug' => 'discbrakes' ),
'supports' => $supports,
'menu_position' => 5,
'taxonomies' => array( 'wps_axlesizes' ),
'menu_icon' => 'http://mydomain.com/wp-content/themes/lib/images/discbrakes-icon.png'
);
register_post_type( 'wps_discbrakes' , $post_type_args );
}
add_action( 'init', 'wps_register_discbrakes_posttype' );

// registration code for AxleSizes taxonomy
function wps_register_axlesizes_tax() {
$labels = array(
'name' => _x( 'Axle Sizes', 'taxonomy general name' ),
'singular_name' => _x( 'Axle Size', 'taxonomy singular name' ),
'add_new' => _x( 'Add New Axle Size', 'Axle Size'),
'add_new_item' => __( 'Add New Axle Size' ),
'edit_item' => __( 'Edit Axle Size' ),
'new_item' => __( 'New Axle Size' ),
'view_item' => __( 'View Axle Size' ),
'search_items' => __( 'Search Axle Sizes' ),
'not_found' => __( 'No Axle Size found' ),
'not_found_in_trash' => __( 'No Axle Size found in Trash' ),
);

$pages = array( 'wps_discbrakes' );

$args = array(
'labels' => $labels,
'singular_label' => __( 'Axle Size' ),
'public' => true,
'show_ui' => true,
'hierarchical' => false,
'show_tagcloud' => false,
'show_in_nav_menus' => true,
'rewrite' => array('slug' => 'axle-sizes'),
);
register_taxonomy( 'wps_axlesizes' , $pages , $args );
}
add_action( 'init' , 'wps_register_axlesizes_tax' );

// Create Metaboxes
$prefix = '_wps_';
add_filter( 'cmb_meta_boxes', 'wps_create_metaboxes' );
function wps_create_metaboxes() {
global $prefix;

$meta_boxes[] = array(
'id' => 'disk-brakes-info',
'title' => 'Disk Brakes Information',
'pages' => array( 'wps_discbrakes' ), // post type
'context' => 'normal',
'priority' => 'low',
'show_names' => true, // Show field names left of input
'fields' => array(
array(
'name' => 'Instructions',
'desc' => 'In the right column upload a featured image. Make sure this image is at least 900x360px wide. Then fill out the information below.',
'id' => $prefix . 'title',
'type' => 'title',
),
array(
'name' => 'Part Number',
'desc' => 'Enter the part number (e.g., XXXXXXX)',
'id' => $prefix . 'part_number',
'type' => 'text'
),
array(
'name' => 'Rotor',
'desc' => '',
'id' => $prefix . 'rotor',
'type' => 'select',
'options' => array(
array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
array('name' => 'Option Three', 'value' => 'none')
)
),
array(
'name' => 'Caliper',
'desc' => '',
'id' => $prefix . 'caliper',
'type' => 'select',
'options' => array(
array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
array('name' => 'Option Three', 'value' => 'none')
)
),
array(
'name' => 'Mounting Bracket',
'desc' => '',
'id' => $prefix . 'mounting_bracket',
'type' => 'select',
'options' => array(
array('name' => 'Stainless Steel', 'value' => 'stainless-steel'),
array('name' => 'E-Coat (Black)', 'value' => 'e-coat-black'),
array('name' => 'Option Three', 'value' => 'none')
)
),
array(
'name' => 'Weight per Axle Set',
'desc' => 'e.g., 45 LBS.',
'id' => $prefix . 'weight_per_axle_set',
'type' => 'text'
),
),
);

return $meta_boxes;
}

// Initialize the metabox class
add_action( 'init', 'wps_initialize_cmb_meta_boxes', 9999 );
function wps_initialize_cmb_meta_boxes() {
if ( !class_exists( 'cmb_Meta_Box' ) ) {
require_once(CHILD_DIR . '/lib/metabox/init.php');
}
}
[/php]

Written by Travis Smith · Categorized: Custom Post Types, Genesis

StudioPress Premium WordPress Themes     WP Engine Managed WordPress Hosting

What can I do for you!?

Custom Development

We develop plugins by determining both business/functional and technical requirements, following WordPress development best practices, and using agile methodology to ensure you get the best solution.

Consulting

Have questions? Need a reliable developer to consult? Please contact us today!

Customized Theme

We can customize your theme or child theme, or create a child theme for you based on your needs while enhancing the performance of every individual attribute.

Customized Plugin

We can customize your plugins, extend plugins (e.g., Gravity Forms, Jetpack, Soliloquy) based on your needs ensuring security, performance, and positive business impact.

Contact Us

About Travis Smith

As a WordPress enthusiast, developer, and speaker, Travis writes about what he learns in WordPress trying to help other WordPress travelers, beginners and enthusiasts with tutorials, explanations, & demonstrations.

Comments

  1. Loren Nason says

    January 13, 2012 at 2:38 am

    Travis,

    Your tutorials are awesome.

    I had already had my own custom post type and was venturing into needing a meta box and then I found your post. I’ve followed everything adding all the required info for doing the meta_boxes and I’ve got nada.

    So I thought there was something wrong with my file so I did everything exactly like you did it completely copying everything and still no metaboxes.

    My file structure is exactly like you have

    Even when setting up my files with your example code the CPT work just no metaboxes.
    Also when making the wps-admin-functions.php I got an error on line 153
    It needed a semi-colon

    Still no metaboxes

    Any pointers?

    FYI it’s on a test domain and im monkeying around in agentpress child theme. (if that matters)

    Reply
  2. Loren Nason says

    January 15, 2012 at 4:10 am

    Got it working

    $meta_boxes needed to be return $meta_boxes;

    Reply
    • Travis Smith says

      January 30, 2012 at 11:02 am

      Thanks for pointing out my error. You’re right $meta_boxes should be return $meta_boxes; My apologies! Don’t know how I missed that! Corrected this!

      Reply
  3. Patrick Hess says

    February 14, 2012 at 6:30 pm

    Hi Travis –

    Thanks for this excellent tutorial – it’s been extremely helpful. I’ve been experimenting with the custom meta boxes for a few days now and I’m a little lost on the front-end implementation. I’ve read a few options for displaying the information, but none have really worked that well. Do you have a suggestion for displaying the meta per the example above?

    I’m working from the Genesis sample child theme. Thanks for any info you can provide. I look forward to reading through the rest of your series (also, feel free to let me know if the front-end side is explained in later tutorials).

    Appreciate it,

    Patrick

    Reply
    • Travis Smith says

      February 25, 2012 at 11:51 pm

      Hello Patrick,

      Hopefully, you read through the rest of the posts. Did they answer your question? Please let me know!

      Thanks,

      Reply
  4. Leia says

    March 9, 2012 at 12:43 pm

    Hi,
    I have tried to copy your code and put it in lib folder but nothing happens, i dont get any new custom post types, any ideas what i have missed?

    Reply
    • Travis Smith says

      March 14, 2012 at 3:59 pm

      Hello Leia,

      Did you add any code to functions.php to call the file?

      Reply
  5. Shaun says

    March 13, 2012 at 4:42 am

    is there a line to add in the functions.php in order for the wps-admin-functions.php to work?

    Reply
    • Travis Smith says

      March 14, 2012 at 3:58 pm

      Yes, you would need to use an include, include_once, require or require_once statement for it to work as a separate file. See PHP.net for more information.

      Reply
      • Brooke says

        August 20, 2012 at 3:23 pm

        Can you elaborate on this pretty please? I’ve gone to PHP.net searched for “include” saw some code, but don’t know how to incorporate it into my Genesis child them functions.php. Do I add an action onto the genesis_init hook? I mean I have absolutely no idea what I’m doing here!

        Reply
        • Brooke says

          August 20, 2012 at 3:37 pm

          ahaha, I’m such a dumb A, I got it!
          // Include custom post types separate php file
          require_once(STYLESHEETPATH.’/lib/wps-admin-functions.php’);

          Reply
          • JohnLionFlow says

            December 24, 2013 at 8:13 am

            I used;
            require_once( CHILD_DIR . ‘/lib/wps-admin-functions.php’ );

            Thanks for bringing that Brooke
            And a big thankyou to you Travis!

  6. David P. Smith says

    June 27, 2012 at 10:34 pm

    Thank you Travis!

    After wasting an entire day on various tutorials (most of which worked, but were not as complete as this), I found yours. I could not get it to work, at first. But then I noticed, at the bottom, there is a call to the child theme’s directory. I’m not using a child theme. I replaced “CHILD_DIR” with “get_template_directory()” and all is well!

    Reply
  7. Andy says

    August 3, 2012 at 4:55 am

    I’ve followed your example here and copied the code as is into the wps-admin-functions.php file but I keep getting the error:
    Parse error: syntax error, unexpected ‘}’ in THEME/nitrous/lib/wps-admin-functions.php on line 154

    Any Ideas?

    Reply
    • Travis Smith says

      August 6, 2012 at 9:01 am

      Yes, I corrected the master code at the end. Try again. Typo!

      Reply
  8. Jeff La Croix says

    August 13, 2012 at 10:14 am

    On line 153 shouldn’t it be “return $meta_boxes;”?

    Reply
    • Travis Smith says

      August 13, 2012 at 10:18 am

      Yes, thanks!

      Reply
  9. carrie says

    August 21, 2012 at 10:33 am

    Hi Travis,
    Thanks for the tutorial. For some reason, adding the include code for wps-admin-functions.php in my functions.php file is killing the site. I’ve tried variations on include, include_once, require_once, etc., but none are doing the trick.

    include_once(CHILD_DIR.’/lib/wps-admin-functions.php’);

    I was wondering if it was a permissions issue on wps-admin-functions.php not being allowed to execute, but I opened up permissions on it and that wasn’t a solution. Any trouble-shooting tips?

    Thanks,
    Carrie

    Reply
    • Travis Smith says

      August 21, 2012 at 11:58 am

      Hello Carrie,

      Did you remove the CMB files as you see here?

      Thanks,

      Travis

      Reply
      • carrie says

        August 21, 2012 at 12:12 pm

        Hi Travis,
        If I use the <? php at the start, I just get a blank screen and have to fix the file via FTP. If I remove it, it outputs all the code of wps-admin-functions.php as text right after the opening tag. (See my dev site for this latter scenario in action: http://infusioncenter.net/dev/).

        My directory structure is set up with lib/metabox/init.php (and the other github-files) and lib/wps-admin-functions.php. The LIB folder is located in my child theme.

        Thanks,
        Carrie

        Reply
        • Nathan says

          August 27, 2013 at 6:12 pm

          Was this ever hashed out? This would be perfect for something I’m working on, but I can’t get anything to show up, either. I have the same issue it looks like as Carrie is/was experiencing. I know this post is over a year old… is this methodology still relevant to Genesis 2.0 and WP 3.6?

          Reply
  10. Nathan says

    September 5, 2013 at 3:57 pm

    I know this post is over a year old, but this is kind of a last-ditch effort:

    I used this quite successfully as a template for setting up my own custom post types and everything is working beautifully except for just one thing:

    In the posting panel in the WP admin/back-end, where I would assign the taxonomy, it’s more like assigning tags. The editor has my taxonomy, but instead of a list of checkboxes w/ custom taxonomies I have set, it wants me to enter tags.

    For instance, my custom post type is ‘equipment’, and the taxonomy is ‘equipment family’. I have about 7 different categories under ‘equipment families’ but when I go to add a new piece of equipment, the ‘Equipment Families’ taxonomy panel gives me a text box w/ an ‘add’ button much like adding tags on a regular post; I’d like to find out how I can get it to give me a list of my configured taxonomy ‘families’ that I can put a checkbox by to assign the taxonomy.

    Any input would be greatly appreciated. Thanks!

    Reply
  11. Newton Rodrigues says

    December 9, 2013 at 1:22 am

    Great post!

    I was able to register my custom post type with your instructions. Now, what if want to register 10 custom taxonomies for this particular custom post type: will i should repeat that code 10 time each one of them for each particular taxonomy or there is an easier why to do in one go?

    Thank you!

    Reply
    • Travis Smith says

      February 11, 2014 at 10:16 am

      Newton,

      Simply create an array and cycle through the array registering the taxonomies. Please let me know if you need more.

      Thanks,
      Travis

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  • Twitter
  • Facebook
  • LinkedIn
  • Google+
  • RSS

Copyright © 2025 � WP Smith on Genesis on Genesis Framework � WordPress � Log in