Today I'd like to show you how to go further with custom metaboxes and specifically how to use them according to post formats.
We won't cover how to build reusable custom metaboxes as it has already been covered in a previous topic, so please refer to this article if you have any trouble with this.
Introduction
First things first, if you've never heard of them before, post formats allow you to display a post in many ways, depending on which "format" of post you've set (image, link, gallery etc.).
To be sure that your theme is "post formats"-ready, check that it accepts different formats by looking for this function:
add_theme_support( 'post-formats', array( 'link', 'quote' ) );
Now with this example, you'll be able to use two post formats: 'link' and 'quote'.
The idea is to display a metabox only if the right post format radio button is checked. For this, we are going to use hooks (PHP) and jQuery (JavaScript).
Step 1 Adding Custom Metaboxes
We'll define an array of metaboxes applicable to posts only (you can write it inside the functions.php file of your theme). There are different default options (location, priority) we won't focus on (again check the article on reusable custom metaboxes).
Define Metaboxes
Besides the fields we are defining, what is important to note in the code below is the display_condition
variable that will be used to show/hide metaboxes according to the current post format. It matches the post format radio button's ID.
$metaboxes = array( 'link_url' => array( 'title' => __('link information', 'twentyeleven'), 'applicableto' => 'post', 'location' => 'normal', 'display_condition' => 'post-format-link', 'priority' => 'low', 'fields' => array( 'l_url' => array( 'title' => __('link url:', 'twentyeleven'), 'type' => 'text', 'description' => '', 'size' => 60 ) ) ), 'quote_author' => array( 'title' => __('quote author', 'twentyeleven'), 'applicableto' => 'post', 'location' => 'normal', 'display_condition' => 'post-format-quote', 'priority' => 'low', 'fields' => array( 'q_author' => array( 'title' => __('quote author:', 'twentyeleven'), 'type' => 'text', 'description' => '', 'size' => 20 ) ) ) );
For this tutorial, we'll only add a basic text input for each metabox. Be sure to check the field key is unique or it won't work properly.
Now we'll create three functions to add, update/save, and show the metaboxes.
Create Metaboxes
add_action( 'admin_init', 'add_post_format_metabox' ); function add_post_format_metabox() { global $metaboxes; if ( ! empty( $metaboxes ) ) { foreach ( $metaboxes as $id => $metabox ) { add_meta_box( $id, $metabox['title'], 'show_metaboxes', $metabox['applicableto'], $metabox['location'], $metabox['priority'], $id ); } } }
Basicly, we're just using our previously defined options to add these metaboxes.
Show Metaboxes
function show_metaboxes( $post, $args ) { global $metaboxes; $custom = get_post_custom( $post->ID ); $fields = $tabs = $metaboxes[$args['id']]['fields']; /** Nonce **/ $output = '<input type="hidden" name="post_format_meta_box_nonce" value="' . wp_create_nonce( basename( __FILE__ ) ) . '" />'; if ( sizeof( $fields ) ) { foreach ( $fields as $id => $field ) { switch ( $field['type'] ) { default: case "text": $output .= '<label for="' . $id . '">' . $field['title'] . '</label><input id="' . $id . '" type="text" name="' . $id . '" value="' . $custom[$id][0] . '" size="' . $field['size'] . '" />'; break; } } } echo $output; }
So far, this is what we should have on a new post admin screen:
Save Metaboxes
add_action( 'save_post', 'save_metaboxes' ); function save_metaboxes( $post_id ) { global $metaboxes; // verify nonce if ( ! wp_verify_nonce( $_POST['post_format_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; } $post_type = get_post_type(); // loop through fields and save the data foreach ( $metaboxes as $id => $metabox ) { // check if metabox is applicable for current post type if ( $metabox['applicableto'] == $post_type ) { $fields = $metaboxes[$id]['fields']; foreach ( $fields as $id => $field ) { $old = get_post_meta( $post_id, $id, true ); $new = $_POST[$id]; if ( $new && $new != $old ) { update_post_meta( $post_id, $id, $new ); } elseif ( '' == $new && $old || ! isset( $_POST[$id] ) ) { delete_post_meta( $post_id, $id, $old ); } } } } }
Ok, now we're all set and are able to add and update post metas to each and every article and display them inside metaboxes. We can now dig into our problem: display the correct metabox to match the current post format.
Step 2 Display the Correct Metabox at the Correct Time
For this, we will use jQuery to handle show, hide and radio change events.
To add inline JavaScript only in the admin section, we can use this action hook:
add_action( 'admin_print_scripts', 'display_metaboxes', 1000 );
The priority is set to 1000 to ensure jQuery has been loaded first.
We could set a more precise hook such as admin_print_scripts-post
or admin_print_scripts-post-new
, but for some reason, if doing so, jQuery is called after our script is printed.
Plus, if we were to add post formats to custom post types, it wouldn't be very convenient to add all possible configurations.
What we'll do is build (via PHP) a JavaScript string containing a list of IDs (the field key seen above) separated with a comma. It will be used to hide all metaboxes but the one matching the current post format.
We are also going to build (still via PHP) a JavaScript object we'll use to bind a post format radio button's ID to a metabox's ID.
function display_metaboxes() { global $metaboxes; if ( get_post_type() == "post" ) : ?> <script type="text/javascript">// <![CDATA[ $ = jQuery; <?php $formats = $ids = array(); foreach ( $metaboxes as $id => $metabox ) { array_push( $formats, "'" . $metabox['display_condition'] . "': '" . $id . "'" ); array_push( $ids, "#" . $id ); } ?> var formats = { <?php echo implode( ',', $formats );?> }; var ids = "<?php echo implode( ',', $ids ); ?>";
Then we will display the right metabox after the page is loaded by selecting the current post format (checked radio button) and fading in the matching metabox (using the formats
object).
For this, we'll define a function that will also be triggered every time a change event happens on the post format radio buttons.
function displayMetaboxes() { // Hide all post format metaboxes $(ids).hide(); // Get current post format var selectedElt = $("input[name='post_format']:checked").attr("id"); // If exists, fade in current post format metabox if ( formats[selectedElt] ) $("#" + formats[selectedElt]).fadeIn(); } $(function() { // Show/hide metaboxes on page load displayMetaboxes(); // Show/hide metaboxes on change event $("input[name='post_format']").change(function() { displayMetaboxes(); }); }); // ]]></script> <?php endif; }
And voila! Now you can switch post formats back and forth and you'll always have the right metabox displayed.
Conclusion
Post formats can be very handy to personalize the layout of any kind of post and displaying metaboxes accordingly is a great way to improve user-friendliness.
Plus it saves space on an already well cluttered admin screen. With a little more CSS and several fields, you can really improve the way you write posts and get a really intuitive interface.
Comments