diff --git a/example-functions.php b/example-functions.php index 5ec70e449..8b074ad31 100644 --- a/example-functions.php +++ b/example-functions.php @@ -515,6 +515,48 @@ function yourprefix_register_user_profile_metabox() { } +add_action( 'cmb2_admin_init', 'yourprefix_register_taxonomy_metabox' ); +/** + * Hook in and add a metabox to add fields to taxonomy terms + */ +function yourprefix_register_taxonomy_metabox() { + $prefix = 'yourprefix_term_'; + + /** + * Metabox to add fields to categories and tags + */ + $cmb_term = new_cmb2_box( array( + 'id' => $prefix . 'edit', + 'title' => __( 'User Profile Metabox', 'cmb2' ), + 'object_types' => array( 'term' ), // Tells CMB2 to use term_meta vs post_meta + 'taxonomies' => array( 'category', 'post_tag' ), // Tells CMB2 which taxonomies should have these fields + // 'new_term_section' => true, // Will display in the "Add New Category" section + ) ); + + $cmb_term->add_field( array( + 'name' => __( 'Extra Info', 'cmb2' ), + 'desc' => __( 'field description (optional)', 'cmb2' ), + 'id' => $prefix . 'extra_info', + 'type' => 'title', + 'on_front' => false, + ) ); + + $cmb_term->add_field( array( + 'name' => __( 'Term Image', 'cmb2' ), + 'desc' => __( 'field description (optional)', 'cmb2' ), + 'id' => $prefix . 'avatar', + 'type' => 'file', + ) ); + + $cmb_term->add_field( array( + 'name' => __( 'Arbitrary Term Field', 'cmb2' ), + 'desc' => __( 'field description (optional)', 'cmb2' ), + 'id' => $prefix . 'term_text_field', + 'type' => 'text', + ) ); + +} + add_action( 'cmb2_admin_init', 'yourprefix_register_theme_options_metabox' ); /** * Hook in and register a metabox to handle a theme options page diff --git a/includes/CMB2.php b/includes/CMB2.php index 7bec5583e..923952624 100644 --- a/includes/CMB2.php +++ b/includes/CMB2.php @@ -62,22 +62,24 @@ class CMB2 { * @since 1.0.1 */ protected $mb_defaults = array( - 'id' => '', - 'title' => '', - 'type' => '', - 'object_types' => array(), // Post type - 'context' => 'normal', - 'priority' => 'high', - 'show_names' => true, // Show field names on the left - 'show_on_cb' => null, // Callback to determine if metabox should display. - 'show_on' => array(), // Post IDs or page templates to display this metabox. overrides 'show_on_cb' - 'cmb_styles' => true, // Include CMB2 stylesheet - 'enqueue_js' => true, // Include CMB2 JS - 'fields' => array(), - 'hookup' => true, - 'save_fields' => true, // Will not save during hookup if false - 'closed' => false, // Default to metabox being closed? + 'id' => '', + 'title' => '', + 'type' => '', + 'object_types' => array(), // Post type + 'context' => 'normal', + 'priority' => 'high', + 'show_names' => true, // Show field names on the left + 'show_on_cb' => null, // Callback to determine if metabox should display. + 'show_on' => array(), // Post IDs or page templates to display this metabox. overrides 'show_on_cb' + 'cmb_styles' => true, // Include CMB2 stylesheet + 'enqueue_js' => true, // Include CMB2 JS + 'fields' => array(), + 'hookup' => true, + 'save_fields' => true, // Will not save during hookup if false + 'closed' => false, // Default to metabox being closed? + 'taxonomies' => array(), 'new_user_section' => 'add-new-user', // or 'add-existing-user' + 'new_term_section' => true, ); /** @@ -637,6 +639,10 @@ public function object_id( $object_id = 0 ) { $object_id = ! $object_id && isset( $GLOBALS['comments']->comment_ID ) ? $GLOBALS['comments']->comment_ID : $object_id; break; + case 'term': + $object_id = isset( $_REQUEST['tag_ID'] ) ? $_REQUEST['tag_ID'] : $object_id; + break; + default: $object_id = isset( $GLOBALS['post']->ID ) ? $GLOBALS['post']->ID : $object_id; $object_id = isset( $_REQUEST['post'] ) ? $_REQUEST['post'] : $object_id; @@ -693,6 +699,7 @@ public function mb_object_type() { case 'user': case 'comment': + case 'term': $this->mb_object_type = $type; break; @@ -736,6 +743,9 @@ public function object_type( $object_type = '' ) { } elseif ( in_array( $pagenow, array( 'edit-comments.php', 'comment.php' ), true ) ) { $this->object_type = 'comment'; + } elseif ( 'edit-tags.php' == $pagenow ) { + $this->object_type = 'term'; + } else { $this->object_type = 'post'; } diff --git a/includes/CMB2_hookup.php b/includes/CMB2_hookup.php index 4e3c251bc..18059da06 100644 --- a/includes/CMB2_hookup.php +++ b/includes/CMB2_hookup.php @@ -41,6 +41,14 @@ class CMB2_hookup { */ protected $cmb; + + /** + * CMB taxonomies array for term meta + * @var array + * @since 2.1.3 + */ + protected $taxonomies = array(); + /** * The object type we are performing the hookup for * @var string @@ -50,14 +58,27 @@ class CMB2_hookup { public function __construct( CMB2 $cmb ) { $this->cmb = $cmb; + $this->object_type = $this->cmb->mb_object_type(); + + $this->universal_hooks(); - $this->hooks(); if ( is_admin() ) { - $this->admin_hooks(); + + switch ( $this->object_type ) { + case 'post': + return $this->post_hooks(); + case 'comment': + return $this->comment_hooks(); + case 'user': + return $this->user_hooks(); + case 'term': + return $this->term_hooks(); + } + } } - public function hooks() { + public function universal_hooks() { // Handle oembed Ajax $this->once( 'wp_ajax_cmb2_oembed_handler', array( cmb2_ajax(), 'oembed_handler' ) ); $this->once( 'wp_ajax_nopriv_cmb2_oembed_handler', array( cmb2_ajax(), 'oembed_handler' ) ); @@ -66,58 +87,87 @@ public function hooks() { add_filter( 'cmb2_show_on', array( 'CMB2_Show_Filters', $filter ), 10, 3 ); } + if ( is_admin() ) { + // register our scripts and styles for cmb + $this->once( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ), 8 ); + } } - public function admin_hooks() { - global $pagenow; + public function post_hooks() { + add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) ); + add_action( 'add_attachment', array( $this, 'save_post' ) ); + add_action( 'edit_attachment', array( $this, 'save_post' ) ); + add_action( 'save_post', array( $this, 'save_post' ), 10, 2 ); - // register our scripts and styles for cmb - $this->once( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ), 8 ); + $this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) ); + } - $this->object_type = $this->cmb->mb_object_type(); - if ( 'post' == $this->object_type ) { - add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) ); - add_action( 'add_attachment', array( $this, 'save_post' ) ); - add_action( 'edit_attachment', array( $this, 'save_post' ) ); - add_action( 'save_post', array( $this, 'save_post' ), 10, 2 ); + public function comment_hooks() { + add_action( 'add_meta_boxes_comment', array( $this, 'add_metaboxes' ) ); + add_action( 'edit_comment', array( $this, 'save_comment' ) ); - $this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) ); + $this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) ); + } - } elseif ( 'comment' == $this->object_type ) { - add_action( 'add_meta_boxes_comment', array( $this, 'add_metaboxes' ) ); - add_action( 'edit_comment', array( $this, 'save_comment' ) ); + public function user_hooks() { - $this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) ); + $priority = $this->cmb->prop( 'priority' ); - } elseif ( 'user' == $this->object_type ) { + if ( ! is_numeric( $priority ) ) { + switch ( $priority ) { - $priority = $this->cmb->prop( 'priority' ); + case 'high': + $priority = 5; + break; - if ( ! is_numeric( $priority ) ) { - switch ( $priority ) { + case 'low': + $priority = 20; + break; - case 'high': - $priority = 5; - break; + default: + $priority = 10; + break; + } + } - case 'low': - $priority = 20; - break; + add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority ); + add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority ); + add_action( 'user_new_form', array( $this, 'user_new_metabox' ), $priority ); - default: - $priority = 10; - break; - } - } + add_action( 'personal_options_update', array( $this, 'save_user' ) ); + add_action( 'edit_user_profile_update', array( $this, 'save_user' ) ); + add_action( 'user_register', array( $this, 'save_user' ) ); + } - add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority ); - add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority ); - add_action( 'user_new_form', array( $this, 'user_new_metabox' ), $priority ); + public function term_hooks() { + if ( ! function_exists( 'get_term_meta' ) || ! $this->cmb->prop( 'taxonomies' ) ) { + wp_die( __( 'Term metaboxes configuration requires a \'taxonomies\' parameter', 'cmb2' ) ); + } + + $this->taxonomies = (array) $this->cmb->prop( 'taxonomies' ); + $show_on_term_add = $this->cmb->prop( 'new_term_section' ); + + foreach ( $this->taxonomies as $taxonomy ) { + // Display our form data + add_action( "{$taxonomy}_edit_form", array( $this, 'term_metabox' ), 8, 2 ); + + $show_on_add = is_array( $show_on_term_add ) + ? in_array( $taxonomy, $show_on_term_add ) + : (bool) $show_on_term_add; + + $show_on_add = apply_filters( "cmb2_show_on_term_add_form_{$this->cmb->cmb_id}", $show_on_add, $this->cmb ); + + // Display form in add-new section (unless specified not to) + if ( $show_on_add ) { + add_action( "{$taxonomy}_add_form_fields", array( $this, 'term_metabox' ), 8, 2 ); + } - add_action( 'personal_options_update', array( $this, 'save_user' ) ); - add_action( 'edit_user_profile_update', array( $this, 'save_user' ) ); - add_action( 'user_register', array( $this, 'save_user' ) ); } + + add_action( 'created_term', array( $this, 'save_term' ), 10, 3 ); + add_action( 'edited_terms', array( $this, 'save_term' ), 10, 2 ); + + add_action( 'delete_term', array( $this, 'delete_term' ), 10, 3 ); } /** @@ -267,6 +317,30 @@ public function user_metabox() { $this->cmb->show_form( 0, 'user' ); } + /** + * Display metaboxes for a taxonomy term object + * @since 2.1.3 + */ + public function term_metabox() { + + if ( 'term' != $this->cmb->mb_object_type() ) { + return; + } + + if ( ! $this->show_on() ) { + return; + } + + if ( $this->cmb->prop( 'cmb_styles' ) ) { + self::enqueue_cmb_css(); + } + if ( $this->cmb->prop( 'enqueue_js' ) ) { + self::enqueue_cmb_js(); + } + + $this->cmb->show_form( 0, 'term' ); + } + /** * Determines if metabox should be shown in current context * @since 2.0.0 @@ -343,6 +417,42 @@ public function save_user( $user_id ) { } } + /** + * Save data from term fields + * @since 1.0.x + * @param int $term_id Term ID + * @param int $tt_id Term Taxonomy ID + * @param string $taxonomy Taxonomy + * @return null + */ + public function save_term( $term_id, $tt_id, $taxonomy = '' ) { + $taxonomy = $taxonomy ? $taxonomy : $tt_id; + + // check permissions + if ( $this->taxonomy_can_save( $taxonomy ) && $this->can_save( 'term' ) ) { + $this->cmb->save_fields( $term_id, 'term', $_POST ); + } + } + + /** + * Delete term meta when a term is deleted. + * @since 1.0.x + * @param int $term_id Term ID + * @param int $tt_id Term Taxonomy ID + * @param string $taxonomy Taxonomy + * @return null + */ + public function delete_term( $term_id, $tt_id, $taxonomy = '' ) { + if ( $this->taxonomy_can_save( $taxonomy ) ) { + + foreach ( $this->cmb->prop( 'fields' ) as $field ) { + $data_to_delete[ $field['id'] ] = ''; + } + + $this->cmb->save_fields( $term_id, 'term', $data_to_delete ); + } + } + /** * Determines if the current object is able to be saved * @since 2.0.9 @@ -362,6 +472,28 @@ public function can_save( $type = '' ) { ); } + /** + * Determine if taxonomy of term being modified is cmb2-editable. + * @since 2.1.3 + * @param string $taxonomy Taxonomy of term being modified. + * @return bool Whether taxonomy is editable. + */ + public function taxonomy_can_save( $taxonomy ) { + $taxonomy = $taxonomy ? $taxonomy : $tt_id; + + if ( empty( $this->taxonomies ) || ! in_array( $taxonomy, $this->taxonomies ) ) { + return false; + } + + $taxonomy_object = get_taxonomy( $taxonomy ); + // Can the user edit this term? + if ( ! isset( $taxonomy_object->cap ) || ! current_user_can( $taxonomy_object->cap->edit_terms ) ) { + return false; + } + + return true; + } + /** * Ensures WordPress hook only gets fired once * @since 2.0.0 diff --git a/tests/test-cmb-core.php b/tests/test-cmb-core.php index c1fc75f1f..d7cd8b082 100644 --- a/tests/test-cmb-core.php +++ b/tests/test-cmb-core.php @@ -79,22 +79,24 @@ public function setUp() { ); $this->defaults = array( - 'id' => $this->cmb_id, - 'title' => '', - 'type' => '', - 'object_types' => array(), // Post type - 'context' => 'normal', - 'priority' => 'high', - 'show_names' => true, // Show field names on the left - 'show_on' => array(), // Specific post IDs or page templates to display this metabox - 'show_on_cb' => null, // Callback to determine if metabox should display. Overrides 'show_on' - 'cmb_styles' => true, // Include cmb bundled stylesheet - 'enqueue_js' => true, // Include CMB2 JS - 'fields' => array(), - 'hookup' => true, - 'save_fields' => true, // Will not save during hookup if false - 'closed' => false, // Default to metabox being closed? + 'id' => $this->cmb_id, + 'title' => '', + 'type' => '', + 'object_types' => array(), // Post type + 'context' => 'normal', + 'priority' => 'high', + 'show_names' => true, // Show field names on the left + 'show_on' => array(), // Specific post IDs or page templates to display this metabox + 'show_on_cb' => null, // Callback to determine if metabox should display. Overrides 'show_on' + 'cmb_styles' => true, // Include cmb bundled stylesheet + 'enqueue_js' => true, // Include CMB2 JS + 'fields' => array(), + 'hookup' => true, + 'save_fields' => true, // Will not save during hookup if false + 'closed' => false, // Default to metabox being closed? + 'taxonomies' => array(), 'new_user_section' => 'add-new-user', // or 'add-existing-user' + 'new_term_section' => true, ); $this->cmb = new CMB2( $this->metabox_array ); @@ -832,4 +834,4 @@ class Test_CMB2_Exception extends Exception { public function __construct( $message = null, $code = 0, Exception $previous = null ) { parent::__construct( $message, $code ); } -} \ No newline at end of file +}