Monday, June 27, 2011

Create Custom Write Panels in WordPress



hanks to webdesignfan



Introduction

The Custom Meta Box was a feature mainly implemented in WordPress 3.0, but has been around a bit longer, since maybe 2.8. They are one of the more powerful features available to theme and plugin developers, but, sadly, not used that frequently.




Custom meta boxes are extra input fields that can be included on the post editor screen, allowing us to enter extra information about our post or page.

Being able to create custom meta boxes gives us the power to define “templates” in a sense. Essentially what they allow us to do is create a set list of “variables”, or “additional info” that can be filled for every post (or a specific post type) without having to go through the bother of writing them out every time.
What are They Used For?



Imagine you run a music website and periodically post updates about new albums coming out: custom meta boxes can be used for listing all of the album details, such as artist, genre, price, release date, etc.

Pretend that you run a website all about cars: custom meta boxes can be used for listing all of the engine specifications, such as number of cylinders, horse power, color, interior details, price, etc.

Or how about a real estate website: custom meta boxes can be used for listing the property details, such as location, square foot, number of baths, garage details, and more.

And one more less specific example: event calendars. If you periodically list events on your website, you’d probably like to be able to set the event details without having to write them out at the bottom or top of your post every time. Instead, you can use custom meta boxes to set up a few nice options that allow you to simply choose the data and time of the event, the location, and anything else your event may need.

Essentially, custom meta boxes can be used for just about anything, and they can be the perfect solution for a countless number of challenges.
Getting Into the Basics

One of the best things you can have when working with something that is new to you, is have a good reference you can consult when you get stuck, or simply need further explanation. So here is a link to the WordPress Function Reference. That article can be of a huge help and I highly suggest looking over it.

Now let’s get started for real.

In order to create our meta boxes, we will be using a WordPress function called add_meta_box();. It looks like this:add_meta_box( $id, $title, $callback, $page, $context, $priority, $callback_args );


The function accepts several paramaters:
$id required: the unique identifier for the meta box
$title required: the title for the meta box, to be displayed in the post editor
$callback required: function that prints out the HTML displayed on the post edit screen
$page required: The kind of edit screen to display the meta box
‘post’, ‘page’, ‘link’, or ‘custom_post_type’ (the name of the custom post type)
$context optional: the place on the editor screen the meta box will be displayed
‘normal’, ‘advanced’, or ‘side’
Default: ‘advanced’
$priority optional: The position within the context the meta box should be shown
‘high’ or ‘low’
$callback_args optional: Arguments to pass into your callback function. The callback will receive the $post object and whatever parameters are passed through this variable.

So, once we have filled in all of the paramaters into our meta box, it might look something like this inside of our functions.php:add_meta_box( 'my_first_meta_box', 'My First Meta Box', 'display_html', 'post', 'advanced', 'high' );


The ID of our box is myFirstMetaBoxm the title is My Meta Box Title, the HTML we wish to display is contained inside a function called display_html(), we are going to display the meta box on all post editing screens, the location of the box in the post editor is the advanced section (below the main content editor), and the priority is set to high so that the box shows up just below the main content editor (as compared to being pushed down by, say, the custom fields).

