Custom Post Type Helper Class

Custom Post Type Helper Class

Tutorial Details
  • Program: WordPress (Custom Post Types)
  • Version: 3.0+ (PHP 5.3+)
  • Difficulty: Moderate
  • Estimated Completion Time: 30 minutes

For a lot of WordPress projects these days we use custom post types. The WordPress development team created some handy methods to integrate them into your projects. But when you use custom post types, taxonomies and meta boxes frequently, it’s quite probable that you’re going to repeat yourself. That’s why we are going to use the power of these WordPress functions to build a more powerful class, which we can use to quickly register post types, taxonomies and meta boxes.


Call Our Class

This is how we call our class when it’s done.

	include('custom-post-type.php');
    
	$book = new Custom_Post_Type( 'Book' );
	$book->add_taxonomy( 'category' );
	$book->add_taxonomy( 'author' );
	
	$book->add_meta_box( 
		'Book Info', 
		array(
			'Year' => 'text',
			'Genre' => 'text'
		)
	);
	
	$book->add_meta_box( 
		'Author Info', 
		array(
			'Name' => 'text',
			'Nationality' => 'text',
			'Birthday' => 'text'
		)
	);

Step 1 The Class, Properties and Methods

We start off with creating the class, main properties, constructor and methods. In this tutorial we will fill them with our programming logic.

	class Custom_Post_Type
	{
		public $post_type_name;
		public $post_type_args;
		public $post_type_labels;
		
		/* Class constructor */
		public function __construct()
		{
			
		}
		
		/* Method which registers the post type */
		public function register_post_type()
		{
			
		}
		
		/* Method to attach the taxonomy to the post type */
		public function add_taxonomy()
		{
			
		}
		
		/* Attaches meta boxes to the post type */
		public function add_meta_box()
		{
			
		}
		
		/* Listens for when the post type being saved */
		public function save()
		{
			
		}
	}

Step 2 The Constructor

Within the constructor we create some important variables, which are used within the entire class. We also call add_action to register the post type and we listen for when the post type is being saved, so we can save our post’s meta data. If the post type exists, the add_action is not called, but the $post_type_name is set, so we can add taxonomies and meta boxes to it.

	public function __construct( $name, $args = array(), $labels = array() )
	{
		// Set some important variables
		$this->post_type_name		= strtolower( str_replace( ' ', '_', $name ) );
		$this->post_type_args 		= $args;
		$this->post_type_labels 	= $labels;
		
		// Add action to register the post type, if the post type does not already exist
		if( ! post_type_exists( $this->post_type_name ) )
		{
			add_action( 'init', array( &$this, 'register_post_type' ) );
		}
		
		// Listen for the save post hook
		$this->save();
	}

Step 3 Register the Post Type

Within the register_post_type method, which gets called by the add_action in the constructor, we first determine the name (capitalized) and the plural. With this name and plural we build our labels for the post type and overwrite (and merge) them with the given labels from the $this->post_type_labels variable. Then we create our arguments with the same principle.

	public function register_post_type()
	{
		//Capitilize the words and make it plural
		$name 		= ucwords( str_replace( '_', ' ', $this->post_type_name ) );
		$plural 	= $name . 's';
		
		// We set the default labels based on the post type name and plural. We overwrite them with the given labels.
		$labels = array_merge(
		
			// Default
			array(
				'name' 					=> _x( $plural, 'post type general name' ),
				'singular_name' 		=> _x( $name, 'post type singular name' ),
				'add_new' 				=> _x( 'Add New', strtolower( $name ) ),
				'add_new_item' 			=> __( 'Add New ' . $name ),
				'edit_item' 			=> __( 'Edit ' . $name ),
				'new_item' 				=> __( 'New ' . $name ),
				'all_items' 			=> __( 'All ' . $plural ),
				'view_item' 			=> __( 'View ' . $name ),
				'search_items' 			=> __( 'Search ' . $plural ),
				'not_found' 			=> __( 'No ' . strtolower( $plural ) . ' found'),
				'not_found_in_trash' 	=> __( 'No ' . strtolower( $plural ) . ' found in Trash'), 
				'parent_item_colon' 	=> '',
				'menu_name' 			=> $plural
			),
			
			// Given labels
			$this->post_type_labels
			
		);
		
		// Same principle as the labels. We set some defaults and overwrite them with the given arguments.
		$args = array_merge(
		
			// Default
			array(
				'label' 				=> $plural,
				'labels' 				=> $labels,
				'public' 				=> true,
				'show_ui' 				=> true,
				'supports' 				=> array( 'title', 'editor' ),
				'show_in_nav_menus' 	=> true,
				'_builtin' 				=> false,
			),
			
			// Given args
			$this->post_type_args
			
		);
		
		// Register the post type
		register_post_type( $this->post_type_name, $args );
	}

Step 3 Add Some Taxonomies

First we check if the $name parameter is empty. When it is, we do nothing. When it’s not, we create three variables in which we store the information for the taxonomy: $taxonomy_name, $taxonomy_labels and $taxonomy_args.

	public function add_taxonomy( $name, $args = array(), $labels = array() )
	{
		if( ! empty( $name ) )
		{
			// We need to know the post type name, so the new taxonomy can be attached to it.
			$post_type_name = $this->post_type_name;

			// Taxonomy properties
			$taxonomy_name		= strtolower( str_replace( ' ', '_', $name ) );
			$taxonomy_labels	= $labels;
			$taxonomy_args		= $args;

			/* More code coming */
		}
	}

After we’ve done the first checks and then set some variables, we’re going to register the post type. But first we check if the taxonomy already exists.

	if( ! taxonomy_exists( $taxonomy_name ) )
	{
		/* Create taxonomy and attach it to the object type (post type) */
	}
	else
	{
		/* The taxonomy already exists. We are going to attach the existing taxonomy to the object type (post type) */
	}

