| Total Complexity | 162 | 
| Total Lines | 1001 | 
| Duplicated Lines | 0 % | 
| Changes | 1 | ||
| Bugs | 0 | Features | 0 | 
Complex classes like CMB2_Hookup often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CMB2_Hookup, and based on these observations, apply Extract Interface, too.
| 1 | <?php | ||
| 14 | class CMB2_Hookup extends CMB2_Hookup_Base { | ||
| 15 | |||
| 16 | /** | ||
| 17 | * Only allow JS registration once | ||
| 18 | * | ||
| 19 | * @var bool | ||
| 20 | * @since 2.0.7 | ||
| 21 | */ | ||
| 22 | protected static $js_registration_done = false; | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Only allow CSS registration once | ||
| 26 | * | ||
| 27 | * @var bool | ||
| 28 | * @since 2.0.7 | ||
| 29 | */ | ||
| 30 | protected static $css_registration_done = false; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * CMB taxonomies array for term meta | ||
| 34 | * | ||
| 35 | * @var array | ||
| 36 | * @since 2.2.0 | ||
| 37 | */ | ||
| 38 | protected $taxonomies = array(); | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Custom field columns. | ||
| 42 | * | ||
| 43 | * @var array | ||
| 44 | * @since 2.2.2 | ||
| 45 | */ | ||
| 46 | protected $columns = array(); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Array of CMB2_Options_Hookup instances if options page metabox. | ||
| 50 | * | ||
| 51 | * @var CMB2_Options_Hookup[]|null | ||
| 52 | * @since 2.2.5 | ||
| 53 | */ | ||
| 54 | protected $options_hookup = null; | ||
| 55 | |||
| 56 | /** | ||
| 57 | * A functionalized constructor, used for the hookup action callbacks. | ||
| 58 | * | ||
| 59 | * @since 2.2.6 | ||
| 60 | * | ||
| 61 | * @param CMB2 $cmb The CMB2 object to hookup. | ||
| 62 | * | ||
| 63 | * @return CMB2_Hookup_Base $hookup The hookup object. | ||
| 64 | */ | ||
| 65 | 	public static function maybe_init_and_hookup( CMB2 $cmb ) { | ||
| 66 | 		if ( $cmb->prop( 'hookup' ) ) { | ||
| 67 | |||
| 68 | $hookup = new self( $cmb ); | ||
| 69 | |||
| 70 | // Hook in the hookup... how meta. | ||
| 71 | return $hookup->universal_hooks(); | ||
| 72 | } | ||
| 73 | |||
| 74 | return false; | ||
| 75 | } | ||
| 76 | |||
| 77 | 	public function universal_hooks() { | ||
| 78 | 		foreach ( get_class_methods( 'CMB2_Show_Filters' ) as $filter ) { | ||
| 79 | add_filter( 'cmb2_show_on', array( 'CMB2_Show_Filters', $filter ), 10, 3 ); | ||
| 80 | } | ||
| 81 | |||
| 82 | 		if ( is_admin() ) { | ||
| 83 | // Register our scripts and styles for cmb. | ||
| 84 | $this->once( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ), 8 ); | ||
| 85 | $this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) ); | ||
| 86 | |||
| 87 | $this->maybe_enqueue_column_display_styles(); | ||
| 88 | |||
| 89 | 			switch ( $this->object_type ) { | ||
| 90 | case 'post': | ||
| 91 | return $this->post_hooks(); | ||
| 92 | case 'comment': | ||
| 93 | return $this->comment_hooks(); | ||
| 94 | case 'user': | ||
| 95 | return $this->user_hooks(); | ||
| 96 | case 'term': | ||
| 97 | return $this->term_hooks(); | ||
| 98 | case 'options-page': | ||
| 99 | return $this->options_page_hooks(); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | return $this; | ||
| 104 | } | ||
| 105 | |||
| 106 | 	public function post_hooks() { | ||
| 107 | |||
| 108 | // Fetch the context we set in our call. | ||
| 109 | $context = $this->cmb->prop( 'context' ) ? $this->cmb->prop( 'context' ) : 'normal'; | ||
| 110 | |||
| 111 | // Call the proper hook based on the context provided. | ||
| 112 | 		switch ( $context ) { | ||
| 113 | |||
| 114 | case 'form_top': | ||
| 115 | add_action( 'edit_form_top', array( $this, 'add_context_metaboxes' ) ); | ||
| 116 | break; | ||
| 117 | |||
| 118 | case 'before_permalink': | ||
| 119 | add_action( 'edit_form_before_permalink', array( $this, 'add_context_metaboxes' ) ); | ||
| 120 | break; | ||
| 121 | |||
| 122 | case 'after_title': | ||
| 123 | add_action( 'edit_form_after_title', array( $this, 'add_context_metaboxes' ) ); | ||
| 124 | break; | ||
| 125 | |||
| 126 | case 'after_editor': | ||
| 127 | add_action( 'edit_form_after_editor', array( $this, 'add_context_metaboxes' ) ); | ||
| 128 | break; | ||
| 129 | |||
| 130 | default: | ||
| 131 | add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) ); | ||
| 132 | } | ||
| 133 | |||
| 134 | add_action( 'add_meta_boxes', array( $this, 'remove_default_tax_metaboxes' ) ); | ||
| 135 | add_action( 'add_attachment', array( $this, 'save_post' ) ); | ||
| 136 | add_action( 'edit_attachment', array( $this, 'save_post' ) ); | ||
| 137 | add_action( 'save_post', array( $this, 'save_post' ), 10, 2 ); | ||
| 138 | |||
| 139 | 		if ( $this->cmb->has_columns ) { | ||
| 140 | 			foreach ( $this->cmb->box_types() as $post_type ) { | ||
| 141 | 				add_filter( "manage_{$post_type}_posts_columns", array( $this, 'register_column_headers' ) ); | ||
| 142 | 				add_action( "manage_{$post_type}_posts_custom_column", array( $this, 'column_display' ), 10, 2 ); | ||
| 143 | 				add_filter( "manage_edit-{$post_type}_sortable_columns", array( $this, 'columns_sortable' ) ); | ||
| 144 | add_action( 'pre_get_posts', array( $this, 'columns_sortable_orderby' ) ); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | return $this; | ||
| 149 | } | ||
| 150 | |||
| 151 | 	public function comment_hooks() { | ||
| 152 | add_action( 'add_meta_boxes_comment', array( $this, 'add_metaboxes' ) ); | ||
| 153 | add_action( 'edit_comment', array( $this, 'save_comment' ) ); | ||
| 154 | |||
| 155 | 		if ( $this->cmb->has_columns ) { | ||
| 156 | add_filter( 'manage_edit-comments_columns', array( $this, 'register_column_headers' ) ); | ||
| 157 | add_action( 'manage_comments_custom_column', array( $this, 'column_display' ), 10, 3 ); | ||
| 158 | add_filter( "manage_edit-comments_sortable_columns", array( $this, 'columns_sortable' ) ); | ||
| 159 | add_action( 'pre_get_posts', array( $this, 'columns_sortable_orderby' ) ); | ||
| 160 | } | ||
| 161 | |||
| 162 | return $this; | ||
| 163 | } | ||
| 164 | |||
| 165 | 	public function user_hooks() { | ||
| 166 | $priority = $this->get_priority(); | ||
| 167 | |||
| 168 | add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority ); | ||
| 169 | add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority ); | ||
| 170 | add_action( 'user_new_form', array( $this, 'user_new_metabox' ), $priority ); | ||
| 171 | |||
| 172 | add_action( 'personal_options_update', array( $this, 'save_user' ) ); | ||
| 173 | add_action( 'edit_user_profile_update', array( $this, 'save_user' ) ); | ||
| 174 | add_action( 'user_register', array( $this, 'save_user' ) ); | ||
| 175 | |||
| 176 | 		if ( $this->cmb->has_columns ) { | ||
| 177 | add_filter( 'manage_users_columns', array( $this, 'register_column_headers' ) ); | ||
| 178 | add_filter( 'manage_users_custom_column', array( $this, 'return_column_display' ), 10, 3 ); | ||
| 179 | add_filter( "manage_users_sortable_columns", array( $this, 'columns_sortable' ) ); | ||
| 180 | add_action( 'pre_get_posts', array( $this, 'columns_sortable_orderby' ) ); | ||
| 181 | } | ||
| 182 | |||
| 183 | return $this; | ||
| 184 | } | ||
| 185 | |||
| 186 | 	public function term_hooks() { | ||
| 187 | 		if ( ! function_exists( 'get_term_meta' ) ) { | ||
| 188 | wp_die( esc_html__( 'Term Metadata is a WordPress 4.4+ feature. Please upgrade your WordPress install.', 'cmb2' ) ); | ||
| 189 | } | ||
| 190 | |||
| 191 | 		if ( ! $this->cmb->prop( 'taxonomies' ) ) { | ||
| 192 | wp_die( esc_html__( 'Term metaboxes configuration requires a "taxonomies" parameter.', 'cmb2' ) ); | ||
| 193 | } | ||
| 194 | |||
| 195 | $this->taxonomies = (array) $this->cmb->prop( 'taxonomies' ); | ||
| 196 | $show_on_term_add = $this->cmb->prop( 'new_term_section' ); | ||
| 197 | $priority = $this->get_priority( 8 ); | ||
| 198 | |||
| 199 | 		foreach ( $this->taxonomies as $taxonomy ) { | ||
| 200 | // Display our form data. | ||
| 201 | 			add_action( "{$taxonomy}_edit_form", array( $this, 'term_metabox' ), $priority, 2 ); | ||
| 202 | |||
| 203 | $show_on_add = is_array( $show_on_term_add ) | ||
| 204 | ? in_array( $taxonomy, $show_on_term_add ) | ||
| 205 | : (bool) $show_on_term_add; | ||
| 206 | |||
| 207 | /** | ||
| 208 | * Filter to determine if the term's fields should show in the "Add term" section. | ||
| 209 | * | ||
| 210 | * The dynamic portion of the hook name, $cmb_id, is the metabox id. | ||
| 211 | * | ||
| 212 | * @param bool $show_on_add Default is the value of the new_term_section cmb parameter. | ||
| 213 | * @param object $cmb The CMB2 instance | ||
| 214 | */ | ||
| 215 | 			$show_on_add = apply_filters( "cmb2_show_on_term_add_form_{$this->cmb->cmb_id}", $show_on_add, $this->cmb ); | ||
| 216 | |||
| 217 | // Display form in add-new section (unless specified not to). | ||
| 218 | 			if ( $show_on_add ) { | ||
| 219 | 				add_action( "{$taxonomy}_add_form_fields", array( $this, 'term_metabox' ), $priority, 2 ); | ||
| 220 | } | ||
| 221 | |||
| 222 | 			if ( $this->cmb->has_columns ) { | ||
| 223 | 				add_filter( "manage_edit-{$taxonomy}_columns", array( $this, 'register_column_headers' ) ); | ||
| 224 | 				add_filter( "manage_{$taxonomy}_custom_column", array( $this, 'return_column_display' ), 10, 3 ); | ||
| 225 | 				add_filter( "manage_edit-{$taxonomy}_sortable_columns", array( $this, 'columns_sortable' ) ); | ||
| 226 | add_action( 'pre_get_posts', array( $this, 'columns_sortable_orderby' ) ); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | add_action( 'created_term', array( $this, 'save_term' ), 10, 3 ); | ||
| 231 | add_action( 'edited_terms', array( $this, 'save_term' ), 10, 2 ); | ||
| 232 | add_action( 'delete_term', array( $this, 'delete_term' ), 10, 3 ); | ||
| 233 | |||
| 234 | return $this; | ||
| 235 | } | ||
| 236 | |||
| 237 | 	public function options_page_hooks() { | ||
| 238 | $option_keys = $this->cmb->options_page_keys(); | ||
| 239 | |||
| 240 | 		if ( ! empty( $option_keys ) ) { | ||
| 241 | 			foreach ( $option_keys as $option_key ) { | ||
| 242 | $this->options_hookup[ $option_key ] = new CMB2_Options_Hookup( $this->cmb, $option_key ); | ||
| 243 | $this->options_hookup[ $option_key ]->hooks(); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | return $this; | ||
| 248 | } | ||
| 249 | |||
| 250 | /** | ||
| 251 | * Registers styles for CMB2 | ||
| 252 | * | ||
| 253 | * @since 2.0.7 | ||
| 254 | */ | ||
| 255 | 	protected static function register_styles() { | ||
| 256 | 		if ( self::$css_registration_done ) { | ||
| 257 | return; | ||
| 258 | } | ||
| 259 | |||
| 260 | // Only use minified files if SCRIPT_DEBUG is off. | ||
| 261 | $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; | ||
| 262 | $front = is_admin() ? '' : '-front'; | ||
| 263 | $rtl = is_rtl() ? '-rtl' : ''; | ||
| 264 | |||
| 265 | /** | ||
| 266 | * Filters the registered style dependencies for the cmb2 stylesheet. | ||
| 267 | * | ||
| 268 | * @param array $dependencies The registered style dependencies for the cmb2 stylesheet. | ||
| 269 | */ | ||
| 270 | $dependencies = apply_filters( 'cmb2_style_dependencies', array() ); | ||
| 271 | 		wp_register_style( 'cmb2-styles', CMB2_Utils::url( "css/cmb2{$front}{$rtl}{$min}.css" ), $dependencies ); | ||
| 272 | 		wp_register_style( 'cmb2-display-styles', CMB2_Utils::url( "css/cmb2-display{$rtl}{$min}.css" ), $dependencies ); | ||
| 273 | |||
| 274 | self::$css_registration_done = true; | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * Registers scripts for CMB2 | ||
| 279 | * | ||
| 280 | * @since 2.0.7 | ||
| 281 | */ | ||
| 282 | 	protected static function register_js() { | ||
| 283 | 		if ( self::$js_registration_done ) { | ||
| 284 | return; | ||
| 285 | } | ||
| 286 | |||
| 287 | $hook = is_admin() ? 'admin_footer' : 'wp_footer'; | ||
| 288 | add_action( $hook, array( 'CMB2_JS', 'enqueue' ), 8 ); | ||
| 289 | |||
| 290 | self::$js_registration_done = true; | ||
| 291 | } | ||
| 292 | |||
| 293 | /** | ||
| 294 | * Registers scripts and styles for CMB2 | ||
| 295 | * | ||
| 296 | * @since 1.0.0 | ||
| 297 | */ | ||
| 298 | 	public static function register_scripts() { | ||
| 299 | self::register_styles(); | ||
| 300 | self::register_js(); | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | ||
| 304 | * Enqueues scripts and styles for CMB2 in admin_head. | ||
| 305 | * | ||
| 306 | * @since 1.0.0 | ||
| 307 | * | ||
| 308 | * @param string $hook Current hook for the admin page. | ||
| 309 | */ | ||
| 310 | 	public function do_scripts( $hook ) { | ||
| 311 | $hooks = array( | ||
| 312 | 'post.php', | ||
| 313 | 'post-new.php', | ||
| 314 | 'page-new.php', | ||
| 315 | 'page.php', | ||
| 316 | 'comment.php', | ||
| 317 | 'edit-tags.php', | ||
| 318 | 'term.php', | ||
| 319 | 'user-new.php', | ||
| 320 | 'profile.php', | ||
| 321 | 'user-edit.php', | ||
| 322 | ); | ||
| 323 | // only pre-enqueue our scripts/styles on the proper pages | ||
| 324 | // show_form_for_type will have us covered if we miss something here. | ||
| 325 | 		if ( in_array( $hook, $hooks, true ) ) { | ||
| 326 | 			if ( $this->cmb->prop( 'cmb_styles' ) ) { | ||
| 327 | self::enqueue_cmb_css(); | ||
| 328 | } | ||
| 329 | 			if ( $this->cmb->prop( 'enqueue_js' ) ) { | ||
| 330 | self::enqueue_cmb_js(); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | /** | ||
| 336 | * Register the CMB2 field column headers. | ||
| 337 | * | ||
| 338 | * @since 2.2.2 | ||
| 339 | * | ||
| 340 | * @param array $columns Array of columns available for the admin page. | ||
| 341 | */ | ||
| 342 | 	public function register_column_headers( $columns ) { | ||
| 343 | 		foreach ( $this->cmb->prop( 'fields' ) as $key => $field ) { | ||
| 344 | 			if ( empty( $field['column'] ) ) { | ||
| 345 | continue; | ||
| 346 | } | ||
| 347 | |||
| 348 | $column = $field['column']; | ||
| 349 | |||
| 350 | 			if ( false === $column['position'] ) { | ||
| 351 | $columns[ $field['id'] ] = $column['name']; | ||
| 352 | 			} else { | ||
| 353 | $before = array_slice( $columns, 0, absint( $column['position'] ) ); | ||
| 354 | $before[ $field['id'] ] = $column['name']; | ||
| 355 | $columns = $before + $columns; | ||
| 356 | } | ||
| 357 | |||
| 358 | $column['field'] = $field; | ||
| 359 | $this->columns[ $field['id'] ] = $column; | ||
| 360 | } | ||
| 361 | |||
| 362 | return $columns; | ||
| 363 | } | ||
| 364 | |||
| 365 | /** | ||
| 366 | * The CMB2 field column display output. | ||
| 367 | * | ||
| 368 | * @since 2.2.2 | ||
| 369 | * | ||
| 370 | * @param string $column_name Current column name. | ||
| 371 | * @param mixed $object_id Current object ID. | ||
| 372 | */ | ||
| 373 | 	public function column_display( $column_name, $object_id ) { | ||
| 374 | 		if ( isset( $this->columns[ $column_name ] ) ) { | ||
| 375 | $field = new CMB2_Field( array( | ||
| 376 | 'field_args' => $this->columns[ $column_name ]['field'], | ||
| 377 | 'object_type' => $this->object_type, | ||
| 378 | 'object_id' => $this->cmb->object_id( $object_id ), | ||
| 379 | 'cmb_id' => $this->cmb->cmb_id, | ||
| 380 | ) ); | ||
| 381 | |||
| 382 | $this->cmb->get_field( $field )->render_column(); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | /** | ||
| 387 | * Returns the columns sortable array. | ||
| 388 | * | ||
| 389 | * @since 2.6.1 | ||
| 390 | * | ||
| 391 | * @param array $columns An array of sortable columns. | ||
| 392 | * | ||
| 393 | * @return array $columns An array of sortable columns with CMB2 columns. | ||
| 394 | */ | ||
| 395 | 	public function columns_sortable( $columns ) { | ||
| 396 | 		foreach ( $this->cmb->prop( 'fields' ) as $key => $field ) { | ||
| 397 | 			if ( ! empty( $field['column'] ) && empty( $field['column']['disable_sortable'] ) ) { | ||
| 398 | $columns[ $field['id'] ] = $field['id']; | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | return $columns; | ||
| 403 | } | ||
| 404 | |||
| 405 | /** | ||
| 406 | * Return the query object to order by custom columns if selected | ||
| 407 | * | ||
| 408 | * @since 2.6.1 | ||
| 409 | * | ||
| 410 | * @param object $query Object query from WordPress | ||
| 411 | * | ||
| 412 | * @return void | ||
| 413 | */ | ||
| 414 | 	public function columns_sortable_orderby( $query ) { | ||
| 415 | 		if ( ! is_admin() ) { | ||
| 416 | return; | ||
| 417 | } | ||
| 418 | |||
| 419 | $orderby = $query->get( 'orderby' ); | ||
| 420 | |||
| 421 | 		foreach ( $this->cmb->prop( 'fields' ) as $key => $field ) { | ||
| 422 | if ( | ||
| 423 | empty( $field['column'] ) | ||
| 424 | || ! empty( $field['column']['disable_sortable'] ) | ||
| 425 | || $field['id'] !== $orderby | ||
| 426 | 			) { | ||
| 427 | continue; | ||
| 428 | } | ||
| 429 | |||
| 430 | $query->set( 'meta_key', $field['id'] ); | ||
| 431 | |||
| 432 | $type = $field['type']; | ||
| 433 | |||
| 434 | 			if ( ! empty( $field['attributes']['type'] ) ) { | ||
| 435 | 				switch ( $field['attributes']['type'] ) { | ||
| 436 | case 'number': | ||
| 437 | case 'date': | ||
| 438 | $type = $field['attributes']['type']; | ||
| 439 | break; | ||
| 440 | case 'range': | ||
| 441 | $type = 'number'; | ||
| 442 | break; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | |||
| 446 | 			switch ( $type ) { | ||
| 447 | case 'number': | ||
| 448 | case 'text_date_timestamp': | ||
| 449 | case 'text_datetime_timestamp': | ||
| 450 | case 'text_money': | ||
| 451 | $query->set( 'orderby', 'meta_value_num' ); | ||
| 452 | break; | ||
| 453 | case 'text_time': | ||
| 454 | $query->set( 'orderby', 'meta_value_time' ); | ||
| 455 | break; | ||
| 456 | case 'text_date': | ||
| 457 | $query->set( 'orderby', 'meta_value_date' ); | ||
| 458 | break; | ||
| 459 | |||
| 460 | default: | ||
| 461 | $query->set( 'orderby', 'meta_value' ); | ||
| 462 | break; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | /** | ||
| 468 | * Returns the column display. | ||
| 469 | * | ||
| 470 | * @since 2.2.2 | ||
| 471 | */ | ||
| 472 | 	public function return_column_display( $empty, $custom_column, $object_id ) { | ||
| 473 | ob_start(); | ||
| 474 | $this->column_display( $custom_column, $object_id ); | ||
| 475 | $column = ob_get_clean(); | ||
| 476 | |||
| 477 | return $column ? $column : $empty; | ||
| 478 | } | ||
| 479 | |||
| 480 | /** | ||
| 481 | * Output the CMB2 box/fields in an alternate context (not in a standard metabox area). | ||
| 482 | * | ||
| 483 | * @since 2.2.4 | ||
| 484 | */ | ||
| 485 | 	public function add_context_metaboxes() { | ||
| 486 | |||
| 487 | 		if ( ! $this->show_on() ) { | ||
| 488 | return; | ||
| 489 | } | ||
| 490 | |||
| 491 | $page = get_current_screen()->id; | ||
| 492 | |||
| 493 | 		foreach ( $this->cmb->box_types() as $object_type ) { | ||
| 494 | $screen = convert_to_screen( $object_type ); | ||
| 495 | |||
| 496 | // If we're on the right post-type/object... | ||
| 497 | 			if ( isset( $screen->id ) && $screen->id === $page ) { | ||
| 498 | |||
| 499 | // Show the box. | ||
| 500 | $this->output_context_metabox(); | ||
| 501 | } | ||
| 502 | } | ||
| 503 | } | ||
| 504 | |||
| 505 | /** | ||
| 506 | * Output the CMB2 box/fields in an alternate context (not in a standard metabox area). | ||
| 507 | * | ||
| 508 | * @since 2.2.4 | ||
| 509 | */ | ||
| 510 | 	public function output_context_metabox() { | ||
| 511 | $title = $this->cmb->prop( 'title' ); | ||
| 512 | |||
| 513 | /* | ||
| 514 | * To keep from outputting the open/close markup, do not include | ||
| 515 | * a 'title' property in your metabox registration array. | ||
| 516 | * | ||
| 517 | * To output the fields 'naked' (without a postbox wrapper/style), then | ||
| 518 | * add a `'remove_box_wrap' => true` to your metabox registration array. | ||
| 519 | */ | ||
| 520 | $add_wrap = ! empty( $title ) || ! $this->cmb->prop( 'remove_box_wrap' ); | ||
| 521 | $add_handle = $add_wrap && ! empty( $title ); | ||
| 522 | |||
| 523 | // Open the context-box wrap. | ||
| 524 | $this->context_box_title_markup_open( $add_handle ); | ||
| 525 | |||
| 526 | // Show the form fields. | ||
| 527 | $this->cmb->show_form(); | ||
| 528 | |||
| 529 | // Close the context-box wrap. | ||
| 530 | $this->context_box_title_markup_close( $add_handle ); | ||
| 531 | } | ||
| 532 | |||
| 533 | /** | ||
| 534 | * Output the opening markup for a context box. | ||
| 535 | * | ||
| 536 | * @since 2.2.4 | ||
| 537 | * @param bool $add_handle Whether to add the metabox handle and opening div for .inside. | ||
| 538 | */ | ||
| 539 | 	public function context_box_title_markup_open( $add_handle = true ) { | ||
| 540 | $title = $this->cmb->prop( 'title' ); | ||
| 541 | |||
| 542 | $page = get_current_screen()->id; | ||
| 543 | 		add_filter( "postbox_classes_{$page}_{$this->cmb->cmb_id}", array( $this, 'postbox_classes' ) ); | ||
| 544 | |||
| 545 | echo '<div id="' . $this->cmb->cmb_id . '" class="' . postbox_classes( $this->cmb->cmb_id, $page ) . '">' . "\n"; | ||
| 546 | |||
| 547 | 		if ( $add_handle ) { | ||
| 548 | |||
| 549 | echo '<button type="button" class="handlediv button-link" aria-expanded="true">'; | ||
| 550 | echo '<span class="screen-reader-text">' . sprintf( __( 'Toggle panel: %s' ), $title ) . '</span>'; | ||
| 551 | echo '<span class="toggle-indicator" aria-hidden="true"></span>'; | ||
| 552 | echo '</button>'; | ||
| 553 | |||
| 554 | echo '<h2 class="hndle"><span>' . esc_attr( $title ) . '</span></h2>' . "\n"; | ||
| 555 | echo '<div class="inside">' . "\n"; | ||
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | /** | ||
| 560 | * Output the closing markup for a context box. | ||
| 561 | * | ||
| 562 | * @since 2.2.4 | ||
| 563 | * @param bool $add_inside_close Whether to add closing div for .inside. | ||
| 564 | */ | ||
| 565 | 	public function context_box_title_markup_close( $add_inside_close = true ) { | ||
| 566 | |||
| 567 | // Load the closing divs for a title box. | ||
| 568 | 		if ( $add_inside_close ) { | ||
| 569 | echo '</div>' . "\n"; // .inside | ||
| 570 | } | ||
| 571 | |||
| 572 | echo '</div>' . "\n"; // .context-box | ||
| 573 | } | ||
| 574 | |||
| 575 | /** | ||
| 576 | * Add metaboxes (to 'post' or 'comment' object types) | ||
| 577 | * | ||
| 578 | * @since 1.0.0 | ||
| 579 | */ | ||
| 580 | 	public function add_metaboxes() { | ||
| 581 | |||
| 582 | 		if ( ! $this->show_on() ) { | ||
| 583 | return; | ||
| 584 | } | ||
| 585 | |||
| 586 | /* | ||
| 587 | * To keep from registering an actual post-screen metabox, | ||
| 588 | * omit the 'title' property from the metabox registration array. | ||
| 589 | * | ||
| 590 | * (WordPress will not display metaboxes without titles anyway) | ||
| 591 | * | ||
| 592 | * This is a good solution if you want to handle outputting your | ||
| 593 | * metaboxes/fields elsewhere in the post-screen. | ||
| 594 | */ | ||
| 595 | 		if ( ! $this->cmb->prop( 'title' ) ) { | ||
| 596 | return; | ||
| 597 | } | ||
| 598 | |||
| 599 | $page = get_current_screen()->id; | ||
| 600 | 		add_filter( "postbox_classes_{$page}_{$this->cmb->cmb_id}", array( $this, 'postbox_classes' ) ); | ||
| 601 | |||
| 602 | 		foreach ( $this->cmb->box_types() as $object_type ) { | ||
| 603 | add_meta_box( | ||
| 604 | $this->cmb->cmb_id, | ||
| 605 | $this->cmb->prop( 'title' ), | ||
| 606 | array( $this, 'metabox_callback' ), | ||
| 607 | $object_type, | ||
| 608 | $this->cmb->prop( 'context' ), | ||
| 609 | $this->cmb->prop( 'priority' ), | ||
| 610 | $this->cmb->prop( 'mb_callback_args' ) | ||
| 611 | ); | ||
| 612 | } | ||
| 613 | } | ||
| 614 | |||
| 615 | /** | ||
| 616 | * Remove the specified default taxonomy metaboxes for a post-type. | ||
| 617 | * | ||
| 618 | * @since 2.2.3 | ||
| 619 | * | ||
| 620 | */ | ||
| 621 | 	public function remove_default_tax_metaboxes() { | ||
| 622 | $to_remove = array_filter( (array) $this->cmb->tax_metaboxes_to_remove, 'taxonomy_exists' ); | ||
| 623 | 		if ( empty( $to_remove ) ) { | ||
| 624 | return; | ||
| 625 | } | ||
| 626 | |||
| 627 | 		foreach ( $this->cmb->box_types() as $post_type ) { | ||
| 628 | 			foreach ( $to_remove as $taxonomy ) { | ||
| 629 | 				$mb_id = is_taxonomy_hierarchical( $taxonomy ) ? "{$taxonomy}div" : "tagsdiv-{$taxonomy}"; | ||
| 630 | remove_meta_box( $mb_id, $post_type, 'side' ); | ||
| 631 | } | ||
| 632 | } | ||
| 633 | } | ||
| 634 | |||
| 635 | /** | ||
| 636 | * Modify metabox postbox classes. | ||
| 637 | * | ||
| 638 | * @since 2.2.4 | ||
| 639 | * @param array $classes Array of classes. | ||
| 640 | * @return array Modified array of classes | ||
| 641 | */ | ||
| 642 | 	public function postbox_classes( $classes ) { | ||
| 643 | 		if ( $this->cmb->prop( 'closed' ) && ! in_array( 'closed', $classes ) ) { | ||
| 644 | $classes[] = 'closed'; | ||
| 645 | } | ||
| 646 | |||
| 647 | 		if ( $this->cmb->is_alternate_context_box() ) { | ||
| 648 | $classes = $this->alternate_context_postbox_classes( $classes ); | ||
| 649 | 		} else { | ||
| 650 | $classes[] = 'cmb2-postbox'; | ||
| 651 | } | ||
| 652 | |||
| 653 | return $classes; | ||
| 654 | } | ||
| 655 | |||
| 656 | /** | ||
| 657 | * Modify metabox altnernate context postbox classes. | ||
| 658 | * | ||
| 659 | * @since 2.2.4 | ||
| 660 | * @param array $classes Array of classes. | ||
| 661 | * @return array Modified array of classes | ||
| 662 | */ | ||
| 663 | 	protected function alternate_context_postbox_classes( $classes ) { | ||
| 664 | $classes[] = 'context-box'; | ||
| 665 | $classes[] = 'context-' . $this->cmb->prop( 'context' ) . '-box'; | ||
| 666 | |||
| 667 | 		if ( in_array( $this->cmb->cmb_id, get_hidden_meta_boxes( get_current_screen() ) ) ) { | ||
| 668 | $classes[] = 'hide-if-js'; | ||
| 669 | } | ||
| 670 | |||
| 671 | $add_wrap = $this->cmb->prop( 'title' ) || ! $this->cmb->prop( 'remove_box_wrap' ); | ||
| 672 | |||
| 673 | 		if ( $add_wrap ) { | ||
| 674 | $classes[] = 'cmb2-postbox postbox'; | ||
| 675 | 		} else { | ||
| 676 | $classes[] = 'cmb2-no-box-wrap'; | ||
| 677 | } | ||
| 678 | |||
| 679 | return $classes; | ||
| 680 | } | ||
| 681 | |||
| 682 | /** | ||
| 683 | * Display metaboxes for a post or comment object. | ||
| 684 | * | ||
| 685 | * @since 1.0.0 | ||
| 686 | */ | ||
| 687 | 	public function metabox_callback() { | ||
| 688 | $object_id = 'comment' === $this->object_type ? get_comment_ID() : get_the_ID(); | ||
| 689 | $this->cmb->show_form( $object_id, $this->object_type ); | ||
| 690 | } | ||
| 691 | |||
| 692 | /** | ||
| 693 | * Display metaboxes for new user page. | ||
| 694 | * | ||
| 695 | * @since 1.0.0 | ||
| 696 | * | ||
| 697 | * @param mixed $section User section metabox. | ||
| 698 | */ | ||
| 699 | 	public function user_new_metabox( $section ) { | ||
| 700 | 		if ( $section === $this->cmb->prop( 'new_user_section' ) ) { | ||
| 701 | $object_id = $this->cmb->object_id(); | ||
| 702 | $this->cmb->object_id( isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id ); | ||
| 703 | $this->user_metabox(); | ||
| 704 | } | ||
| 705 | } | ||
| 706 | |||
| 707 | /** | ||
| 708 | * Display metaboxes for a user object. | ||
| 709 | * | ||
| 710 | * @since 1.0.0 | ||
| 711 | */ | ||
| 712 | 	public function user_metabox() { | ||
| 713 | $this->show_form_for_type( 'user' ); | ||
| 714 | } | ||
| 715 | |||
| 716 | /** | ||
| 717 | * Display metaboxes for a taxonomy term object. | ||
| 718 | * | ||
| 719 | * @since 2.2.0 | ||
| 720 | */ | ||
| 721 | 	public function term_metabox() { | ||
| 722 | $this->show_form_for_type( 'term' ); | ||
| 723 | } | ||
| 724 | |||
| 725 | /** | ||
| 726 | * Display metaboxes for an object type. | ||
| 727 | * | ||
| 728 | * @since 2.2.0 | ||
| 729 | * @param string $type Object type. | ||
| 730 | * @return void | ||
| 731 | */ | ||
| 732 | 	public function show_form_for_type( $type ) { | ||
| 733 | 		if ( $type != $this->object_type ) { | ||
| 734 | return; | ||
| 735 | } | ||
| 736 | |||
| 737 | 		if ( ! $this->show_on() ) { | ||
| 738 | return; | ||
| 739 | } | ||
| 740 | |||
| 741 | 		if ( $this->cmb->prop( 'cmb_styles' ) ) { | ||
| 742 | self::enqueue_cmb_css(); | ||
| 743 | } | ||
| 744 | 		if ( $this->cmb->prop( 'enqueue_js' ) ) { | ||
| 745 | self::enqueue_cmb_js(); | ||
| 746 | } | ||
| 747 | |||
| 748 | $this->cmb->show_form( 0, $type ); | ||
| 749 | } | ||
| 750 | |||
| 751 | /** | ||
| 752 | * Determines if metabox should be shown in current context. | ||
| 753 | * | ||
| 754 | * @since 2.0.0 | ||
| 755 | * @return bool Whether metabox should be added/shown. | ||
| 756 | */ | ||
| 757 | 	public function show_on() { | ||
| 758 | // If metabox is requesting to be conditionally shown. | ||
| 759 | $show = $this->cmb->should_show(); | ||
| 760 | |||
| 761 | /** | ||
| 762 | * Filter to determine if metabox should show. Default is true. | ||
| 763 | * | ||
| 764 | * @param array $show Default is true, show the metabox. | ||
| 765 | * @param mixed $meta_box_args Array of the metabox arguments. | ||
| 766 | * @param mixed $cmb The CMB2 instance. | ||
| 767 | */ | ||
| 768 | $show = (bool) apply_filters( 'cmb2_show_on', $show, $this->cmb->meta_box, $this->cmb ); | ||
| 769 | |||
| 770 | return $show; | ||
| 771 | } | ||
| 772 | |||
| 773 | /** | ||
| 774 | * Get the CMB priority property set to numeric hook priority. | ||
| 775 | * | ||
| 776 | * @since 2.2.0 | ||
| 777 | * | ||
| 778 | * @param integer $default Default display hook priority. | ||
| 779 | * @return integer Hook priority. | ||
| 780 | */ | ||
| 781 | 	public function get_priority( $default = 10 ) { | ||
| 782 | $priority = $this->cmb->prop( 'priority' ); | ||
| 783 | |||
| 784 | 		if ( ! is_numeric( $priority ) ) { | ||
| 785 | 			switch ( $priority ) { | ||
| 786 | |||
| 787 | case 'high': | ||
| 788 | $priority = 5; | ||
| 789 | break; | ||
| 790 | |||
| 791 | case 'low': | ||
| 792 | $priority = 20; | ||
| 793 | break; | ||
| 794 | |||
| 795 | default: | ||
| 796 | $priority = $default; | ||
| 797 | break; | ||
| 798 | } | ||
| 799 | } | ||
| 800 | |||
| 801 | return $priority; | ||
| 802 | } | ||
| 803 | |||
| 804 | /** | ||
| 805 | * Save data from post metabox | ||
| 806 | * | ||
| 807 | * @since 1.0.0 | ||
| 808 | * @param int $post_id Post ID. | ||
| 809 | * @param mixed $post Post object. | ||
| 810 | * @return void | ||
| 811 | */ | ||
| 812 | 	public function save_post( $post_id, $post = false ) { | ||
| 813 | |||
| 814 | $post_type = $post ? $post->post_type : get_post_type( $post_id ); | ||
| 815 | |||
| 816 | $do_not_pass_go = ( | ||
| 817 | ! $this->can_save( $post_type ) | ||
| 818 | // Check user editing permissions. | ||
| 819 | || ( 'page' === $post_type && ! current_user_can( 'edit_page', $post_id ) ) | ||
| 820 | || ! current_user_can( 'edit_post', $post_id ) | ||
| 821 | ); | ||
| 822 | |||
| 823 | 		if ( $do_not_pass_go ) { | ||
| 824 | return; | ||
| 825 | } | ||
| 826 | |||
| 827 | $this->cmb->save_fields( $post_id, 'post', $_POST ); | ||
| 828 | } | ||
| 829 | |||
| 830 | /** | ||
| 831 | * Save data from comment metabox. | ||
| 832 | * | ||
| 833 | * @since 2.0.9 | ||
| 834 | * @param int $comment_id Comment ID. | ||
| 835 | * @return void | ||
| 836 | */ | ||
| 837 | 	public function save_comment( $comment_id ) { | ||
| 838 | |||
| 839 | $can_edit = current_user_can( 'moderate_comments', $comment_id ); | ||
| 840 | |||
| 841 | 		if ( $this->can_save( get_comment_type( $comment_id ) ) && $can_edit ) { | ||
| 842 | $this->cmb->save_fields( $comment_id, 'comment', $_POST ); | ||
| 843 | } | ||
| 844 | } | ||
| 845 | |||
| 846 | /** | ||
| 847 | * Save data from user fields. | ||
| 848 | * | ||
| 849 | * @since 1.0.x | ||
| 850 | * @param int $user_id User ID. | ||
| 851 | * @return void | ||
| 852 | */ | ||
| 853 | 	public function save_user( $user_id ) { | ||
| 854 | // check permissions. | ||
| 855 | 		if ( $this->can_save( 'user' ) ) { | ||
| 856 | $this->cmb->save_fields( $user_id, 'user', $_POST ); | ||
| 857 | } | ||
| 858 | } | ||
| 859 | |||
| 860 | /** | ||
| 861 | * Save data from term fields | ||
| 862 | * | ||
| 863 | * @since 2.2.0 | ||
| 864 | * @param int $term_id Term ID. | ||
| 865 | * @param int $tt_id Term Taxonomy ID. | ||
| 866 | * @param string $taxonomy Taxonomy. | ||
| 867 | * @return void | ||
| 868 | */ | ||
| 869 | 	public function save_term( $term_id, $tt_id, $taxonomy = '' ) { | ||
| 870 | $taxonomy = $taxonomy ? $taxonomy : $tt_id; | ||
| 871 | |||
| 872 | // check permissions. | ||
| 873 | 		if ( $this->taxonomy_can_save( $taxonomy ) && $this->can_save( 'term' ) ) { | ||
| 874 | $this->cmb->save_fields( $term_id, 'term', $_POST ); | ||
| 875 | } | ||
| 876 | } | ||
| 877 | |||
| 878 | /** | ||
| 879 | * Delete term meta when a term is deleted. | ||
| 880 | * | ||
| 881 | * @since 2.2.0 | ||
| 882 | * @param int $term_id Term ID. | ||
| 883 | * @param int $tt_id Term Taxonomy ID. | ||
| 884 | * @param string $taxonomy Taxonomy. | ||
| 885 | * @return void | ||
| 886 | */ | ||
| 887 | 	public function delete_term( $term_id, $tt_id, $taxonomy = '' ) { | ||
| 888 | 		if ( $this->taxonomy_can_save( $taxonomy ) ) { | ||
| 889 | |||
| 890 | $data_to_delete = array(); | ||
| 891 | 			foreach ( $this->cmb->prop( 'fields' ) as $field ) { | ||
| 892 | $data_to_delete[ $field['id'] ] = ''; | ||
| 893 | } | ||
| 894 | |||
| 895 | $this->cmb->save_fields( $term_id, 'term', $data_to_delete ); | ||
| 896 | } | ||
| 897 | } | ||
| 898 | |||
| 899 | /** | ||
| 900 | * Determines if the current object is able to be saved. | ||
| 901 | * | ||
| 902 | * @since 2.0.9 | ||
| 903 | * @param string $type Current object type. | ||
| 904 | * @return bool Whether object can be saved. | ||
| 905 | */ | ||
| 906 | 	public function can_save( $type = '' ) { | ||
| 907 | |||
| 908 | $can_save = ( | ||
| 909 | $this->cmb->prop( 'save_fields' ) | ||
| 910 | // check nonce. | ||
| 911 | && isset( $_POST[ $this->cmb->nonce() ] ) | ||
| 912 | && wp_verify_nonce( $_POST[ $this->cmb->nonce() ], $this->cmb->nonce() ) | ||
| 913 | // check if autosave. | ||
| 914 | && ! ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) | ||
| 915 | // get the metabox types & compare it to this type. | ||
| 916 | && ( $type && in_array( $type, $this->cmb->box_types() ) ) | ||
| 917 | // Don't do updates during a switch-to-blog instance. | ||
| 918 | && ! ( is_multisite() && ms_is_switched() ) | ||
| 919 | ); | ||
| 920 | |||
| 921 | /** | ||
| 922 | * Filter to determine if metabox is allowed to save. | ||
| 923 | * | ||
| 924 | * @param bool $can_save Whether the current metabox can save. | ||
| 925 | * @param object $cmb The CMB2 instance. | ||
| 926 | */ | ||
| 927 | return apply_filters( 'cmb2_can_save', $can_save, $this->cmb ); | ||
| 928 | } | ||
| 929 | |||
| 930 | /** | ||
| 931 | * Determine if taxonomy of term being modified is cmb2-editable. | ||
| 932 | * | ||
| 933 | * @since 2.2.0 | ||
| 934 | * | ||
| 935 | * @param string $taxonomy Taxonomy of term being modified. | ||
| 936 | * @return bool Whether taxonomy is editable. | ||
| 937 | */ | ||
| 938 | 	public function taxonomy_can_save( $taxonomy ) { | ||
| 939 | 		if ( empty( $this->taxonomies ) || ! in_array( $taxonomy, $this->taxonomies ) ) { | ||
| 940 | return false; | ||
| 941 | } | ||
| 942 | |||
| 943 | $taxonomy_object = get_taxonomy( $taxonomy ); | ||
| 944 | // Can the user edit this term? | ||
| 945 | 		if ( ! isset( $taxonomy_object->cap ) || ! current_user_can( $taxonomy_object->cap->edit_terms ) ) { | ||
| 946 | return false; | ||
| 947 | } | ||
| 948 | |||
| 949 | return true; | ||
| 950 | } | ||
| 951 | |||
| 952 | /** | ||
| 953 | * Enqueues the 'cmb2-display-styles' if the conditions match (has columns, on the right page, etc). | ||
| 954 | * | ||
| 955 | * @since 2.2.2.1 | ||
| 956 | */ | ||
| 957 | 	protected function maybe_enqueue_column_display_styles() { | ||
| 958 | global $pagenow; | ||
| 959 | if ( | ||
| 960 | $pagenow | ||
| 961 | && $this->cmb->has_columns | ||
| 962 | && $this->cmb->prop( 'cmb_styles' ) | ||
| 963 | && in_array( $pagenow, array( 'edit.php', 'users.php', 'edit-comments.php', 'edit-tags.php' ), 1 ) | ||
| 964 | 			) { | ||
| 965 | self::enqueue_cmb_css( 'cmb2-display-styles' ); | ||
| 966 | } | ||
| 967 | } | ||
| 968 | |||
| 969 | /** | ||
| 970 | * Includes CMB2 styles. | ||
| 971 | * | ||
| 972 | * @since 2.0.0 | ||
| 973 | * | ||
| 974 | * @param string $handle CSS handle. | ||
| 975 | * @return mixed | ||
| 976 | */ | ||
| 977 | 	public static function enqueue_cmb_css( $handle = 'cmb2-styles' ) { | ||
| 978 | |||
| 979 | /** | ||
| 980 | * Filter to determine if CMB2'S css should be enqueued. | ||
| 981 | * | ||
| 982 | * @param bool $enqueue_css Default is true. | ||
| 983 | */ | ||
| 984 | 		if ( ! apply_filters( 'cmb2_enqueue_css', true ) ) { | ||
| 985 | return false; | ||
| 986 | } | ||
| 987 | |||
| 988 | self::register_styles(); | ||
| 989 | |||
| 990 | /* | ||
| 991 | * White list the options as this method can be used as a hook callback | ||
| 992 | * and have a different argument passed. | ||
| 993 | */ | ||
| 994 | return wp_enqueue_style( 'cmb2-display-styles' === $handle ? $handle : 'cmb2-styles' ); | ||
| 995 | } | ||
| 996 | |||
| 997 | /** | ||
| 998 | * Includes CMB2 JS. | ||
| 999 | * | ||
| 1000 | * @since 2.0.0 | ||
| 1001 | */ | ||
| 1002 | 	public static function enqueue_cmb_js() { | ||
| 1003 | |||
| 1004 | /** | ||
| 1005 | * Filter to determine if CMB2'S JS should be enqueued. | ||
| 1006 | * | ||
| 1007 | * @param bool $enqueue_js Default is true. | ||
| 1008 | */ | ||
| 1009 | 		if ( ! apply_filters( 'cmb2_enqueue_js', true ) ) { | ||
| 1010 | return false; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | self::register_js(); | ||
| 1014 | return true; | ||
| 1015 | } | ||
| 1018 |