Now let’s look at the function for displaying the HTML (also in functions.php:function display_html() { echo 'This is your first meta box'; }


Now, your post editor should look like this:



That’s it! At least for a really simple meta box.
Getting a Little More Advanced

The above example really doesn’t do anything, and doesn’t serve a purpose, so let’s expand upon what we’ve just learned and make it so our meta box can actually receive some sort of input.

What we will do now is setup a complete meta box that will allow us to enter a set of details, including a block of text, perhaps for an additional description, a single line of text for a date, choose an option from a drop down list, as well as pick options from a series of check boxes.

Our final result will look like this:


Create Options for the Meta Box

As with before, all of our code is going to be placed inside of the functions.php, though we will not be using the exact code from above, (it was only an example) so it can be erased.

First, we are going to create a list of all of the options we want displayed in out meta box. Copy this code into functions.php:// custom meta boxe $prefix = 'custom_meta_'; // a custom prefix to help us avoid pulling data from the wrong meta box $meta_box = array( 'id' => 'my_first_meta_box', // the id of our meta box 'title' => 'My First Meta Box', // the title of the meta box 'page' => 'post', // display this meta box on post editing screens 'context' => 'normal', 'priority' => 'high', // keep it near the top 'fields' => array( // all of the options inside of our meta box array( 'name' => 'Sub Title', 'desc' => 'Give this post a sub title?', 'id' => $prefix . 'subtitle', 'type' => 'text', 'std' => '' ), array( 'name' => 'Additional Details', 'desc' => 'Enter extra post details here', 'id' => $prefix . 'add_details', 'type' => 'textarea', 'std' => '' ), array( 'name' => 'Choose a Fruit', 'id' => $prefix . 'fruit', 'type' => 'select', 'options' => array('Apples', 'Oranges', 'Pears', 'Pineapples') ), array( 'name' => 'Check 1', 'id' => $prefix . 'check1', 'type' => 'checkbox', ), array( 'name' => 'Check 2', 'id' => $prefix . 'check2', 'type' => 'checkbox', ), array( 'name' => 'Check 3', 'id' => $prefix . 'check3', 'type' => 'checkbox', ), ) );


Before moving onward, let me break this code down for you a little. The top section is self explanatory if you read the comments, but the middle gets a bit more complex.

Each option we create looks like this, more or less:array( 'name' => 'Sub Title', 'desc' => 'Give this post a sub title?', 'id' => $prefix . 'subtitle', 'type' => 'text', 'std' => '' ),


First, we set the option name to Sub Title, then we describe our option with the desc. Next we give a unique ID, followed by our meta boxes prefix, to our Option. When rendered, the ID is custom_meta_subtitle. This is very important because we will use the complete IDs of our options later on. The next line defines our option as a type = text, which is a single text input line. And lastly, we define what we want the default text to be inside of our option with std. In this case, we’ve left it blank, but it could be anything.

So you can see that we can easily create more options by simply creating additional arrays with each of the variables set to our desired value. For example, if we want to create a drop down list of options, as I have down above, we can do it like this:array( 'name' => 'Choose a Fruit', 'id' => $prefix . 'type', 'type' => 'select', 'options' => array('Apples', 'Oranges', 'Pears', 'Pineapples') ),


The only difference between this example and the first one is that we have changed the type from text to select, and also defined a list of options. If we wanted to have five options, instead of four, we could simply change the last line to:'options' => array('Apples', 'Oranges', 'Pears', 'Pineapples', 'Tomatoes')

Add Meta Box to Editor

Now that we have created the options for the meta box, we need to actually make the meta box show up on the editor screen.// Add meta box to editor function my_first_meta_add_box() { global $meta_box; // get all of the options from the $meta_box array add_meta_box($meta_box['id'], $meta_box['title'], 'display_html', $meta_box['page'], $meta_box['context'], $meta_box['priority']); } add_action('admin_menu', 'my_first_meta_add_box');


Even though we’re still using the add_meta_box() that we used in section 2, it looks a bit different. The reason is that we’re pulling all of the paramaters from the global $meta_box variable we defined above. Remember this?'id' => 'my_first_meta_box', // the id of our meta box 'title' => 'My First Meta Box', // the title of the meta box 'page' => 'post', // display this meta box on post editing screens 'context' => 'normal', 'priority' => 'high', // keep it near the top


All of our add_meta_box() paramaters come from that.

The last line in the my_first_meta_add_box() function is very important. Withoutadd_action('admin_menu', 'my_first_meta_add_box');


our meta box will not show up.

NOTE: At this point in the tutorial, the options inside of your meta box will NOT show up. So don’t freak out :)
Display Meta Options With HTML Callback

So we’ve created the options and added the meta box to our post editors, the next step is to format the options using HTML markup within our meta box.

Paste this into your functions.php below all of the code we have thus far created:// Callback function to show fields in meta box function display_html() { global $meta_box, $post; // get the variables from global $meta_box and $post // Use nonce for verification to check that the person has adequate priveleges echo '<input type="hidden" name="my_first_meta_box_nonce" value="', wp_create_nonce(basename(__FILE__)), '" />'; // create the table which the options will be displayed in echo ''; foreach ($meta_box['fields'] as $field) { // do this for each array inside of the fields array // get current post meta data $meta = get_post_meta($post->ID, $field['id'], true); echo '', // create a table row for each option '', '



['id'], '">', $field['name'], '

