Develop

Custom MetaBoxes and Fields: Show MetaBox on Condition

So there is an amazing project on GitHub that I’ve been utilizing for just about a year, Custom MetaBoxes and Fields for WordPress. It’s similar to the Advanced Custom Fields plugin, but there are some things about it I like more…one of those being that it’s not setup like a plugin and I can build it with unlimited flexibility into my client solutions.

The project is also very well supported and documented and has frequent commits, which I also like ;)

WordPress Custom Meta Box

[fig 1.0 metabox?]

I posted a question on GitHub asking if CMB had a built-in feature to show MetaBoxes/Fields on condition, which I came to find it cannot. So, I wrote a solution for my situation and have since gotten a few emails requesting that I share the setup. So, instead of responding to these per instance, I figured I would just post the method here and refer people to it.

Note: Please forgive my jQuery…I know there is a way to simplify this, but jQuery/Javascript are not yet my strong suit….I’m working on it!

Update 3/27/13:

The jQuery and CSS portions of this walkthrough were slightly altered to target ONLY pages that are using this feature. My original solution was hiding the post thumbnail (featured image) on every page…oops!

Solution:

In this instance, I am using a MetaBox with radio buttons so the client can choose which type of featured content they would like on their page: static photo, slideshow or video. Per their choice, the MetaBox containing that field will appear on the page. Here is the setup for the MetaBox that handles the radio buttons:

	$meta_boxes[] = array(
		'id' => 'featured_choose',
		'title' => 'Featured Item',
		'pages' => array('page'), // post type
		'show_on' => array( 'key' => 'page-template', 'value' => array( 'template-page.php', 'default' ) ),
		'context' => 'normal',
		'priority' => 'high',
		'show_names' => true,
		'fields' => array(
			array(
				'name' => 'Choose Feature',
				'id' => $prefix . 'feature_choose',
				'type' => 'radio_inline',
				'options' => array(
					array('name' => 'Image', 'value' => 'image'),
					array('name' => 'Slide Show', 'value' => 'slide'),
					array('name' => 'Video', 'value' => 'video')				
				)
			),								
		),
	);

In addition, here is the setup for the individual MetaBoxes related to the slideshow and video content (the static image is using WP featured image, not a CMB):

	$meta_boxes[] = array(
		'id' => 'featured_video',
		'title' => 'Featured Video',
		'pages' => array('page'), // post type
		'show_on' => array( 'key' => 'page-template', 'value' => array( 'template-page.php', 'default' ) ),
		'context' => 'normal',
		'priority' => 'high',
		'show_names' => true,
		'fields' => array(
			array(
				'name' => 'YouTube Video ID',
				'desc' => 'Paste in your YouTube video ID. Refer to the help page if you need instruction on finding it.',
				'id' => $prefix . 'featured_video',
				'type' => 'text'
			),						
		),
	);
		$meta_boxes[] = array(
		'id' => 'featured_slideshow',
		'title' => 'Featured Slideshow',
		'pages' => array('page'), // post type
		'show_on' => array( 'key' => 'page-template', 'value' => array( 'template-page.php', 'default' ) ),
		'context' => 'normal',
		'priority' => 'high',
		'show_names' => true,
		'fields' => array(
			array(
				'name' => 'Showcase Gallery Shortcode',
				'desc' => 'Paste in the shortcode to the gallery you would like on this page, example: [showcase id="###"]',
				'id' => $prefix . 'slideshow_shortcode',
				'type' => 'textarea_code'
			),						
		),
	);

So based on these MetaBoxes, I wrote the following jQuery condition and added it to the bottom of the cmb.js file. I don’t know how you manage your updates for CMB, but you may want to put this code somewhere else, as an update would override your changes. Some notes: #postimagediv is referring to the WordPress built in Featured Image MetaBox, #featured_slideshow and #featured_video are referring to the MetaBoxes we setup in the step before this where you see 'id' => $prefix .'some_id'.

Also, note the input values. These are specific to the options array for our radio buttons: array('name' => 'Image', 'value' => 'image'), we are taking the value, in this first case ‘image’ and using that in the following  condition:

	if ($('#featured_choose').length){

		$('#postimagediv', '#featured_slideshow', '#featured_video').addClass('hide_feature');

		if (jQuery('input[value=image]:checked').length > 0){
				jQuery('#postimagediv').show()
		}
			else {
				jQuery('#postimagediv').hide();
			}
			jQuery('input[name=bj_cmb_feature_choose]').change(function() {
				var selected = jQuery(this).val();console.log(selected);
				if(selected == 'image'){
					jQuery('#postimagediv').show();
			} else {
				jQuery('#postimagediv').hide();
			}
		});

		if (jQuery('input[value=slide]:checked').length > 0){
				jQuery('#featured_slideshow').show()
		}
			else {
				jQuery('#featured_slideshow').hide();
			}
			jQuery('input[name=bj_cmb_feature_choose]').change(function() {
				var selected = jQuery(this).val();console.log(selected);
				if(selected == 'slide'){
					jQuery('#featured_slideshow').show();
			} else {
				jQuery('#featured_slideshow').hide();
			}
		});

		if (jQuery('input[value=video]:checked').length > 0){
				jQuery('#featured_video').show()
		}
			else {
				jQuery('#featured_video').hide();
			}
			jQuery('input[name=bj_cmb_feature_choose]').change(function() {
				var selected = jQuery(this).val();console.log(selected);
				if(selected == 'video'){
					jQuery('#featured_video').show();
			} else {
				jQuery('#featured_video').hide();
			}
		});

	}

