Adding a Custom Post Type with Custom Meta Box in WordPress
I’m not going to cover how to add a custom post type & a meta box specifically for Nivo Slider. Instead I’m going to show you how to do it in general with hints and tips on how it could be used with Nivo Slider. That way this tutorial is much more useful to everyone, not just those looking to use it with Nivo Slider.
If you are wanting to use Nivo Slider with this tutorial I’ve already covered how to add Nivo Slider into your theme in a previous tutorial. I will not be looking at custom Taxonomies since there is no need for one in this tutorial.
All of this code must be placed in your functions.php file. If you do not have one in your theme, just create a file with that name & you are ready to go. All of these code snippets are PHP so do not forget your opening & closing PHP tags.
Setting Up a Custom Post Type
First let’s set up our post type. I am going to call it ‘Slides’. This part is generally just copy & paste, but it does help if you understand the code a little.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
add_action('init', 'add_slides_type'); function add_slides_type() { $labels = array( 'name' => _x('Slides', 'post type general name'), 'singular_name' => _x('Slide', 'post type singular name'), 'add_new' => _x('Add New', 'Post'), 'add_new_item' => __('Add New Slide'), 'edit_item' => __('Edit Slide'), 'new_item' => __('New Slide'), 'view_item' => __('View Slide'), 'search_items' => __('Search Slides'), 'not_found' => __('No Slides found'), 'not_found_in_trash' => __('No Slides found in Trash'), 'parent_item_colon' => '' ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'query_var' => true, 'rewrite' => true, 'capability_type' => 'post', 'hierarchical' => false, 'menu_position' => 5, 'supports' => array('title','editor','author','thumbnail','excerpt','comments','custom-fields','post-formats'), 'has_archive' => true ); register_post_type('slides',$args); } |
First thing we do here is add an action to run our custom post type function on initialization of WordPress. Next we create the function I just mentioned. The function is made up of three things:
First is an array of labels which you will need to customize with the name you have chosen to give your post type, this should just require a basic knowledge of grammar/languages but you can find an explanation of the labels on the WordPress Codex page for Register Post Type.
Second is an array of arguments. These are also listed on the WordPress Codex page for Register Post Type but this list provided here is generally how you would want them set up provided you don’t need a taxonomy.
Third is the actual call to Register Post Type. All we are doing is giving a unique name for the post type and the array of arguments. Please note that the unique name cannot be more than 20 characters or contain any spaces or capital letters. I’m not sure about special characters although I would assume they cannot be used either.
That should give you your custom post type in your admin menu as shown below.
N.B. There is one very important thing you must do after you have created your custom post type. You must visit ‘Settings -> Permalinks’ in your WordPress Admin and hit save. You don’t have the change anything, just hit the save button. This is to refresh your Rewrite Rules or you may have problems accessing your new post type.
Next up we need to create our Meta Box. This is actually the most difficult part of this tutorial & can take a little while to get right.
Creating The Meta Box
The code is quite large so let’s get started. I’m going to go through it in sections, but don’t worry if you want to copy & paste I’ll put the entire code at the end.
1 2 |
add_action( 'add_meta_boxes', 'nivo_add_custom_box' ); add_action( 'save_post', 'nivo_save_postdata' ); |
First we set up our two actions. The first adds the meta box (WP 3.0+ only) and the second adds a function to the post being saved so we can actually save the data for later use.
1 2 3 4 5 6 7 8 |
function nivo_add_custom_box() { add_meta_box( 'nivo_options', 'Slide Options', 'nivo_inner_custom_box', 'slides' ); } |
This adds our meta box and also triggers a function to produce the form inside the meta box. The first parameter is a unique name for our meta box, the second a nice name to place in the meta boxes header, the third is the name of the function I mentioned, and finally the slug of the post type you want to attach it to (post, page, custom post type slug).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
function nivo_inner_custom_box( $post ) { // Use nonce for verification wp_nonce_field( plugin_basename( __FILE__ ), 'nivo_noncename' ); $mydata = get_post_meta($post->ID, 'nivo_slider', TRUE); // The actual fields for data entry echo '<label for="nivo_imageurl">'; echo 'URL to image for slide:'; echo '</label> '; echo '<input type="text" id="nivo_imageurl" name="nivo_imageurl" value="'.$mydata['nivo_imageurl'].'" size="25" />'; echo '<label for="nivo_caption">'; echo 'URL to image for slide:'; echo '</label> '; echo '<input type="text" id="nivo_caption" name="nivo_caption" value="'.$mydata['nivo_caption'].'" size="25" />'; //Add more fields as you need them... } |
This function, which is called from add_meta_box
via a callback, actually creates the form for you to enter information into. This is all very basic HTML and I am not going to cover it in detail as you may want different fields etc. The ones shown here should be enough to get you started though. The wp_nonce_field
function produces a special field that has a one use security code inside, this is used to validate the information when it is saved.
The get_post_meta
allows us to grab the information from the database to place back into the field when editing. It makes it a lot easier to use & look a lot better too. The array key to use will always be the same as the input’s name attribute.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
function nivo_save_postdata( $post_id ) { if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( !wp_verify_nonce( $_POST['nivo_noncename'], plugin_basename( __FILE__ ) ) ) return; if ( !current_user_can( 'edit_post', $post_id ) ) return; $mydata = array(); foreach($_POST as $key => $data) { if($key == 'nivo_noncename') continue; if(preg_match('/^nivo/i', $key)) { $mydata[$key] = $data; } } update_post_meta($post_id, 'nivo_slider', $mydata); return $mydata; } |
This final function saves the data in the meta box when the post is saved. It first checks to see if WordPress is performing an autosave, we don’t want to save our data yet if that is the case. We then check that the one use code is present & still valid. Then we check to see if the user has post editing privledges.
The final part goes through the global post data array and finds all the entries from the submitted meta box pertaining to nivo slider using a preg_match
pattern to check the array keys. You can change it to anything you like as long as the field names from the form all have the prefix in common & it is a word/name unlikely to be used by WordPress itself. Inside the preg_match
is fairly simple, the forward slashes (/) are just delimiters to contain the pattern we want to match, the caret (^) means starts with, and the letter (i) just means case insensitive. If it’s a match we add it to an array. After that is complete we take the data and give it to update_post_meta
which serializes it and places it neatly in the database.
Here is all the code together just in case you need/want to copy & paste it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
add_action( 'add_meta_boxes', 'nivo_add_custom_box' ); add_action( 'save_post', 'nivo_save_postdata' ); function nivo_add_custom_box() { add_meta_box( 'nivo_options', 'Slide Options', 'nivo_inner_custom_box', 'slides' ); } function nivo_inner_custom_box( $post ) { // Use nonce for verification wp_nonce_field( plugin_basename( __FILE__ ), 'nivo_noncename' ); $mydata = get_post_meta($post->ID, 'nivo_slider', TRUE); // The actual fields for data entry echo '<label for="nivo_imageurl">'; echo 'URL to image for slide:'; echo '</label> '; echo '<input type="text" id="nivo_imageurl" name="nivo_imageurl" value="'.$mydata['nivo_imageurl'].'" size="25" />'; echo '<label for="nivo_caption">'; echo 'URL to image for slide:'; echo '</label> '; echo '<input type="text" id="nivo_caption" name="nivo_caption" value="'.$mydata['nivo_caption'].'" size="25" />'; //Add more fields as you need them... } function nivo_save_postdata( $post_id ) { if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( !wp_verify_nonce( $_POST['nivo_noncename'], plugin_basename( __FILE__ ) ) ) return; if ( !current_user_can( 'edit_post', $post_id ) ) return; $mydata = array(); foreach($_POST as $key => $data) { if($key == 'nivo_noncename') continue; if(preg_match('/^nivo/i', $key)) { $mydata[$key] = $data; } } update_post_meta($post_id, 'nivo_slider', $mydata); return $mydata; } |
How Do I Enter Data?
Just like you would a custom field. You should see your new meta box on the add new/edit page for your custom post type just like this.
Just enter the text you want & hit the update/publish button as normal to save it.
How Do I Use The Data?
Using the data is as simple as if you had just used a custom field. In our case it is a little different because the data was stored as a serialized array. To access the data you will need to do something like this before you need access to any of it:
1 |
$nivodata = get_post_meta($post->ID, 'nivo_slider', TRUE); |
This will store the array into a variable. Then all you need to do is access it as a normal array, like this:
1 |
echo $nivodata['nivo_imageurl']; |
Again the field names you used in the meta boxes form will be used to access the data so the easier you make them to remember the easier it will be to write the code.
Like I said this tutorial is aimed at anyone wanting to create a custom post type or custom meta box. However if you want to add custom captions you will need to visit the Nivo Slider Custom Captions tutorial and follow the section for Custom Fields. The exception is that the variable $caption
would end up an array and would need to change to $caption['blah_blahblah']
where ‘blah_blahblah’ is the field name you used to contain your caption inside your custom meta box.
Hopefully this tutorial has helped show how to add a custom post type with a custom meta box. I didn’t want it to become Nivo Slider specific as it is useful to so many other people too. If you are using this tutorial for Nivo and you are stuck with anything please leave a comment & I’ll help you out. I will be making another tutorial in the next few days to extend this one detailing how to use the post meta data with Nivo Slider as it is worthy of it’s own tutorial, until then please use this one to make your post type & meta box as I won’t be repeating it in that new tutorial.
37 Comments
Jamie
Great article. I have always had problems with custom post types. I can make them but then when I go to click on the page, they never show. I think it has something to do with the permalinks setup you are using.
Paul Robinson
Hi Jamie,
That’s actually one thing you’ve reminded me of that I must add into this tutorial. Thank you.
When creating a Custom Post Type you must refresh your Rewrite Rules by visiting the ‘permalink’ settings page in your WordPress Admin & just hitting the save button.
kathy
hi paul, have i told you about WP_Alchemy? it is what I use to create all my metaboxes b/c it lets me focus on creating the data and using the data while someone else handles the saving of the data. it also has some really cool methods built in like the ability for the user to loop and add as as many inputs as you’d like. i actually use exactly that for my Nivo slider backend UI. if you haven’t you should check it out:
farinspace.com/wpalchemy-metabox/
i use it on almost every project i do these days.
Paul Robinson
Nope I didn’t know about WP_Alchemy. Looks like an awesome tool though.
I would normally use something like that, but someone asked how to do it from scratch so I thought I’d better show how to do it the old fashioned way, lol.
I know you are very busy, but would you be willing to make a post on how you used WP_Alchemy to create your Nivo Slider UI? Or maybe just a how to tutorial on the basics of WP_Alchemy?
Drop me an email via the contact page if you are interested and I’ll set you up an account here.
dan
i too would love a tutorial on alchemy,i was aware of it but metaboxes are a little grey area for me,is it possible to do a shortcode generator in it? for example;
i select a shortcode button from a dropdown of shortcodes,this then reveals further attributes like; url,button size,button colour etc etc,then a submit button to send to text editor(either visual or html)
🙂 😉
Paul Robinson
I’m afraid I have no idea on that one Dan, I’m hoping that Kathy might be able to find some time to write a tutorial on Alchemy for us.
If she isn’t able to write one, I’ll see what I can do but as I’ve never used it before it might take a little time as I have to learn how to use it.
Randy
I usually don’t even need to “save” the permalink page. Just visit it.
There is one extra step with using ‘supports’ => ‘thumbnail’. You need to manually add the new post type to the add_theme_support() array or it won’t show up.
Randy
I also must add that after I upgraded to WP 3.2 I noticed they changed the link names to “All Posts”, “All Pages” etc. I dug into the core files and saw this is done with the (new?) label ‘all_items’.
Nice article! Thanks!
Paul Robinson
That’s for adding all that Randy.
I’ve always wondered that about the thumbnail support. If you use:
does it enable support for all post types (including pages) or just posts? Or am I required to name them all using:
It doesn’t really give a clear indication in the codex as it just says use the standard function to enable support for it, not whether or not it only adds thumbnail support to normal posts.
Randy
After testing, I see that if you have anything in the array (ie: if you wanted to only allow thumbnails for Posts and not Pages) then you also need to specify the custom post type within that array. However, you can just have ‘post_thumbnails’ and it will cover all post types in the entire theme.
That will save me a step! Thanks for pointing it out. I was always forgetting to edit my functions file to include the new post type. Now I will just enable thumbnails for the whole theme!
Paul Robinson
Yeah, just checked that out myself. I never took much notice of the fact that just using
add_theme_support()
enabled thumbnail support for all post types.Glad it does, makes it a lot easier. 😉
stvwlf
Hi – Thank you for this tutorial. You came close to explaining something I’ve been trying to figure out. In nivo_save_postdata you show how to perform some validation checking on the data that was entered. How do you stop WordPress from updating the post if the metabox data fails validation, and how do you display a relevant error message to the user?
thank you
Paul Robinson
Hi Stvwlf,
The only way I know of adding a error message is using the
admin_notice
hook. There is a bit on Stack Exchange on how it can be done, but it uses transients to do it so some people aren’t comfortable using them.Just in case you don’t know, transients are like options. They are items stored in WP’s database, but they are only kept for so long and then auto deleted by the WP CRON worker.
stvwlf
Thank you Paul.
I’ve been trying to implement this one http://wordpress.stackexchange.com/questions/15546/dont-publish-custom-post-type-post-if-a-meta-data-field-isnt-valid/15582#15582 which I’ve got partially working. It sets the post status to Pending when entries are invalid and then displays the message. The code posted is incomplete and I don’t quite understand the location redirect at the end that’s to display the error message.
I’ll look into the one you linked to. I know what transients are though haven’t worked with them much. It seems pretty convoluted that all of this is needed to display a simple error message, especially since its been made pretty simple to display a custom meta box. However, whatever works.
thank you, I appreciate your help
Paul Robinson
It looks like the guy in that post had another hook that took a number as a value to show a specific custom error message.
Since he didn’t post it I don’t know what hook he used, but it may have been the admin notice hook. He probably just checked the $_GET super global for the value 4 & showed a specific message.
It is quite annoying that it isn’t very simple to show a custom message for meta box/custom field errors.
Alessio
What does this mean?
preg_match(‘/^nivo/i’
Paul Robinson
Hi Alessio,
It checks for the word ‘nivo’ at the start of any of the keys of the
$_POST
data. It’s so if any other data is sent in the post super global we don’t accidentally save it with our data.Alessio
One little thing, I cannot save a custom field set by a .
It saves me the first option ever, some advice?
Alessio
.. set by a select/option form field, not a simple input… 🙁
Paul Robinson
I’m not sure I understand? A select/option field is just like a text input in that is will only return the value selected, unless it is a multi-select.
Alessio
Probably I don’t understand what I’ve to write in the “value” attribute of each option, sorry I’m just a designer not a programmer 🙂
Paul Robinson
The value would be exactly that. What value you would like passed to the code & saved into the database should that option be selected.
Alessio
it save me everytime the first OPTION, if I selected the 2nd or the 3rd, when I save the post wp ignore my selection and set everytime only the 1st OPTION of the SELECT field.
Probably i’m doing something wrong, or probably the UPDATE_POST_META need some modifications?
I really appreciate your help, thannks… Your code work really fine with the rest 🙂
Paul Robinson
Hmm. That’s very odd. Could you post your HTML code, specifically the Select & Options tags into a pastebin (at pastebin.com) and post the link & I’ll take a look.
Alessio
Here is my code pastebin.com/HtNvasXq
All the best!
Paul Robinson
Hi Alessio,
I honestly have no idea as looking at your code it should work fine. I’ve just been working with a select/option field recently & when you save it should send the key as the name of the select input & the value as the selected value. What happens if you try to view the entire contents of the
$_POST
superglobal by usingprint_r($_POST);
?Alessio
no ok i’m sorry, WP save correctly the custom field but in the Write section of WP-Admin it shows everytime the first value of the select. Probably a little fix for a correct visualization will be great, anyway your code works great 🙂 🙂 🙂 🙂 🙂
Paul Robinson
Ahhh, I get you.
It’s because the select requires a different way of pre selecting the value. You have to do something like this:
Obviously you remove the
rinse & repeat
and replace it with the rest of your options.Alessio
Like this?
Paul Robinson
Yep, you just need to repeat your option tag (with the PHP code) for each option you have.
Alessio
I know I’m becoming boring, by the way it doesn’t work for me… sorry for the waste of time, I think I’ll may find another way to do this 🙁
Paul Robinson
Wait a second, I’ve just noticed I missed a little bit out. Sorry about that. It should be:
You need to change
'Aburuzzo'
for the value of each option field as you do each one.Ignacio
Hi Paul, I’ve a problem with custom fields.
When I use the in my loop it gives me the value with extra numbers and letters. For example:
I enter the number “600” in the admin area and in the loop I see:
a:1:{s:15:”prop_superficie”;s:3:”600″;}
I checked the DB and the value saved is a:1:{s:15:”prop_superficie”;s:3:”600″;} NOT 600.
It looks ok in the admin area. I just can’t figure it out, could someone help me?
Paul Robinson
Hi Ignacio,
the information you are seeing is a serialized array. It is how you store array data in text format so it can be restored to array format later for use in your applications.
WordPress’ normal
get_post_meta()
function should unserialize any data as it is returned. I’m not sure why it isn’t. If that does keep happening try running it throughunserialize()
after grabbing the data viaget_post_meta()
.Ignacio
Paul thanks for you quick answer!
How should I write the
unserialize()
andthe_meta()
functions on my loop? : /I tryed using the same code you wrote but the problem is the same.
Thanks again!
Paul Robinson
That’s odd.
get_post_meta()
should unserialize array data automatically. It seems to be serializing automatically. The code would probably be something like:Again it should already be unserialized, but that should do it if it hasn’t been.