Categories
How To

CMB2: Conditional Meta Fields

Hiding parts of CMB2 fields is necessary to make like less confusing and easier.

Even though Gutenberg is on the rise, and every day gets us closer to using a whole new editor, we still use the ‘classic’ editor and we’re still beholden to it’s space limitations. I have strong feelings about how to properly utilize space when using CMB2, but not included in that specific post is this.

Fields You Don’t (Always) Need Fields You Don’t (Always) Need

There are three types of fields for CMB2.

  1. Fields you always need to use
  2. Fields that are optional
  3. Fields that are needed only in specific situations

Most of the time we use option 2. Option 3 is the tricky one, though, since most of the time we end up having things show based on actions. That is, I save a post, and new options show up. When it comes to CMB2, we really don’t want to have to save and then edit and save and edit.

Yuck!

Thankfully this is all possible.

Top ↑

Practical Example: Affiliates Practical Example: Affiliates

Today we’re making a box to handle affiliate links. There are three types of links: Amazon, Genric, and ‘Unique.’

The Amazon one will link directly to a signup link and the generic one links to the same thing only on Click Junction. Both of those links will have affiliate details backed in so I don’t have to look them up later. This also means any partners I have on the site don’t need to know all the gory details. Bazinga.

The last one, though ‘Unique’ is tricky. You see, when someone picks that, I want them to be able to put in a specific URL that may be affiliate linking somewhere else. But let’s start out with how it normally works.

Top ↑

Make Your Fields Make Your Fields

function my_site_cmb2_metaboxes() {
	// prefix for all custom fields
	$prefix = 'my_sites_';

	// Metabox Group: Must See
	$cmb_affiliate = new_cmb2_box( array(
		'id'           => 'affiliate_metabox',
		'title'        => __( 'Affiliate Details', 'my-domain' ),
		'object_types' => array( 'post_type_shows' ),
		'show_in_rest' => true,
	) );

	// Field Box: Affiliate Type
	$field_affiliatetype = $cmb_affiliate->add_field( array(
		'name'             => __( 'Type', 'my-domain' ),
		'id'               => $prefix . 'affiliate',
		'type'             => 'select',
		'options'          => array( 
			'amazon'  => 'Amazon',
			'generic' => 'Generic',
			'url'     => 'Unique Link',
		);
		'show_option_none' => true,
	) );
	// Field Box: Affiliate Links
	$field_affiliateurl = $cmb_affiliate->add_field( array(
		'name'    => __( 'Link', 'my-domain' ),
		'id'      => $prefix . 'affiliateurl',
		'type'    => 'text_url',
	) );
);

That’s pretty normal for CMB2 and looks like this:

CMB2: Affiliate Details

Normal, but … I want to hide that Link field unless a specific option is selected. Enter javascript.

Top ↑

Hide That Field (Conditionally) Hide That Field (Conditionally)

Make a file for your javascript. I’ve called mine cmb2.js and put it in the same folder as my file that will enqueue the scripts.

// Either create a new empty object, or work with the existing one.
window.MySite_CMB2 = window.MySite_CMB2 || {};

(function( window, document, $, app, undefined ) {
	'use strict';

	app.cache = function() {
		app.$ = {};
		app.$.select = $( document.getElementById( 'my_sites_affiliate' ) );
		app.$.field = $( document.getElementById( 'my_sites_affiliateurl' ) );
		app.$.field_container = app.$.field.closest( '.cmb-row');
	};

	app.init = function() {
		app.cache();
		app.$.select.on( 'change', function( event ) {
			if ( 'url' === $(this).val() ) {
				app.$.field_container.show();
			} else {
				app.$.field_container.hide();
			}
		} ).trigger( 'change' );
	};

	$( document ).ready( app.init );
})( window, document, jQuery, MySite_CMB2 );

And then call the enqueue, but only when appropriate (because we want to keep the load low):

add_action( ‘admin_enqueue_scripts’, ‘my_site_admin_enqueue_scripts’ );

function my_site_admin_enqueue_scripts( ) {
$screen = get_current_screen();
if ( ! isset( $screen->post_type ) || ‘post_type_shows’ !== $screen->post_type ) return;

wp_enqueue_script( 'custom-js', plugins_url( '/cmb2.js' , __FILE__ ), array( 'jquery' ) );

}

And that works like this:

GIF of how it shows and hides things

Top ↑

A Word of Warning A Word of Warning

While all this is great for the sighted people, hiding things is not actually all that great for those who use screen-readers. For that you’d want to toggle the field to be disabled.