If the taxonomy doesn’t exist, we register it. We use an add_action, but not in the normal way. Normally, the second parameter of the add_action is the name of a function, but since we use different parameters each time, we are going to pass a nameless function (Note: this feature requires PHP 5.3+) and use the use() function. With the use() function we can pass variables to the nameless function. This time we need to pass $taxonomy_name, $post_type_name and $taxonomy_args to register the taxonomy.

	//Capitilize the words and make it plural
	$name 		= ucwords( str_replace( '_', ' ', $name ) );
	$plural 	= $name . 's';
	
	// Default labels, overwrite them with the given labels.
	$labels = array_merge(
	
		// Default
		array(
			'name' 					=> _x( $plural, 'taxonomy general name' ),
			'singular_name' 		=> _x( $name, 'taxonomy singular name' ),
		    'search_items' 			=> __( 'Search ' . $plural ),
		    'all_items' 			=> __( 'All ' . $plural ),
		    'parent_item' 			=> __( 'Parent ' . $name ),
		    'parent_item_colon' 	=> __( 'Parent ' . $name . ':' ),
		    'edit_item' 			=> __( 'Edit ' . $name ),
		    'update_item' 			=> __( 'Update ' . $name ),
		    'add_new_item' 			=> __( 'Add New ' . $name ),
		    'new_item_name' 		=> __( 'New ' . $name . ' Name' ),
		    'menu_name' 			=> __( $name ),
		),

		// Given labels
		$taxonomy_labels

	);

	// Default arguments, overwritten with the given arguments
	$args = array_merge(

		// Default
		array(
			'label'					=> $plural,
			'labels'				=> $labels,
			'public' 				=> true,
			'show_ui' 				=> true,
			'show_in_nav_menus' 	=> true,
			'_builtin' 				=> false,
		),

		// Given
		$taxonomy_args

	);
	
	// Add the taxonomy to the post type
	add_action( 'init',
		function() use( $taxonomy_name, $post_type_name, $args )
		{
			register_taxonomy( $taxonomy_name, $post_type_name, $args );
		}
	);

When the taxonomy doesn’t exist, we only attach it to our post type. Just like before, we use a nameless function and the use() function. This time we only need to pass $taxonomy_name and $post_type_name.

	add_action( 'init',
		function() use( $taxonomy_name, $post_type_name )
		{
			register_taxonomy_for_object_type( $taxonomy_name, $post_type_name );
		}
	);

Step 4 Meta Boxes

For registering meta boxes, we need the post type name, so first we determine that. After that we need some variables for the meta box itself and we make the custom meta fields global, so we can access them in the save hook. We won’t cover too much detail here, because Tammy Hart made a very useful tutorial about reusable meta boxes already.

	public function add_meta_box( $title, $fields = array(), $context = 'normal', $priority = 'default' )
	{
		if( ! empty( $title ) )
		{
			// We need to know the Post Type name again
			$post_type_name = $this->post_type_name;

			// Meta variables
			$box_id 		= strtolower( str_replace( ' ', '_', $title ) );
			$box_title		= ucwords( str_replace( '_', ' ', $title ) );
			$box_context	= $context;
			$box_priority	= $priority;
			
			// Make the fields global
			global $custom_fields;
			$custom_fields[$title] = $fields;
			
			/* More code coming */
		}
		
	}

When we set the variables and globals, we register the meta box with an add_action. Like before, we use a nameless function. This time we need $box_id, $box_title, $post_type_name, $box_context, $box_priority and $fields.

	add_action( 'admin_init',
		function() use( $box_id, $box_title, $post_type_name, $box_context, $box_priority, $fields )
		{
			add_meta_box(
				$box_id,
				$box_title,
				function( $post, $data )
				{
					global $post;
					
					// Nonce field for some validation
					wp_nonce_field( plugin_basename( __FILE__ ), 'custom_post_type' );
					
					// Get all inputs from $data
					$custom_fields = $data['args'][0];
					
					// Get the saved values
					$meta = get_post_custom( $post->ID );
					
					// Check the array and loop through it
					if( ! empty( $custom_fields ) )
					{
						/* Loop through $custom_fields */
						foreach( $custom_fields as $label => $type )
						{
							$field_id_name 	= strtolower( str_replace( ' ', '_', $data['id'] ) ) . '_' . strtolower( str_replace( ' ', '_', $label ) );
							
							echo '<label for="' . $field_id_name . '">' . $label . '</label><input type="text" name="custom_meta[' . $field_id_name . ']" id="' . $field_id_name . '" value="' . $meta[$field_id_name][0] . '" />';
						}
					}
				
				},
				$post_type_name,
				$box_context,
				$box_priority,
				array( $fields )
			);
		}
	);

Step 5 Save the Post’s Meta Data

