How to Create a Custom Post Type with Image Uploads For WordPress 3
I’ve been working on a project to create a CMS for a series of dental websites. One of the important things is to be able to make the CMS as simple as possible for the end users, so I’ve set out using WordPress 3′s new custom post types to create and display these nice and neat. For this example I wanted to create a post type for “Before and After” images. Rather than having the end user have to go to media, upload it, and then grab the link for the page I wanted to have them to be able to go in to a “Before and After” post type and simply upload1 upload2 and press publish. Here’s how I went about doing it.
Step 1 : Create the Custom Post type
Custom post types are pretty easy to create:
// Creates before and after post type add_action('init', 'post_type_before_after'); function post_type_before_after() { $labels = array( 'name' => _x('Before and Afters', 'post type general name'), 'singular_name' => _x('Before and After', 'post type singular name'), 'add_new' => _x('Add New', 'before_and_after'), 'add_new_item' => __('Add New Before and After') ); $args = array( 'labels' => $labels, 'public' => true, 'publicly_queryable' => true, 'show_ui' => true, 'query_var' => true, 'rewrite' => true, 'capability_type' => 'post', 'hierarchical' => true, 'menu_position' => null, 'supports' => array('title','excerpt')); register_post_type('before_and_after',$args); }
Step 2: Creating the meta boxes
The custom post type above if you look at the code
'supports' => array('title','excerpt'));
What this does is tell WordPress what stuff you want on the admin page. I only want the title and excerpt fields on mine because I’m going to add some extras. You could also add, “editor”,
comments” etc..
<?php $prefix = 'sic_'; $meta_box = array( 'id' => 'my-meta-box', 'title' => 'Before and Afters', 'page' => 'before_and_after', 'context' => 'normal', 'priority' => 'high', 'fields' => array( array( 'name' => 'Before', 'desc' => 'Select a Before Image', 'id' => 'upload_image', 'type' => 'text', 'std' => '' ), array( 'name' => '', 'desc' => 'Select an After Image', 'id' => 'upload_image_button', 'type' => 'button', 'std' => 'Browse' ), array( 'name' => 'After', 'desc' => 'Select an After Image', 'id' => 'upload_image2', 'type' => 'text', 'std' => '' ), array( 'name' => '', 'desc' => '', 'id' => 'upload_image_button2', 'type' => 'button', 'std' => 'Browse' ), ) ); add_action('admin_menu', 'mytheme_add_box'); // Add meta box function mytheme_add_box() { global $meta_box; add_meta_box($meta_box['id'], $meta_box['title'], 'mytheme_show_box', $meta_box['page'], $meta_box['context'], $meta_box['priority']); } // Callback function to show fields in meta box function mytheme_show_box() { global $meta_box, $post; // Use nonce for verification echo '<input type="hidden" name="mytheme_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />'; echo '<table class="form-table">'; foreach ($meta_box['fields'] as $field) { // get current post meta data $meta = get_post_meta($post->ID, $field['id'], true); echo '<tr>', '<th style="width:20%"><label for="', $field['id'], '">', $field['name'], '</label></th>', '<td>'; switch ($field['type']) { //If Text case 'text': echo '<input type="text" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" />', '<br />', $field['desc']; break; //If Text Area case 'textarea': echo '<textarea name="', $field['id'], '" id="', $field['id'], '" cols="60" rows="4" style="width:97%">', $meta ? $meta : $field['std'], '</textarea>', '<br />', $field['desc']; break; //If Button case 'button': echo '<input type="button" name="', $field['id'], '" id="', $field['id'], '"value="', $meta ? $meta : $field['std'], '" />'; break; } echo '<td>', '</tr>'; } echo '</table>'; } add_action('save_post', 'mytheme_save_data'); // Save data from meta box function mytheme_save_data($post_id) { global $meta_box; // verify nonce if (!wp_verify_nonce($_POST['mytheme_meta_box_nonce'], basename(__FILE__))) { return $post_id; } // check autosave if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return $post_id; } // check permissions if ('page' == $_POST['post_type']) { if (!current_user_can('edit_page', $post_id)) { return $post_id; } } elseif (!current_user_can('edit_post', $post_id)) { return $post_id; } foreach ($meta_box['fields'] as $field) { $old = get_post_meta($post_id, $field['id'], true); $new = $_POST[$field['id']]; if ($new && $new != $old) { update_post_meta($post_id, $field['id'], $new); } elseif ('' == $new && $old) { delete_post_meta($post_id, $field['id'], $old); } } } function my_admin_scripts() { wp_enqueue_script('media-upload'); wp_enqueue_script('thickbox'); wp_register_script('my-upload', get_bloginfo('template_url') . '/functions/my-script.js', array('jquery','media-upload','thickbox')); wp_enqueue_script('my-upload'); } function my_admin_styles() { wp_enqueue_style('thickbox'); } add_action('admin_print_scripts', 'my_admin_scripts'); add_action('admin_print_styles', 'my_admin_styles');
Ok so what this has done is write all of the meta box fields that you want. The php reads what you put in the array and all of those switch cases check to see what kind of input field it is then create the format accordingly. You can copy and paste that exactly as is and it will work for this tutorial.
Step 3: Getting the WordPress Media Upload working for the browse buttons
So now we have the meta boxes for the custom field but what we want is the end user to be able to click browse and upload an image or select from the gallery. Just for usability sake you know? Heres how we do it.
If you look at the code above
function my_admin_scripts() { wp_enqueue_script('media-upload'); wp_enqueue_script('thickbox'); wp_register_script('my-upload', get_bloginfo('template_url') . '/functions/my-script.js', array('jquery','media-upload','thickbox')); wp_enqueue_script('my-upload'); } function my_admin_styles() { wp_enqueue_style('thickbox'); } add_action('admin_print_scripts', 'my_admin_scripts'); add_action('admin_print_styles', 'my_admin_styles');
This loads the wp_enqueue_script(‘thickbox;), as well as registers the “my-upload” function which will be used to link to some jquery that adds functionality to our browse buttons.
Step 4: The Jquery for the Browse Buttons
jQuery(document).ready(function() { jQuery('#upload_image_button').click(function() { window.send_to_editor = function(html) { imgurl = jQuery('img',html).attr('src'); jQuery('#upload_image').val(imgurl); tb_remove(); } tb_show('', 'media-upload.php?post_id=1&type=image&TB_iframe=true'); return false; }); }); jQuery(document).ready(function() { jQuery('#upload_image_button2').click(function() { window.send_to_editor = function(html) { imgurl = jQuery('img',html).attr('src'); jQuery('#upload_image2').val(imgurl); tb_remove(); } tb_show('', 'media-upload.php?post_id=1&type=image&TB_iframe=true'); return false; }); });
Want to learn more WordPress?
This book is way worth checking out if your just getting in to WordPress. Chris Coyier is awesome and this book is a great place to start.














thanks for this great tut!
one question: i have made a single select box type and works great.
but what about multiple select, and checkbox? it does not return all selected values, only the last one selected.
any tips on these without involving javascript? i have jquery method but i would not use that if it can be avoided.
thanks!
figured it out