I recently needed to modify my portfolio items to display a bit differently than my blog posts. I also decided I didn’t want to hack a solution together and instead have a simple form in the backend where I could add portfolio pieces easily. I chose to make a custom write panel to accomplish this.
Custom write panels like the one shown above are common in many wordpress themes nowadays. Many theme developers rely on them to give the user easy access to control more complex features of a site. In this tutorial I’ll walk you through a simple example of custom write panel code found here.
We’re going to follow the order that WordPress would look at this. Below you can see a simple call that “hooks” into the admin menu. WordPress knows when it reaches this “hook” it will run a function called “create_portfolio_images”.
add_action( 'admin_menu', 'create_portfolio_images' );
Now WordPress looks for this function within this file. Sure enough it finds it.
function create_portfolio_images() { global $key_images; if( function_exists( 'add_meta_box' ) ) { add_meta_box( 'new-portfolio-images', ucfirst( $key_images ) . ' Images', 'display_portfolio_images', 'post', 'normal', 'high' ); } }
Now we see that we need something called “$key_images” in the global scope. We define it in the block of code at the top of the page. We also define what fields we’ll be outputting to the admin menu, but that comes a bit later.
$key_images = "portfolio";
Now that we’ve defined what this admin panel is called. We can look at the above function called “create_portfolio_images”. It’s pulling in our key, then if a function called “add_meta_box” exists, we’ll call the function on another function called “display_portfolio_images”. This is where we start to get fancy.
function display_portfolio_images() { global $post, $meta_boxes_images, $key_images; ?> <div class="form-wrap"> <?php wp_nonce_field( plugin_basename( __FILE__ ), $key_images . '_wpnonce', false, true ); foreach($meta_boxes_images as $meta_box) { $data = get_post_meta($post->ID, $key_images, true); ?> <div class="form-field form-required"> <label for="<?php echo $meta_box[ 'name' ]; ?>"><?php echo $meta_box[ 'title' ]; ?></label> <input type="text" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" /> <p><?php echo $meta_box[ 'description' ]; ?></p> </div> <?php } ?> </div> <?php }
Now that we’ve called the function to display our admin panel to the user, we need some information about the form fields we’ll be showing. To get this, we define an array at the top of the page to list out each of our form fields.
$meta_boxes_images = array( "portfolio_image1" => array( "name" => "portfolio_image1", "title" => "Portfolio Image 1", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_image2" => array( "name" => "portfolio_image2", "title" => "Portfolio Image 2", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_image3" => array( "name" => "portfolio_image3", "title" => "Portfolio Image 3", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_image4" => array( "name" => "portfolio_image4", "title" => "Portfolio Image 4", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_imag5" => array( "name" => "portfolio_image5", "title" => "Portfolio Image 5", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340.") );
Now that we have our data about the form fields we’ll show to the admin, its time to add our second action. So far we have something to display our new admin panel and show some form fields. Now we want the form fields to save our data when the user hits the “update” or “publish” buttons. We’ll do that by adding another “hook” into WordPress.
add_action( 'save_post', 'save_portfolio_images' );
We’ll say that when we “save the post” we’ll run another function called “save_portfolio_images”. This will do some security screening and save the new post data to your post_meta area of our posts.
function save_portfolio_images( $post_id ) { global $post, $meta_boxes_images, $key_images; foreach( $meta_boxes_images as $meta_box ) { $data[ $meta_box[ 'name' ] ] = $_POST[ $meta_box[ 'name' ] ]; } if ( !wp_verify_nonce( $_POST[ $key_images . '_wpnonce' ], plugin_basename(__FILE__) ) ) return $post_id; if ( !current_user_can( 'edit_post', $post_id )) return $post_id; update_post_meta( $post_id, $key_images, $data ); }
When it’s all put together, it should look something like this:
<?php $key_images = "portfolio"; $meta_boxes_images = array( "portfolio_image1" => array( "name" => "portfolio_image1", "title" => "Portfolio Image 1", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_image2" => array( "name" => "portfolio_image2", "title" => "Portfolio Image 2", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_image3" => array( "name" => "portfolio_image3", "title" => "Portfolio Image 3", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_image4" => array( "name" => "portfolio_image4", "title" => "Portfolio Image 4", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340."), "portfolio_imag5" => array( "name" => "portfolio_image5", "title" => "Portfolio Image 5", "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here. These Images are generally 900x340.") ); function create_portfolio_images() { global $key_images; if( function_exists( 'add_meta_box' ) ) { add_meta_box( 'new-portfolio-images', ucfirst( $key_images ) . ' Images', 'display_portfolio_images', 'post', 'normal', 'high' ); } } function display_portfolio_images() { global $post, $meta_boxes_images, $key_images; ?> <div class="form-wrap"> <?php wp_nonce_field( plugin_basename( __FILE__ ), $key_images . '_wpnonce', false, true ); foreach($meta_boxes_images as $meta_box) { $data = get_post_meta($post->ID, $key_images, true); ?> <div class="form-field form-required"> <label for="<?php echo $meta_box[ 'name' ]; ?>"><?php echo $meta_box[ 'title' ]; ?></label> <input type="text" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" /> <p><?php echo $meta_box[ 'description' ]; ?></p> </div> <?php } ?> </div> <?php } function save_portfolio_images( $post_id ) { global $post, $meta_boxes_images, $key_images; foreach( $meta_boxes_images as $meta_box ) { $data[ $meta_box[ 'name' ] ] = $_POST[ $meta_box[ 'name' ] ]; } if ( !wp_verify_nonce( $_POST[ $key_images . '_wpnonce' ], plugin_basename(__FILE__) ) ) return $post_id; if ( !current_user_can( 'edit_post', $post_id )) return $post_id; update_post_meta( $post_id, $key_images, $data ); } add_action( 'admin_menu', 'create_portfolio_images' ); add_action( 'save_post', 'save_portfolio_images' ); ?>
This will save your new custom admin panel, otherwise known as a “write panel” in WordPress.
Mike,
I copied your code & it worked perfectly. Thanks for providing it. Normally, I don’t just copy & paste without first digesting everything, but I’m under time pressure.
Thanks John,
I’m glad it worked out for you. I could have cleaned up the code a bit, but likewise…I’m under time and pressure.
The write panels works for me but how do you output the data in the single posts?
I guesss you use som kide of echo of the meta data?
Could you show the exact code you put into the single.php?
Thanks a lot for the post.. Can you please tell me that if I am doing the WordPress Blog Customization, so at that time custom right panel is available for the blog or not..
I think this is among the most important information for me. And i am glad studying your article. However wanna remark on some basic issues, The site taste is wonderful, the articles is actually nice : D. Good task, cheers