Save all the post’s meta data. We loop through them, using the global $custom_fields. This is also a quick coverage, see Tammy Hart’s tutorial about reusable meta boxes.

	public function save()
	{
		// Need the post type name again
		$post_type_name = $this->post_type_name;
	
		add_action( 'save_post',
			function() use( $post_type_name )
			{
				// Deny the WordPress autosave function
				if( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;

				if ( ! wp_verify_nonce( $_POST['custom_post_type'], plugin_basename(__FILE__) ) ) return;
			
				global $post;
				
				if( isset( $_POST ) && isset( $post->ID ) && get_post_type( $post->ID ) == $post_type_name )
				{
					global $custom_fields;
					
					// Loop through each meta box
					foreach( $custom_fields as $title => $fields )
					{
						// Loop through all fields
						foreach( $fields as $label => $type )
						{
							$field_id_name 	= strtolower( str_replace( ' ', '_', $title ) ) . '_' . strtolower( str_replace( ' ', '_', $label ) );
							
							update_post_meta( $post->ID, $field_id_name, $_POST['custom_meta'][$field_id_name] );
						}
					
					}
				}
			}
		);
	}

Step 6 Optimize

As you can see we use strtolower( str_replace( ' ', '_', $string ) ) and ucwords( str_replace( '_', ' ', $string ) ) a number of times. The reason of creating this class is that we don’t repeat ourselves, so we don’t want to do that in this part either. That’s why we create some helper methods. In this way we can do this: $name = self::beautify( $string ); instead of $name = strtolower( str_replace( ' ', '_', $title ) );

	public static function beautify( $string )
	{
		return ucwords( str_replace( '_', ' ', $string ) );
	}
	
	public static function uglify( $string )
	{
		return strtolower( str_replace( ' ', '_', $string ) );
	}

Another point is the plural forms we create. We just create them by adding an ‘s’ to the word. But what happens when the word ends with a ‘y’? For this reason we create a helper method to determine the plural form of a word. Now we can easily do this: $plural = self::pluralize( $string ) and the plural form of our word will be determined.

	public static function pluralize( $string )
	{
		$last = $string[strlen( $string ) - 1];
		
		if( $last == 'y' )
		{
			$cut = substr( $string, 0, -1 );
			//convert y to ies
			$plural = $cut . 'ies';
		}
		else
		{
			// just attach an s
			$plural = $string . 's';
		}
		
		return $plural;
	}

Wrap up

And now we’re done. You can now use this class to easily register post types, taxonomies and meta boxes. If you have any suggestions or questions, just leave a comment, so we can talk about it. Hope to see you next time!

Also, I would like to give some credit to Jeffrey Way. I used his class as inspiration for my class and for this tutorial. Also, I would like to give some credit to Tammy Hart, for building the reusable meta boxes tutorial. Take a look at their work.

Gijs Jorissen is Gizburdt on Codecanyon
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.wpfix.org Wpfix

    Nice tutorial

    :)

  • Soufiane

    I think there should be another version that supports older versions of PHP, this class will break the website if the host doesn’t support the latest version of PHP 5.3 !!!

    • http://www.ginius.nl Gijs Jorissen

      I will certainly have a look at it for the future.

    • http://rikdevos.com/ Rik de Vos

      +1000 This class is super awesome!! But it should really support 5.2 & 5.1 otherwise it’s just not useful :(

    • Kyle

      I agree. I have client sites hosted at all the most used Web Hosting companies, and most are not at PHP5.3 yet last time I checked.

      And without sounding negative, it’s a pretty big shortcoming in my opinion.

    • http://jeremypry.com/ JPry

      What will break exactly?

      WordPress itself requires PHP 5.2.4 or greater, as stated on their requirements page. I’ve used code very similar to this with no problems at all on the latest version of WordPress, and that’s on a server running PHP 5.2.17. So no, PHP 5.3 is not required.

      However, if your host is running some version of PHP 4, then yes you will have problems. But if it’s running PHP 4, then you’re not using the latest version of WordPress anyway, so this is already irrelevant to you. And you should actually find a new host so that you can upgrade for security reasons. :)

      • http://www.ryantanglao.com/ Ryan Tanglao

        I think it’s because the code in the article uses anonymous functions and that isn’t available until PHP 5.3.0.

  • http://www.nico-oud.nl Nico Oud

    Great tutorial, Gijs! Congrets!

  • Tanmoy

    For me, custom-post-type.php seems have some syntax error, confused.

    • http://ginius.nl Gijs Jorissen

      Which error do you get exactly?

      • Tanmoy

        Actually I opened with Dreamweaver 5 and was noticed that some syntax error was there though script was run smoothly now.

        • Rafael Ehlers

          Forget DW errors, it got lost some times, normal behavior…

  • http://jeremypry.com/ JPry

    Nice tutorial, and definitely a great start to a much-needed class. I’ve just written something similar, but it doesn’t include the meta boxes as yours does.

    Speaking of meta boxes, you should check out this class: Custom Metaboxes and Fields for WordPress. I use it frequently, and it’s very easy to use. It may be worthwhile to combine that with your class to also include custom post types and taxonomies.

  • http://ginius.nl Gijs Jorissen

    Thanks for your replies.

    @JPry: The class will need PHP 5.3, since I use nameless functions and the use() function. And thanks for the link, I will have a look at it.

    I will certainly have a look at PHP 5.1 and 5.2 compatibility and I will keep working on this class to make it more complete. You can watch it here: https://github.com/Ginius/Wordpress-Custom-Post-Type-Helper.

  • http://ddwb.me/autobahn David Decker

    Please add correct internationalization, e.g. PHP Gettext syntax to your tutorial, otherwise it might not work with non-English locales and/or confuse users.

    For example in your code in step 3 the textdomain is missing completely — it could happen that the context string is misinterpreted as textdomain, also variables in Gettext will NOT work, you have to use sprintf() wrapper for that…

    It’s frustrating to see more and more tutorials here with wrong or missing implementation of internationalization.

    -Thanks, Dave from Germany :)

  • http://cv.deminoodle.be Sam De Decker

    Really cool tut. This class is really userfull when we have a lot of custom post types.

    Appriciate it!

  • http://rawfoodisme.com Mike

    Thanks for the sharing, however as far as I am not that good with wordpress yet, my question might sound silly but what to do after the class is downloaded? It is definitely not a plugin to install/apply so how can someone nonguru like me use this?

    • Rafael Ehlers

      You can call on a Plugin (if you made one) or on your functions.php, just use the code at the beginning of the tutorial, where it says “This is how we call our class when it’s done.”

  • http://www.panofy.com André Kramer

    If you want the custom post to have a featured image, add

    ‘supports’ => array( ‘title’, ‘editor’, ‘thumbnail’ ),

    on line 68

    • http://ginius.nl Gijs Jorissen

      Hi Andre,

      It is not necessary to change to code in my class. Just provide a second parameter when you call the Class:

      $book = new Custom_Post_Type( ‘Book’,
      array( ‘supports’ => array( ‘title’, ‘editor’, ‘excerpt’ ) ),
      array( ‘plural’ => ‘Little Books’ )
      )

      For more info, you can have a look here: https://github.com/Ginius/Wordpress-Custom-Post-Type-Helper

  • Remy Martin

    I was actually in the process of adding onto Jeffrey Ways class and came across this and Tammy’s article so I went ahead and merged them together and added the wysiwyg editor for meta boxes. You can check it out here: https://github.com/rmartindotco/WordPress-Custom-Post-Helper . Thank you for this tut.

    • http://ginius.nl Gijs Jorissen

      Hi Remy,

      There are some more classes indeed, yours looks nice too! This is just a tutorial to explain the process of building a class like this.

      And because it helps me in my WordPress projects I will keep extending this Class.

  • http://ginius.nl Gijs Jorissen

    My class now also supports PHP versions lower then 5.3.

    Look here: https://github.com/Ginius/Wordpress-Cuztom-Helper

  • http://ginius.nl Gijs Jorissen

    Changed my Github account name, so I have a new URL.

    https://github.com/Gizburdt/Wordpress-Cuztom-Helper

  • http://slimmity.com Omar

    Hey Gijs great work on the class looking forward to use it, but I have a question maybe you could help me! to get an archive of a custom class you got to use domain.com/?post_type=books what if i just wanted it to be domain.com/books/ does wordpress support this or do i need a plugin/extra code to get this working? Would really appreciate the help!

    • http://lauhakari.com Lauhakari [mikko]

      You could use/add “har_archive” & “rewrite” to the supports array.
      Like:
      $book = new Custom_Post_Type( ‘Book’,
      array( ‘supports’ => array( ‘title’, ‘editor’, ‘excerpt’,’has_archive’ => true,
      ‘rewrite’ => array(‘slug’ => ‘products’) ) ),
      array( ‘plural’ => ‘Little Books’ )
      )
      Then make som nice template for them ;)
      Read more here: http://codex.wordpress.org/Function_Reference/register_post_type

      • http://lauhakari.com Lauhakari [mikko]

        Come to think of it, you shouldn’t add it to the supports array, but the args array.
        Like so:
        array( ‘supports’ => array( ‘title’, ‘editor’, ‘excerpt’),
        ’has_archive’ => true,
        ‘rewrite’ => array(‘slug’ => ‘products’) ),

  • http://lauhakari.com Lauhakari [mikko]

    Spelling error, I meant “has_archive” ofc (and “some nice template”) :D

    • http://slimmity.com Omar

      Lauhakari, yes for the individual posts i get the rewrite perfectly but when i want to list all of them that’s where I’m hitting a dead end, tried and searched for a clean answer but cant seem to find one. Back in 3.0 you had no choice but to get a plugin to list them as an archive was hopping there was a native way in 3.3

      • http://ginius.nl Gijs Jorissen

        @Omar. Maybe you can create your own query with WP_Query. If you want to insert it in the WYSIWYG editor, you can create a shortcode that calls your Query. Hope it helps…

  • Kyle

    Good stuff, although I’m having some issues with the code. Does anyone have this code completely written out in one place? The taxonomy section is giving me some trouble. Thanks

    • Kyle

      Sorry, I missed the giant “DOWNLOAD SOURCE FILES” button – got it going, kicks butt, thanks

      • http://wp.envato.com/ Japh Thomson
        Staff

        No problem, Kyle! Glad you found it :)

  • Pingback: Best of Tuts+ in April 2012 | Shadowtek Hosting and Design Solutions

  • Pingback: Best of Tuts+ in April 2012 - Milk-Break

  • Pingback: Best of Tuts+ in April 2012 | How to Web

  • Pingback: Best of Tuts+ in April 2012 « CSS Tips

  • christian

    Hi, excellent tutorial and PHP class, only a question how I can integrate this tutorial with the tutorial of the meta boxes? http://wp.tutsplus.com/tutorials/reusable-custom-meta-boxes-part-3-extra-fields/

    Thanks!

  • http://markoheijnen.com Marko Heijnen

    I was busy with building a class myself when I start searching. There are a couple of things that can be better

    - __construct()
    – If you do check if post type exists you probably also want to have the save function in it.
    – save should be the add_action in save()
    – I would create two paramters for singular and plural name. No weird code needed to make that happen then.

    - save()
    – No capability check
    – add_action can be done in __construct().
    – It also doesn’t need to use use(). You only have one post type name in that class. I’m curious why you changed it from the plugin you look at.

  • Pingback: How to Create an RSS Syndicator Site Using WordPress | Wptuts+

  • Pingback: How to Create an RSS Syndicator Site Using WordPress | Shadowtek Hosting and Design Solutions

  • Pingback: How to Create an RSS Syndicator Site Using WordPress | Wordpress Webdesigner

  • Pingback: Wordpress Leaks » How to Create an RSS Syndicator Site Using WordPress

  • Pingback: My Stream | How to Create an RSS Syndicator Site Using WordPress | My Stream

  • Pingback: How to Create an RSS Syndicator Site Using WordPress | How to Web

  • Pingback: How to Create an RSS Syndicator Site Using WordPress | Wordpress Sifter

  • http://danielhanly.com Daniel Hanly

    Is there a way to hide some default Meta Boxes?
    I’m creating a Photograph post type, and the client wont want to type in the body, just give it a title and upload the image.

    I’ve got the featured image box to display by using the ‘supports’ argument, but I would like to remove the ‘body’ box as well. Is this possible?

    • http://danielhanly.com Daniel Hanly

      Never Mind.

      It seems I aimlessly copy/pasted the ‘supports’ code without realising.

      I had: array(‘supports’ => array(‘title’, ‘editor’, ‘thumbnail’)),
      I now have: array(‘supports’ => array(‘title’, ‘thumbnail’)),

      Just removed editor and job-done

  • Juan

    Hi Guys, i am new to all of this…i was able to insert all this beautiful code into WP, created the new post type “books”, added the taxonomy, and a few meta boxes. everything is great so far… i saved the new post and it’s save but when i go to view the post i get an 404 page not found.. can someone help me out here thanks.. i am using these files https://github.com/Gizburdt/Wordpress-Cuztom-Helper

    • Juan

      LOL never mind i have a problem with the permalink… i save the Permalink Settings and it works just fine!

  • Juan

    Does any one know who to do the front page code for it..i am using this
    ID, ‘author’, true);
    echo “$author’”; ?>

    ——————————————————————————-
    here is what my custom post type code:
    $book = new Cuztom_Post_Type( ‘Book’ );

    $book->add_taxonomy( ‘Author’ );
    $book->add_meta_box(
    ‘west’,
    array(
    array(
    ‘name’ => ‘author’,
    ‘label’ => ‘author’,
    ‘description’ => ‘Just a little description’,
    ‘type’ => ‘text’
    ),
    array(
    ‘name’ => ‘Car Description’,
    ‘label’ => ‘Car_Description’,
    ‘desc’ => ‘Please enter a description for the car’,
    ‘type’ => ‘image’,
    ),
    array(
    ‘name’ => ‘test’,
    ‘label’ => ‘test’,
    ‘title’ => ‘test’,
    ‘desc’ => ‘Please enter a description for the car’,
    ‘type’ => ‘wysiwyg’,
    ),
    array(
    ‘name’ => ‘date’,
    ‘label’ => ‘date’,
    ‘desc’ => ‘Please enter a description for the car’,
    ‘type’ => ‘text’,
    )

    )
    );

    $book->add_meta_box(
    ‘Book Info’,
    array(
    ‘Year’ => ‘text’,
    ‘Genre’ => ‘text’
    )
    );

    i am just trying to display whats on the custom meta box in the front end of the site……..

  • Juan

    sorry..
    ID, ‘author’, true);
    echo “$author’”;
    ?>

  • ruben

    What a great post, came across it this weekend. It works great, but i’m running into a little problem when i try to use it on a version of wordpress multisite.

    “Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 261904 bytes) in \custom_helper\classes\cuztom.class.php on line 201 ”

    line 201 : return $this->_determine_cuztom_dir( $path );

    running this on Thesis (multisite)

  • http://www.agnelwaghela.wordpress.com/ Agnel Waghela

    Is there a way to add a custom menu icon to a post type…?

    • http://ginius.nl Gijs Jorissen

      To add a custom menu icon to a post type just do this:

      $book = new Custom_Post_Type( ‘Book’, array( ‘menu_icon’ => ‘url_to_the_icon’ ) );

      • http://www.agnelwaghela.wordpress.com/ Agnel Waghela

        Thanks a lot Gijs Jorissen…

  • http://spyropress.com SpyroPress

    Hi,

    Its a really nice add-on to be used through development but I come across a question. How can I use the same class to add new taxonomies and meta boxes to Post and Page type.

    Thanks
    -Ed

    • http://ginius.nl Gijs Jorissen

      Hi SpyroPress,

      This can be done by directly calling the Cuztom_Taxonomy class, like so.

      $taxonomy = new Cuztom_Taxonomy( ‘Author’, ‘name_of_the_post_type’ ) )

      Note that you need my newest Cuztom Helper class, you can find it here: https://github.com/Gizburdt/Wordpress-Cuztom-Helper

      Hope this will, otherwise please let me know.

  • Anon

    I’ve got the script working, it’s great so thanks!

    Just one question, how would I add something other than a custom text field?

    Could somebody write a brief example to add say a predefined dropdown list or a checkbox? I’ve Googled but I can’t find anything particularly helpful :/

    Thanks!

    • http://ginius.nl Gijs Jorissen

      Hi Anon.

      Good to hear you like it. To add a dropdown, you need this:

      $book->add_meta_box(
      ‘Book Info’,
      array(
      array(
      ‘name’ => ‘author’,
      ‘label’ => ‘Author’,
      ‘description’ => ‘Just a little description’,
      ‘type’ => ‘select’,
      ‘options’ => array( ‘slug’ => ‘name’, ‘slug’ => ‘name’ )
      )
      )
      );

      If you want some checkboxes, just replace ‘type’ => ‘select’ with ‘type’ => ‘checkboxes’.

      Note: You need to set $book before you call this piece of code, like so:
      $book = new Cuztom_Post_Type(‘Book’);

      For more help, just go to this link: https://github.com/Gizburdt/Wordpress-Cuztom-Helper.
      You can check the wiki and get to latest version of my helper class.

      Hope this will help, otherwise please let me know.

      Gijs

  • http://www.gradientgraphics.net Wes

    Thank you the write up and the great helper class. I would like to implement this on a project that I have already defined custom post types for. Is there a way to add custom meta boxes to custom post types that already exist?

    I attempted to use the:
    $box = add_cuztom_meta_box(
    ‘Book Info’,
    ‘book’,
    array(
    ‘name’ => ‘author’,
    ‘label’ => ‘Author’,
    ‘description’ => ‘Just a little description’,
    ‘type’ => ‘text’
    )
    )

    The meta box shows up on the custom post type page, however the box is filled with the following errors:
    Notice: Undefined offset: 0 in /home/saaladv/public_html/lt/wp-content/themes/ltrealty/_/functions/cp-helper/classes/meta_box.class.php on line 100

    Notice: Undefined offset: 0 in /home/saaladv/public_html/lt/wp-content/themes/ltrealty/_/functions/cp-helper/classes/meta_box.class.php on line 100

    Notice: Undefined offset: 0 in /home/saaladv/public_html/lt/wp-content/themes/ltrealty/_/functions/cp-helper/classes/meta_box.class.php on line 100

    a Unknown input type

    A Unknown input type

    J Unknown input type

    t Unknown input type

    So not really sure what I’m missing…thank you in advance for any assistance and keep up the good work!

    • http://ginius.nl Gijs Jorissen

      Hi Wes,

      It is possible, but there is a small mistake in your code. The third parameter is an array of fields. Each field is an array too. So instead of setting one array, you need to set two, like so:

      array(
      array(
      ‘name’ => ‘author’,
      ‘label’ => ‘Author’,
      ‘description’ => ‘Just a little description’,
      ‘type’ => ‘text’
      )
      )

      If you want more fields, just add a new array to the parent array.
      Hope it helps, otherwise please let me know.

  • http://ginius.nl Gijs Jorissen

    To everyone else, if you have questions about the class and not about the tutorial, please ask them here: https://github.com/Gizburdt/Wordpress-Cuztom-Helper. The class on Github is in a further state. Thanks though, for all the questions and feedback! Keep them coming!

  • Arnaud

    The php 5.2 compatible version :

    <?php
    
    class Custom_Post_Type
    {
    	public $post_type_name;
    	public $post_type_args;
    	public $post_type_labels;
    	public $post_type_taxos;
    	public $post_type_taxos_exits;
    	public $post_type_meta_boxes;
    	
    	/* Class constructor */
    	public function __construct($name, $args = array(),$labels = array())
    	{
    		// Set some important variables self::beautify( $string )
    		$this->post_type_name 		= self::uglify($name);
    		$this->post_type_args 		= $args;
    		$this->post_type_labels 	= $labels;
    		$this->post_type_taxos		= array();
    		$this->post_type_taxos_exits= array();
    		$this->post_type_meta_boxes = array();
    	
    		// Add action to register the post type, if the post type does not already exist
    		if(! post_type_exists($this->post_type_name))
    		{
    			add_action('init',array(&$this,'register_post_type'));
    			add_action('init',array(&$this,'push_taxonomy'));
    			add_action('admin_init',array(&$this,'push_meta_box'));
    		}
    		// only for 5.3
    		//$this->save();
    		add_action('save_post',array(&$this,'save_data'));
    	}
    	
    	/* Method which registers the post type */
    	public function register_post_type()
    	{
    		// Capitilize the words and make it plural
    		$name 	= self::beautify($this->post_type_name);
    		$plural = $name.'s';
    		
    		// We set the default labels based on the post type name and plural. We overwrite them with the given labels.
    		$labels = array_merge(
    			//Default
    			array(
    				'name' 				=> _x($plural,'post type general name'),
    				'singular'			=> _x($name,'post type singular name'),
    				'add_new'			=> _x('Add New',strtolower($name)),
    				'add_new_item'		=> __('Add New '.$name),
    				'edit_item'			=> __('Edit '.$name),
    				'new_item'			=> __('New '.$name),
    				'all_items'			=> __('All '.$plural),
    				'view_item'			=> __('View '.$name),
    				'search_items'		=> __('Search '.$plural),
    				'not_found'			=> __('No '.strtolower($plural).' found'),
    				'not_found_in_trash'=> __('No '.strtolower($plural).' found in Trash'),
    				'parent_item_colon' => '',
    				'menu_name'			=> $plural
    			),
    			// Given labels
    			$this->post_type_labels
    		);
    		
    		// Same principle as the labels. We set some defaults and overwrite them with the given arguments.
    		$args = array_merge(
    			// Default
    			array(
    				'label'				=> $plural,
    				'labels'			=> $labels,
    				'public'			=> true,
    				'show_ui'			=> true,
    				'supports'			=> array('title','editor'),
    				'show_in_nav_menus'	=> true,
    				'_builtin'			=> false
    			),
    			// Given args
    			$this->post_type_args
    		);
    		
    		// Register the post type 
    		register_post_type($this->post_type_name,$args);
    	}
    	
    	/* Method to attach the taxonomy to the post type */
    	public function add_taxonomy($name,$args = array(),$labels = array())
    	{
    		if(! empty($name))
    		{
    			// We need to know the post type name, so the new taxonomy can be attached to it.
    			$post_type_name = $this->post_type_name;
    			
    			// Taxonomy properties
    			$taxonomy_name		= self::uglify($name);
    			$taxonomy_labels	= $labels;
    			$taxonomy_args		= $args;
    			
    			if(! taxonomy_exists($taxonomy_name))
    			{
    				/* Create taxonomy and attach to the post type */
    				$name 	= self::beautify($name);
    				$plural	= $name.'s';
    				
    				// Default labels, overwrite them with the given labels.
    				$labels = array_merge(
    					//Default
    					array(
    						'name'				=> _x($plural, 'taxonomy general name'),
    						'singular_name'		=> _x($name,'taxonomy singular name'),
    						'search_items'		=> __('Search '.$plural),
    						'all_items'			=> __('All '.$plural),
    						'parent_item'		=> __('Parent '.$name),
    						'parent_item_colon'	=> __('Parent '.$name.':'),
    						'edit_item'			=> __('Edit '.$name),
    						'update_item'		=> __('Update '.$name),
    						'add_new_item'		=> __('Add New '.$name),
    						'new_item_name'		=> __('New '.$name.' Name'),
    						'menu_name'			=> __($name)
    					),
    					$taxonomy_labels
    				);
    				
    				// Default arguments, overwritten with the given arguments
    				$args = array_merge(
    					// Default
    					array(
    						'label'				=> $plural,
    						'labels'			=> $labels,
    						'public'			=> true,
    						'show_ui'			=> true,
    						'show_in_nav_menus'	=> true,
    						'_builtin'			=> false
    					),
    					// Given
    					$taxonomy_args
    				);
    				
    				/* only 5.3
    				// Add the taxonomy to the post type
    				add_action('init',
    					function() use($taxonomy_name,$post_type_name,$args)
    					{
    						register_taxonomy($taxonomy_name,$post_type_name,$args);
    					}
    				);
    				*/
    				
    				$temp = array(
    					'name' 			=> $taxonomy_name,
    					'object_type'	=> $post_type_name,
    					'args' 			=> $args
    				);
    				array_push($this->post_type_taxos,$temp);
    			
    			}else{
    				/* the taxo already exists. but attach to the post type */
    				/* only 5.3
    				add_action('init',
    					function() use($taxonomy_name,$post_type_name)
    					{
    						register_taxonomy_for_object_type($taxonomy_name,$post_type_name);
    					}
    				);
    				*/
    				
    				$temp = array(
    					'name' 			=> $taxonomy_name,
    					'object_type'	=> $post_type_name
    				);
    				array_push($this->post_type_taxos_exits,$temp);
    			}
    		}
    	}
    	
    	/* only for under php 5.3 */
    	public function push_taxonomy()
    	{
    		if(NULL != $this->post_type_taxos)
    		{
    			foreach($this->post_type_taxos as $taxo)
    			{
    				register_taxonomy($taxo['name'],$taxo['object_type'],$taxo['args']);
    			}
    		}
    	
    		if(NULL != $this->post_type_taxos_exits)
    		{
    			foreach($this->post_type_taxos_exits as $taxo)
    			{
    				register_taxonomy_for_object_type($taxo['name'],$taxo['object_type']);
    			}		
    		}
    	}
    	
    	/* Attaches meta boxes to the post type */
    	public function add_meta_box($title,$fields = array(),$context='normal',$priority = 'default')
    	{
    		if(!empty($title))
    		{
    			$temp = array(
    				'title'		=> $title,
    				'box_id'	=> self::uglify($title),
    				'box_title'	=> self::beautify($title),
    				'context'	=> $context,
    				'priority'	=> $priority,
    				'fields'	=> $fields
    			);
    			array_push($this->post_type_meta_boxes,$temp);
    			
    			/*
    			// We need to know the Post Type name again
    			$post_type_name = $this->post_type_name;
    			
    			//Meta variables
    			$box_id			= self::uglify($title);
    			$box_title		= self::beautify($title);
    			$box_context	= $context;
    			$box_priority 	= $priority;
    			
    			// Make the fields global
    			global $custom_fields;
    			$custom_fields[$title] = $fields;
    			
    			add_action('admin_init',
    				function() use($box_id,$box_title,$post_type_name,$box_context,$box_priority,$fields)
    				{
    					add_meta_box(
    						$box_id,
    						$box_title,
    						function ($post,$data)
    						{
    							global $post;
    							
    							// Nonce field for some validation
    							wp_nonce_field(plugin_basename(__FILE__),'custom_post_type');
    							
    							// Get all inputs from $data
    							$custom_fields = $data['args'][0];
    							
    							// Get the saved values
    							$meta = get_post_custom($post->ID);
    							
    							// Check the array and loop through it
    							if(! empty($custom_fields))
    							{
    								// Loop through $custom_fields
    								foreach($custom_fields as $label => $type)
    								{
    									$field_id_name = strtolower(str_replace(' ','_',$data['id'])).'_'.strtolower(str_replace(' ','_',$label));
    									echo'<label for="'.$field_id_name.'">'.$label.'</label> <input type="text" name="custom_meta['.$field_id_name.']" id="'.$field_id_name.'" value="'.$meta[$field_id_name][0].'" />';
    								}
    							}
    						},
    						$post_type_name,
    						$box_context,
    						$box_priority,
    						array($fields)
    					);
    				}
    			);
    			*/
    		}
    	}
    	
    	public function push_meta_box()
    	{
    		if(NULL != $this->post_type_meta_boxes)
    		{
    			// Make the fields global
    			global $custom_fields;
    			$post_type_name = $this->post_type_name;
    		
    			foreach($this->post_type_meta_boxes as $meta_box)
    			{
    				
    				$title 	= $meta_box['title'];
    				$fields	= $meta_box['fields'];
    				$custom_fields[$title] = $fields;
    				
    				add_meta_box(
    					$meta_box['box_id'],
    					$meta_box['box_title'],
    					array(&$this,'callback_metabox'),
    					$post_type_name,
    					$meta_box['context'],
    					$meta_box['priority'],
    					array($fields)
    				);
    			}
    		}
    	}
    	
    	public function callback_metabox($post,$metabox)
    	{
    		global $post;		
    		// Nonce field for some validation
    		wp_nonce_field(plugin_basename(__FILE__),'custom_post_type');
    				
    		// Get all inputs from $data
    		$custom_fields = $metabox['args'][0];
    				
    		// Get the saved values
    		$meta = get_post_custom($post->ID);
    				
    		// Check the array and loop through it
    		if(! empty($custom_fields))
    		{
    			// Loop through $custom_fields
    			foreach($custom_fields as $label => $type)
    			{
    				$field_id_name = self::uglify($metabox['id']).'_'.self::uglify($label);
    				echo'<label for="'.$field_id_name.'" style="min-width:80px;display:inline-block;padding:7px 0px;">'.$label.'</label>
    				<input type="text" name="custom_meta['.$field_id_name.']" id="'.$field_id_name.'" value="'.$meta[$field_id_name][0].'" /><br>';
    			}
    		}
    	}
    	
    	/* Listens for when the post type being saved */
    	/*
    	public function save()
    	{
    		// Need the post type name again
    		$post_type_name = $this->post_type_name;
    		
    		add_action('save_post',
    			function() use($post_type_name)
    			{
    				// Deny the WordPress autosave function
    				if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    				
    				if(! wp_verify_nonce($_POST['custom_post_type'], plugin_basename(__FILE__))) return;
    				
    				global $post;
    				if(isset($_POST) && isset($post->ID) && get_post_type($post->ID) == $post_type_name)
    				{
    					global $custom_fields;
    					
    					// Loop through each meta box
    					foreach($custom_fields as $title => $fields)
    					{
    						// Loop through all fields
    						foreach($fields as $label => $type)
    						{
    							$field_id_name = self::uglify($title).'_'.self::uglify($label);
    							update_post_meta($post->ID,$field_id_name,$_POST['custom_meta'][$field_id_name]);
    						}
    					}
    				}
    			}
    		);
    	}
    	*/
    	
    	public function save_data()
    	{
    		// Deny the WordPress autosave function
    		if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    				
    		if(! wp_verify_nonce($_POST['custom_post_type'], plugin_basename(__FILE__))) return;
    				
    		global $post;
    		if(isset($_POST) && isset($post->ID) && get_post_type($post->ID) == $this->post_type_name)
    		{
    			global $custom_fields;
    					
    			// Loop through each meta box
    			foreach($custom_fields as $title => $fields)
    			{
    				// Loop through all fields
    				foreach($fields as $label => $type)
    				{
    					$field_id_name = self::uglify($title).'_'.self::uglify($label);
    					update_post_meta($post->ID,$field_id_name,$_POST['custom_meta'][$field_id_name]);
    				}
    			}
    		}
    	}
    	
    	public static function beautify($string)
    	{
    		return ucwords(str_replace('_',' ',$string));
    	}
    	public static function uglify($string)
    	{
    		return strtolower(str_replace(' ','_',$string));
    	}
    }
    
    • http://gijsjorissen.nl Gijs Jorissen

      The PHP 5.2 compatible version can be found on Github, with more updates in it!

      https://github.com/Gizburdt/Wordpress-Cuztom-Helper

      • http://igorchudy.pl Igor

        Gijs – I download Your version from Github and it’s awesome :)
        But I’ve found one problem. When I try get select / checkboxes group or radio group I get this message:

        “Warning: ucwords() expects parameter 1 to be string, array given in C:\xampp\htdocs\wp_dev\wp-content\themes\szablon_wp\includes\cuztom_helper\classes\cuztom.class.php on line 149″

        It WP install on localhost, xammp server on PHP: 5.3.8.

  • wael

    thanks!

    the box of portfolio thumbnail not visible with me!!!!

    plz help

  • Brendan

    I’m trying to have a switch in the meta boxes, to allow for checkboxes (and eventually uploaded images).

    So in the add_meta_box function’s for each loop, I’m trying this, but it doesn’t work – I think because I don’t know what to switch. Any help appreciated

    switch ($field_id_name['type']) { //this line must be wrong!

    //If Text
    case ‘text’:
    echo ” . $label . ”;

    //If checkbox
    case ‘checkbox’:
    echo ”;

    • http://ginius.nl Gijs Jorissen

      I think it’s just:

      switch( $type )

      But I don’t know for sure, because my recent ocde is much more complex then this one. That thing you are trying to build is supported in my recent code. Just have a look here: https://github.com/Gizburdt/Wordpress-Cuztom-Helper

  • http://igorchudy.pl Igor

    Great job!
    For that moment I write every line of my CPT form hand, but know – few lines of code and voila!

    Excellent!

  • http://cmsdeployed.com Toure

    OK, this is all good, but I cannot seem to find how to display any of these in/outside the loop on the front end. Any help will be appreciated.

    • http://ginius.nl Gijs Jorissen

      The meta_key is the name of the meta box + the name of the field.

      So if you have a meta box called Extra Information and a field within that meta box called Something, then the meta_key is _extra_information_something. Don’t forget the _ at the start!

      You can always check your database for the name (wp_postmeta table)

      Hope it helps, otherwise please let me know.

      You can always check my Github page: https://github.com/Gizburdt/Wordpress-Cuztom-Helper

  • phpcore

    This comment is about “Cuztom-Helper” class:
    Developper said that is compatible with older php version, so on my server I have PHP 5.2.7 and it’s prints errors :

    syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM (file : ./functions/field.php)

    so in order to let it work, we must change this 2 lines of code:

    1) return $field::_supports_repeatable();
    2) return $field::_supports_bundle();

    IN :

    1) call_user_func(array($field, ‘_supports_repeatable’));
    2) call_user_func(array($field, ‘_supports_bundle’));

    see refernce : http://php.net/manual/fr/function.call-user-func.php

  • http://gizburdt.com Gijs Jorissen

    Hi,

    This is fixed in the newest version…
    I changed this:

    return $field::_supports_repeatable();

    to this:

    return $field->_supports_repeatable();

    Thanks for your comment

  • http://studio.quintalinda.com/ Websites Made Easy

    Great class – perfect to tidy up my code base – however, when added a new CPT with taxonomy, the taxonomy seems to always come out tag-like, not hierarchical like categories – any chance of offering some suggestions about how the class could be extended to allow for a second option like:

    $tree->add_taxonomy( ‘tree_category’, ‘category’ );

    to be passed to the class object?

    Thanks!

    Ray

  • http://studio.quintalinda.com/ Websites Made Easy

    got it:

    $tree_tag_args = array (

    ‘rewrite’ => array( “slug” => “tree/tag” ),

    ‘hierarchical’ => false,

    );

    $tree->add_taxonomy( ‘tree_tag’, $tree_tag_args ); // add tree_tag taxonomy ##

    nice one!

  • Pingback: Wordpress Plugin Development Primer | Polytechnic?

  • http://twitter.com/ohead_id Daeho Jeong

    public function add_taxonomy( $name, $args = array(), $labels = array() )
    {

    …..

    // Add the taxonomy to the post type

    add_action( ‘init’,

    function() use( $taxonomy_name, $post_type_name, $args )

    {

    if( ! taxonomy_exists( $taxonomy_name ) )

    {

    register_taxonomy( $taxonomy_name, $post_type_name, $args );

    }

    else

    {

    register_taxonomy_for_object_type( $taxonomy_name, $post_type_name );

    }

    }

    );

    ….

    }