PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 8.0.3
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v8.0.3
8.0.4 8.0.3 8.0.1 8.0.2 8.0.0 7.9.9.7 7.9.9.6 7.9.9.5 7.9.9.4 7.9.9.3 7.9.9.2 7.9.9.1 7.9.9 7.9.8 7.9.7 7.9.6 7.9.5 7.9.4 7.9.3 7.9.2 7.9.1 7.9.0 7.8.9 7.8.8 7.8.7 All 46 releases
gamipress / libraries / cmb2 / includes / CMB2_Hookup.php

CMB2_Hookup.php in GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI 8.0.3, at libraries/cmb2/includes/CMB2_Hookup.php

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