How to Display Metaboxes According to the Current Post Format

How to Display Metaboxes According to the Current Post Format

Tutorial Details
  • Program: WordPress, jQuery
  • Version: 2.5+
  • Difficulty: Advanced
  • Estimated Completion Time: 30 min

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’.

Two metaboxes with a simple text input inside

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:

Two metaboxes with a simple text input inside

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.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://blog.nicolas-juen.fr/ Rahe

    Add a real js file and use the wp_localize_script for the dynamic names.
    At least use the esc_js function for the dynamic vars you use. JQuery is on noConflict mode so use the JQuery instead of $, or wrap your functions in jQuery( function($) {…} ); for using $.
    For theses you can use the admin_enqueue_scripts that give you a parameter for the current page and test if you are on a post page or not.

    • janw_oostendorp

      Totaly agree with you, the JS part isn’t done so well :(

    • Guillaume
      Author

      Thanks for your comment, I’ll separate JS from PHP next time ;)

  • Pingback: Tweet Parade (no.45 Nov 2012) | gonzoblog

  • Pingback: November 2012 Handout: Custom Field & Metabox Resources

  • harishchouhan
    • Guillaume
      Author

      My code isn’t too different from Tammy Hart’s. There shouldn’t be much problem to adapt.

  • Keisa

    So everything here goes inside functions.php , correct?

    • Guillaume
      Author

      Have you activated the audio post format ?

      add_theme_support( ‘post-formats’, array( ‘audio’ ) );

      • Juan Manuel Villegas

        lol she hasnt..

  • Keisa

    Also, how does the content of the custom meta box appear on the front-end? Nothing appears on my site :(

    • Guillaume
      Author

      It wasn’t really the point of this tutorial. So it doesn’t actually. But you can get your post metas using wordpress function get_post_meta() and use it inside your theme.

  • Guest

    How can I add multiple meta fields?

    • Guillaume
      Author

      You simply have to add some within the “fields” array when you declare your metaboxes.

      • Akeisa Lowe

        I tried but I get this error “Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting ‘)’ in /functions.php on line 666″

  • Akeisa Lowe

    This code disables my “Tags” metabox. I am not able to insert tags into my posts after following this tutorial…

  • http://twitter.com/DDInteligente DDInteligente

    Hi How I can do to add a METABOX for a slideshow in a custom post type?

    • Juan Manuel Villegas

      using Advanced Custom Fields plugin with the Repeater addon is going to be the fastest for you advancedcustomfields.com

  • tuan anh

    ‘description’ => ‘some txt’, <—————- not working ?

  • tuan anh

    ‘description’ => __(‘some text’), <—————- not working ? somebody tell me why ?