'; switch ($field['type']) { case 'text': // the HTML to display for type=text options echo '['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" />', ' ', $field['desc']; break; case 'textarea': // the HTML to display for type=textarea options echo '[</span><span class="phpString">'id'</span><span class="phpOperator">]</span>, <span class="phpString">'" id="'</span>, $field<span class="phpOperator">[</span><span class="phpString">'id'</span><span class="phpOperator">]</span>, <span class="phpString">'" cols="60" rows="8" style="width:97%">', $meta ? $meta : $field['std'], '', ' ', $field['desc']; break; case 'select': // the HTML to display for type=select options echo ''; break; case 'radio': // the HTML to display for type=radio options foreach ($field['options'] as $option) { echo '['id'], '" value="', $option['value'], '"', $meta == $option['value'] ? ' checked="checked"' : '', ' />', $option['name']; } break; case 'checkbox': // the HTML to display for type=checkbox options echo '['id'], '" id="', $field['id'], '"', $meta ? ' checked="checked"' : '', ' />'; break; } echo '<td>', '</tr>'; } echo '</table>'; } This code probably looks pretty complex, but it's actually quite simple, once you get past the difficult syntax. Essentially, it reads the fields array inside of the $meta_box array that we created in step 5 and outputs a specific HTML layout for each type of option. So, if an option is of type text, the following gets outputted into our meta box:<input type="text" name="', $field['id'], '" id="', $field['id'], '" value="', $meta ? $meta : $field['std'], '" size="30" style="width:97%" />


It will then also auto-populate the name=”", id=”", and value=”" with the variable set for the option in step 5. So after everything is rendered out it might look like this:"text" name="Sub Title" id="custom_meta_subtitle" value="" size="30" style="width:97%" />


Excellent! Now our options will actually show up in our meta box.
Saving the Meta Box Data

If you have tried to input some data into the new meta box options, then clicked Update, you will notice that none of your data is actually saved.

So let’s make a function to save the data.

Once again, in functions.php:// Save data from meta box function my_first_meta_save_data($post_id) { global $meta_box; // verify nonce -- checks that the user has access if (!wp_verify_nonce($_POST['my_first_meta_box_nonce'], basename(__FILE__))) { return $post_id; } // check autosave if (defined('DOING_AUTOSAVE') &amp;&amp; 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) { // save each option $old = get_post_meta($post_id, $field['id'], true); $new = $_POST[$field['id']]; if ($new &amp;&amp; $new != $old) { // compare changes to existing values update_post_meta($post_id, $field['id'], $new); } elseif ('' == $new &amp;&amp; $old) { delete_post_meta($post_id, $field['id'], $old); } } } add_action('save_post', 'my_first_meta_save_data'); // save the data


I’m not going to explain exactly how this code works, except to say that if you read the comments, you should have a sufficient understanding.
Displaying Custom Meta Info

In this section, I’m going to show you two different ways to display your post’s custom meta information. Note that I am not going to talk about how to style the meta information, just display it. Styling and organization are up to you.

Method Number 1 – From Inside functions.php

The following function will display all of the post meta just above the post’s main content:function display_post_meta($content) { $custom_meta = get_post_custom($post->ID); // get all of the post's meta and store in $custom_meta $subtitle = $custom_meta['custom_meta_subtitle'][0]; // store the subtitle in $subtitle $details = $custom_meta['custom_meta_add_details'][0]; // store additional details in $details $fruit = $custom_meta['custom_meta_fruit'][0]; // store fruit $check1 = $custom_meta['custom_meta_check1'][0]; // store first check $check2 = $custom_meta['custom_meta_check2'][0]; // store second check $check3 = $custom_meta['custom_meta_check3'][0]; // store third check echo '<div class="custom_meta_content">'; if (isset($subtitle)) // check to see if $subtitle is empty { echo '<span>' . $subtitle . '</span>'; // display sub title } if (isset($details)) // check if it's empty { echo '<tp>' . $details . '</p>'; // display additional details } echo '<p>This is the kind of fruit I like: ' . $fruit . '</p>'; // display favorite fruit if (isset($check1)) // test to see if it's checked { echo '<p>Check # 1 is checked.</p>'; // display message } if (isset($check2)) // test to see if it's checked { echo '<p>Check # 2 is checked.</p>'; // display message } if (isset($check3)) // test to see if it's checked { echo '<p>Check # 3 is checked.</p>'; // display message } echo '</div>'; return $content; } add_filter('the_content', 'display_post_meta');


This method works really well, but does not allow you to control the position of the meta information very well. For example, maybe you want you display the subtitle just below the actual post title? That would be very difficult with this method.

I recommend using this method if you are developing a plugin for custom meta boxes.

Method Number 2 – From Inside single.php

This method is definitely better for theme development as it provides us greater control over the positioning of the meta elements.

Your single.php probably looks something like this:<?php if (have_posts()) : ?> <?php while (have_posts()) : the_post(); ?>


"entry">
"<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?>




"entry-text"> <?php the_content('Read the rest of this entry »'); ?>

<?php endwhile; ?> <?php endif; ?>


Well, to display your custom meta information, modify the single.php to look something more like this:<?php if (have_posts()) : ?> <?php while (have_posts()) : the_post(); ?> <?php $custom_meta = get_post_custom($post->ID); $subtitle = $custom_meta['custom_meta_subtitle'][0]; $details = $custom_meta['custom_meta_add_details'][0]; $fruit = $custom_meta['custom_meta_fruit'][0]; $check1 = $custom_meta['custom_meta_check1'][0]; $check2 = $custom_meta['custom_meta_check2'][0]; $check3 = $custom_meta['custom_meta_check3'][0]; ?>


"entry">
"<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?>




"subtitle"><?php echo $subtitle; ?>


"entry-text"> <?php the_content('Read the rest of this entry »'); ?>


"add_details"> <?php echo $details; ?>


"fruit"> I really like <?php echo $fruit; ?>. <?php if (isset($check1)) { echo '<p>Check # 1 is checked.</p>'; } if (isset($check2)) { echo '<p>Check # 2 is checked.</p>'; } if (isset($check3)) { echo '<p>Check # 3 is checked.</p>'; } ?>

<?php endwhile; ?> <?php endif; ?>


There you have it.

No comments:

Post a Comment