The last step you need to take is some simple CSS that again, I included in the bottom of the style.css file included with CMB.

	.hide_feature {
		display:none;
	}

Explanation:

Once our MetaBoxes have been setup, we are fist checking to see that our MetaBox with the id #featured_choose exists on the page. If it does, we are hiding our three featured options (#postimagediv, #featured_video and #featured_slideshow) with the CSS. Our jQuery is checking to see what radio button value is currently selected, and if that value is selected it will change our CSS display:none to display:block, which “shows” our previously hidden MetaBox. The great thing about this too, is that the data that was entered in any one of these MetaBoxes remains there unless you remove it. In my case this is ideal, since the client will frequently be changing between video, image etc. and won’t need to reinsert assets that were previously used.

Note:

For this to make sense from a UI perspective, make sure you “slide” your conditional MetaBoxes to be one on top of the other so that when the hide/appear it happens in the same area in the page editor. I moved “featured image” from it’s standard spot in the right column to directly above the video and slideshow MetaBoxes.

 

{ 11 Comments }

  1. Alain Sainvil

    wow, thank you Chris, this article was written in 2013 and till this day it still works like a charm, thank you again.

    • Chris Perryman

      Awesome! You’re welcome 😉

  2. In case you have a set of complex fields, you can try with Meta Box Conditional Logic plugin, it have more controls of visibility for meta boxes, and more operators for them also :)

  3. Hi Chris,

    I used your tutorial for inspiration, my jQuery and javascript isn’t much better.
    I broke it down to a function that analyzes a variable I’m setting and passing to it in an if loop that can technically be infinite.

    function doBoxes(selecType) {

    if (selecType ==’TYPEX’){

    $(‘TypeX_info’).show();
    }else if(selecType ==’NOTX’){

    $(‘#TypeX_info’).hide();

    }
    else if(selecType !=’typeA’){

    $(‘#typeA_info’).hide();

    }
    else if(selecType ==’typeA’){

    $(‘#typeA_info’).show();

    }
    }

    I call this with a simple script –

    $(‘.cmb_select’).change(function(){

    selecType = $(this).find(“option:selected”).text();
    doBoxes(selecType);

    });

    This handles the change function and fires it every time the box changes.

    When loading, I want to run this on every possible box. You could do an each() function for each of these that mimics the on-change function. If you don’t have a lot, you can just fire it onload:

    $(){
    selecType = $(‘#select :selected’).text();
    doBoxes(selecType);
    event_selectype = $(‘#select_2 :selected’).text();
    doBoxes(selecType);
    }

    or

    $(‘.cmb_select’).each{function(){
    selecType = $(‘#select :selected’).text();
    doBoxes(selecType);
    }

    I know this post is a bit older, hopefully this helps people trying to make this run in a slightly DRYer manner.

    • Chris Perryman

      Mike, thank you for your contribution!

  4. Patrick

    Hello there and thank you for this trick.
    I’d like to use CMB to create a full screen image in a page using jQuery Vegas.
    I’m using CMB to upload image inside a page template and it works.
    My problem is that I’d like to upload more images to create a full screen image slide in that page.

    Do you know how I can get it, please?
    Thank You very much for your time.

    • Chris Perryman

      Hey Patrick,

      I’ve done something similar to what you’re talking about using jQuery Flexslider. I don’t think CMB has a “gallery” option to upload multiple photos, so what I did was write a query that pulls all of the images uploaded directly to that particular post/page…then spits them out into the slider.

      I’ve written a post about this for you, you can view it here.

    • Hey Chris, great write-up! CMB does actually support multiple file uploads via the file_list field type. You could also use repeatable groups with a ‘file’ field in the grouped field.

    • Chris Perryman

      Hi Justin, thanks for the update and for all of your contributions to the WP community! I haven’t used CMB for a while, but I know there have been updates and improvements since I had been using it and I’ve been meaning to get back into it ;) Repeatable groups sound like a great addition.

  5. Chris, I can’t thank you enough for sharing this. I’m currently wrapping my head around meta boxes and conditionally showing more meta boxes was a feature I wanted to implement. Your code worked beautifully!

    • Chris Perryman

      Yay! So glad it helped. Metaboxes are the besssssst :)

{ Respond }

Leave a response