Using Chosen + Custom Meta Boxes

Lately I’ve been using Custom Meta Boxes for use with custom post types. CMB makes programmatically adding specific custom fields to your posts very simple - as simple as filling out an array. The following example adds a WYSIWYG ‘sidebar’ field to posts, pages, and events (a custom post type):

<?php
// get CMB library here: https://github.com/jaredatch/Custom-Metaboxes-and-Fields-for-WordPress
function kd_example_sidebar_metaboxes( $meta_boxes ) {
$meta_boxes[] = array(
'id' => 'sidebar_metabox',
'title' => 'Sidebar', //this is the metabox, the field container.
'pages' => array('page','post','event'), // post type
'context' => 'normal',
'priority' => 'high',
'show_names' => false,
'fields' => array( //this array contains the fields inside the container.
array(
'name' => 'Sidebar',
'id' => 'sidebar',
'type' => 'wysiwyg',
'options' => array(
'textarea_rows' => 3,
)
),
)
);
return $meta_boxes;
} add_filter( 'cmb_meta_boxes', 'kd_example_sidebar_metaboxes' );

You do need to include the CMB code, though -but that’s also easy. Just change the path to the correct location.

<?php
// Initialize the metabox class
function be_initialize_cmb_meta_boxes() {
if ( !class_exists( 'cmb_Meta_Box' ) ) {
require_once( 'libs/cmb-library/init.php' );
}
} add_action( 'init', 'be_initialize_cmb_meta_boxes', 9999 );

These snippets above came from a theme’s functions.php, though CMB can also be used in plugins (as my next example). Perhaps the above would be better if it were moved into a must-use plugin - maybe that’ll be my next improvement. In any case, as awesome as the above is, it gets better: see how in the sidebar field I say 'type' => 'wysiwyg'? There are plenty of field types to choose from, but you can also very easily create your own.

Getting to the point: creating a taxonomy field using Chosen


I came across Helen Hou-Sandí’s Using Chosen for a replacement taxonomy metabox & decided to see if I could get it to work with CMB. First, run through this tutorial for adding custom field types to CMB. You’ll see the last example is actually a taxonomy list - so between these two, most of my work was already done for me.

Below I’ve created an example plugin to add categories to posts using Chosen. The first few lines of the KD_Example_Class are setting that up - you could easily switch $taxonomy = 'category'; to $taxonomy = 'post_tag'; if you wanted to do this for tags, or switch $post_type to your CPT[1].

The first thing to do is create the render function. We’ll call our field type 'chosen_taxonomy'. We want to be taxonomy-independent, so we’re going to pass 'taxonomy' into the render function via $fields. We’ll initialize Chosen & build our dropdown, Chosen will do the rest automatically (see more detail about this step in Helen’s post).

Next we need to make sure this new field is saved along with the post, so we’ll do that it in the validation function. wp_set_object_terms attaches the terms in our defined taxonomy to the post ID, meaning we can use this on any post type & taxonomy.

The only issue I encountered was that I want to warn about is that for initial testing of my example plugin, I still had the original plugin I wrote all this for active - which conflicted because there were two functions for rendering & saving 'chosen_taxonomy' - so if you want to use this for multiple taxonomies & post types, you’ll need to either edit the functions, or rename them to be more specific (like, 'chosen_post_category' or something).

So far I haven’t discussed the includes() function. That one is setting up the chosen.js to only be used on the edit or add screen, and only when the post type matches.

<?php
/**
* Plugin Name: KD Example!
* Version: v0.1
* Author: Kelly Dwan
* Author URI: http://redradar.net/
* Description: Using Chosen + Custom Meta Boxes
*/
class KD_Example_Class {
protected $prefix = 'kd_example_';
protected $post_type = 'post';
protected $taxonomy = 'category';
public function __construct() {
add_action( 'admin_enqueue_scripts', array( $this, 'includes'), 10, 1 );
add_action( 'init', array( $this, 'initialize_cmb_meta_boxes' ), 9999 );
add_filter( 'cmb_render_chosen_taxonomy', array( $this, 'render_chosen_taxonomy' ), 10, 2 );
add_filter( 'cmb_validate_chosen_taxonomy', array( $this, 'validate_chosen_taxonomy' ), 10, 3 );
add_filter( 'cmb_meta_boxes', array( $this, 'add_meta_boxes' ) );
add_action( 'do_meta_boxes', array($this, 'remove_meta_boxes'), 10, 3 );
}
/**
* Add chosen to the edit screen for our new Item CPT
*/
public function includes($hook){
global $post;
if ( $hook == 'post-new.php' || $hook == 'post.php' ) {
if ( $this->post_type === $post->post_type ) {
wp_enqueue_script( 'chosen', plugins_url('libs/chosen/chosen.jquery.min.js',__FILE__), array( 'jquery' ), '1.0' );
wp_enqueue_style( 'chosen', plugins_url('libs/chosen/chosen.css',__FILE__) );
}
}
}
// Initialize the metabox class
function initialize_cmb_meta_boxes() {
if ( !class_exists( 'cmb_Meta_Box' ) ) {
require_once( 'libs/cmb-library/init.php' );
}
}
function render_chosen_taxonomy( $field, $meta ) {
global $post;?>
<script type="text/javascript">
jQuery(document).ready(function($){
$( '.chzn-select' ).chosen();
});
</script><?php
echo '<select name="', $field['id'], '[]" id="', $field['id'], '" class="chzn-select widefat" multiple>';
$current_terms = wp_get_post_terms ( $post->ID, $field['taxonomy'], array('fields' => 'ids') );
$terms = get_terms( $field['taxonomy'], 'hide_empty=0' );
foreach ( $terms as $term ) {
?>
<option value="<?php echo $term->slug; ?>"<?php selected( in_array( $term->term_id, $current_terms ) ); ?>><?php echo $term->name; ?></option>
<?php
}
echo '</select>';
echo '<p class="cmb_metabox_description">', $field['desc'], '</p>';
}
function validate_chosen_taxonomy( $new, $post_id, $field ) {
return wp_set_object_terms( $post_id, $new, $field['taxonomy'] );
}
function add_meta_boxes( $meta_boxes ) {
$meta_boxes[] = array(
'id' => $this->prefix.'item_metabox',
'title' => 'Information',
'pages' => array($this->post_type),
'context' => 'normal',
'priority' => 'high',
'show_names' => true, // Show field names on the left
'fields' => array(
array(
'name' => 'Categories',
'id' => 'chosen_'.$this->taxonomy,
'type' => 'chosen_taxonomy',
'taxonomy' => $this->taxonomy
),
)
);
return $meta_boxes;
}
/**
* Since we're adding the Menu taxonomy in the CMB 'Info' box, we should hide the default tax box
* I also generally hide the custom fields box when using CMB, because I don't want extra fields created.
*/
function remove_meta_boxes( $post_type, $priority, $post ) {
remove_meta_box( $this->taxonomy.'div', $this->post_type, 'side' ); // remove tax box
remove_meta_box( 'postcustom', $this->post_type, 'normal'); // remove custom fields
}
}
new KD_Example_Class;

[1] One thing you can’t do, is switch $taxonomy to an array… not even if you foreach over $field[‘taxonomy’]… you end up creating categories for all your selected tags, and tags for all your selected categories. Oops:

Leave a Reply

%d bloggers like this: