Completed
Pull Request — trunk (#838)
by Andrew
06:40
created

CMB2_hookup   D

Complexity

Total Complexity 129

Size/Duplication

Total Lines 739
Duplicated Lines 1.08 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 34.22%

Importance

Changes 0
Metric Value
dl 8
loc 739
rs 4.4444
c 0
b 0
f 0
ccs 64
cts 187
cp 0.3422
wmc 129
lcom 1
cbo 4

36 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
C universal_hooks() 0 24 7
C post_hooks() 0 39 8
A comment_hooks() 0 9 2
A user_hooks() 4 16 2
C term_hooks() 4 39 7
B register_styles() 0 17 6
A register_js() 0 10 3
A register_scripts() 0 4 1
B do_scripts() 0 24 4
B register_column_headers() 0 27 4
A column_display() 0 12 2
A return_column_display() 0 7 2
C add_context_metaboxes() 0 29 7
A context_box_title_markup_open() 0 21 2
A context_box_title_markup_close() 0 6 1
B add_metaboxes() 0 31 6
A remove_default_tax_metaboxes() 0 10 4
A close_metabox_class() 0 4 1
A metabox_callback() 0 4 2
A user_new_metabox() 0 7 3
A user_metabox() 0 3 1
A term_metabox() 0 3 1
B show_form_for_type() 0 18 5
A show_on() 0 15 1
B get_priority() 0 22 4
B save_post() 0 19 6
A save_comment() 0 8 3
A save_user() 0 6 2
A save_term() 0 8 4
A delete_term() 0 11 3
B can_save() 0 14 9
B taxonomy_can_save() 0 13 5
B maybe_enqueue_column_display_styles() 0 11 5
A enqueue_cmb_css() 0 13 3
A enqueue_cmb_js() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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
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    WebDevStudios
11
 * @license   GPL-2.0+
12
 * @link      http://webdevstudios.com
13
 */
14
class CMB2_hookup extends CMB2_Hookup_Base {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
15
16
	/**
17
	 * Only allow JS registration once
18
	 * @var   bool
19
	 * @since 2.0.7
20
	 */
21
	protected static $js_registration_done = false;
22
23
	/**
24
	 * Only allow CSS registration once
25
	 * @var   bool
26
	 * @since 2.0.7
27
	 */
28
	protected static $css_registration_done = false;
29
30
	/**
31
	 * CMB taxonomies array for term meta
32
	 * @var   array
33
	 * @since 2.2.0
34
	 */
35
	protected $taxonomies = array();
36
37
	/**
38
	 * Custom field columns.
39
	 * @var   array
40
	 * @since 2.2.2
41
	 */
42
	protected $columns = array();
43
44
	/**
45
	 * Constructor
46
	 * @since 2.0.0
47
	 * @param CMB2 $cmb The CMB2 object to hookup
48
	 */
49
	public function __construct( CMB2 $cmb ) {
50
		$this->cmb = $cmb;
51
		$this->object_type = $this->cmb->mb_object_type();
52
	}
53
54
	public function universal_hooks() {
55
		foreach ( get_class_methods( 'CMB2_Show_Filters' ) as $filter ) {
56
			add_filter( 'cmb2_show_on', array( 'CMB2_Show_Filters', $filter ), 10, 3 );
57
		}
58
59
		if ( is_admin() ) {
60
			// register our scripts and styles for cmb
61
			$this->once( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ), 8 );
62
			$this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
63
64
			$this->maybe_enqueue_column_display_styles();
65
66
			switch ( $this->object_type ) {
67
				case 'post':
68
					return $this->post_hooks();
69
				case 'comment':
70
					return $this->comment_hooks();
71
				case 'user':
72
					return $this->user_hooks();
73
				case 'term':
74
					return $this->term_hooks();
75
			}
76
		}
77
	}
78
79
	public function post_hooks() {
80
81
		// Fetch the context we set in our call.
82
		$context = ! empty( $this->cmb->prop( 'context' ) ) ? $this->cmb->prop( 'context' ) : 'normal';
83
84
		// Call the proper hook based on the context provided.
85
		switch ( $context ) {
86
87
			case 'form_top':
88
				add_action( 'edit_form_top', array( $this, 'add_context_metaboxes' ) );
89
				break;
90
91
			case 'before_permalink':
92
				add_action( 'edit_form_before_permalink', array( $this, 'add_context_metaboxes' ) );
93
				break;
94
95
			case 'after_title':
96
				add_action( 'edit_form_after_title', array( $this, 'add_context_metaboxes' ) );
97
				break;
98
99
			case 'after_editor':
100
				add_action( 'edit_form_after_editor', array( $this, 'add_context_metaboxes' ) );
101
				break;
102
103
			default:
104
				add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) );
105
		}
106
107
		add_action( 'add_attachment', array( $this, 'save_post' ) );
108
		add_action( 'edit_attachment', array( $this, 'save_post' ) );
109
		add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
110 1
111 1
		if ( $this->cmb->has_columns ) {
112 1
			foreach ( $this->cmb->prop( 'object_types' ) as $post_type ) {
113
				add_filter( "manage_{$post_type}_posts_columns", array( $this, 'register_column_headers' ) );
114
				add_action( "manage_{$post_type}_posts_custom_column", array( $this, 'column_display' ), 10, 2 );
115
			}
116 1
		}
117
	}
118 1
119
	public function comment_hooks() {
120 1
		add_action( 'add_meta_boxes_comment', array( $this, 'add_metaboxes' ) );
121 1
		add_action( 'edit_comment', array( $this, 'save_comment' ) );
122 1
123 1
		if ( $this->cmb->has_columns ) {
124 1
			add_filter( 'manage_edit-comments_columns', array( $this, 'register_column_headers' ) );
125 1
			add_action( 'manage_comments_custom_column', array( $this, 'column_display'  ), 10, 3 );
126 1
		}
127 1
	}
128 1
129
	public function user_hooks() {
130 1
		$priority = $this->get_priority();
131
132
		add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority );
133 1
		add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority );
134
		add_action( 'user_new_form', array( $this, 'user_new_metabox' ), $priority );
135 1
136
		add_action( 'personal_options_update', array( $this, 'save_user' ) );
137 1
		add_action( 'edit_user_profile_update', array( $this, 'save_user' ) );
138
		add_action( 'user_register', array( $this, 'save_user' ) );
139 1
140 1 View Code Duplication
		if ( $this->cmb->has_columns ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
141 1
			add_filter( 'manage_users_columns', array( $this, 'register_column_headers' ) );
142 1
			add_filter( 'manage_users_custom_column', array( $this, 'return_column_display'  ), 10, 3 );
143 1
		}
144 1
	}
145
146 1
	public function term_hooks() {
147
		if ( ! function_exists( 'get_term_meta' ) ) {
148 1
			wp_die( esc_html__( 'Term Metadata is a WordPress 4.4+ feature. Please upgrade your WordPress install.', 'cmb2' ) );
149 1
		}
150 1
151 1
		if ( ! $this->cmb->prop( 'taxonomies' ) ) {
152 1
			wp_die( esc_html__( 'Term metaboxes configuration requires a "taxonomies" parameter.', 'cmb2' ) );
153 1
		}
154 1
155 1
		$this->taxonomies = (array) $this->cmb->prop( 'taxonomies' );
156 1
		$show_on_term_add = $this->cmb->prop( 'new_term_section' );
157 1
		$priority         = $this->get_priority( 8 );
158 1
159 1
		foreach ( $this->taxonomies as $taxonomy ) {
160 1
			// Display our form data
161 1
			add_action( "{$taxonomy}_edit_form", array( $this, 'term_metabox' ), $priority, 2 );
162
163 1
			$show_on_add = is_array( $show_on_term_add )
164 1
				? in_array( $taxonomy, $show_on_term_add )
165 1
				: (bool) $show_on_term_add;
166 1
167
			$show_on_add = apply_filters( "cmb2_show_on_term_add_form_{$this->cmb->cmb_id}", $show_on_add, $this->cmb );
168 1
169 1
			// Display form in add-new section (unless specified not to)
170
			if ( $show_on_add ) {
171 1
				add_action( "{$taxonomy}_add_form_fields", array( $this, 'term_metabox' ), $priority, 2 );
172 1
			}
173 1
174 1 View Code Duplication
			if ( $this->cmb->has_columns ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175 1
				add_filter( "manage_edit-{$taxonomy}_columns", array( $this, 'register_column_headers' ) );
176 1
				add_filter( "manage_{$taxonomy}_custom_column", array( $this, 'return_column_display'  ), 10, 3 );
177 1
			}
178 1
		}
179
180 1
		add_action( 'created_term', array( $this, 'save_term' ), 10, 3 );
181
		add_action( 'edited_terms', array( $this, 'save_term' ), 10, 2 );
182 1
		add_action( 'delete_term', array( $this, 'delete_term' ), 10, 3 );
183 1
184
	}
185
186
	/**
187
	 * Registers styles for CMB2
188
	 * @since 2.0.7
189
	 */
190
	protected static function register_styles() {
191
		if ( self::$css_registration_done ) {
192
			return;
193
		}
194
195
		// Only use minified files if SCRIPT_DEBUG is off
196
		$min   = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
197
		$front = is_admin() ? '' : '-front';
198
		$rtl   = is_rtl() ? '-rtl' : '';
199
200
		// Filter required styles and register stylesheet
201
		$dependencies = apply_filters( 'cmb2_style_dependencies', array() );
202
		wp_register_style( 'cmb2-styles', CMB2_Utils::url( "css/cmb2{$front}{$rtl}{$min}.css" ), $dependencies );
203
		wp_register_style( 'cmb2-display-styles', CMB2_Utils::url( "css/cmb2-display{$rtl}{$min}.css" ), $dependencies );
204
205
		self::$css_registration_done = true;
206
	}
207
208
	/**
209
	 * Registers scripts for CMB2
210
	 * @since  2.0.7
211
	 */
212
	protected static function register_js() {
213
		if ( self::$js_registration_done ) {
214
			return;
215
		}
216
217
		$hook = is_admin() ? 'admin_footer' : 'wp_footer';
218
		add_action( $hook, array( 'CMB2_JS', 'enqueue' ), 8 );
219
220
		self::$js_registration_done = true;
221
	}
222
223
	/**
224
	 * Registers scripts and styles for CMB2
225
	 * @since  1.0.0
226
	 */
227
	public static function register_scripts() {
228
		self::register_styles();
229
		self::register_js();
230
	}
231
232
	/**
233
	 * Enqueues scripts and styles for CMB2 in admin_head.
234
	 * @since  1.0.0
235
	 */
236
	public function do_scripts( $hook ) {
237
		$hooks = array(
238
			'post.php',
239
			'post-new.php',
240
			'page-new.php',
241
			'page.php',
242
			'comment.php',
243
			'edit-tags.php',
244
			'term.php',
245
			'user-new.php',
246
			'profile.php',
247
			'user-edit.php',
248
		);
249
		// only pre-enqueue our scripts/styles on the proper pages
250
		// show_form_for_type will have us covered if we miss something here.
251
		if ( in_array( $hook, $hooks, true ) ) {
252
			if ( $this->cmb->prop( 'cmb_styles' ) ) {
253
				self::enqueue_cmb_css();
254
			}
255
			if ( $this->cmb->prop( 'enqueue_js' ) ) {
256
				self::enqueue_cmb_js();
257
			}
258
		}
259
	}
260
261
	/**
262
	 * Register the CMB2 field column headers.
263
	 * @since 2.2.2
264
	 */
265
	public function register_column_headers( $columns ) {
266
		$fields = $this->cmb->prop( 'fields' );
267
268
		foreach ( $fields as $key => $field ) {
269
			if ( ! isset( $field['column'] ) ) {
270
				continue;
271
			}
272
273
			$column = $field['column'];
274
275
			if ( false === $column['position'] ) {
276
277
				$columns[ $field['id'] ] = $column['name'];
278
279
			} else {
280
281
				$before = array_slice( $columns, 0, absint( $column['position'] ) );
282
				$before[ $field['id'] ] = $column['name'];
283
				$columns = $before + $columns;
284
			}
285
286
			$column['field'] = $field;
287
			$this->columns[ $field['id'] ] = $column;
288
		}
289
290
		return $columns;
291
	}
292
293
	/**
294
	 * The CMB2 field column display output.
295
	 * @since 2.2.2
296
	 */
297
	public function column_display( $column_name, $object_id ) {
298
		if ( isset( $this->columns[ $column_name ] ) ) {
299
 			$field = new CMB2_Field( array(
300
				'field_args'  => $this->columns[ $column_name ]['field'],
301
				'object_type' => $this->object_type,
302
				'object_id'   => $this->cmb->object_id( $object_id ),
303
				'cmb_id'      => $this->cmb->cmb_id,
304
			) );
305
306
			$this->cmb->get_field( $field )->render_column();
307
		}
308
	}
309
310
	/**
311
	 * Returns the column display.
312
	 * @since 2.2.2
313
	 */
314
	public function return_column_display( $empty, $custom_column, $object_id ) {
315
		ob_start();
316
		$this->column_display( $custom_column, $object_id );
317
		$column = ob_get_clean();
318
319
		return $column ? $column : $empty;
320
	}
321
322
	/**
323
	 * Output the CMB2 fields in an alternate context (not in a metabox).
324
	 * @since 2.2.4
325
	 */
326
	public function add_context_metaboxes() {
327
328
		if ( ! $this->show_on() ) {
329
			return;
330
		}
331
332
		$current_screen = get_current_screen();
333
334
		foreach ( $this->cmb->prop( 'object_types' ) as $object_type ) {
335
			$screen = convert_to_screen( $object_type );
336
337
			// If we're on the right post-type/object, stop searching...
338
			if ( isset( $screen->id ) && $screen->id === $current_screen->id ) {
339
340
				// Call our before hook.
341
				if ( ! empty( $this->cmb->prop( 'title' ) ) ) {
342
					$this::context_box_title_markup_open( $this->cmb );
343
				}
344
345
				// Show the form.
346
				$this->cmb->show_form();
347
348
				// Call our after hook.
349
				if ( ! empty( $this->cmb->prop( 'title' ) ) ) {
350 1
					$this::context_box_title_markup_close();
351 1
				}
352
			}
353 1
		}
354
	}
355
356
	/**
357
	 * The opening markup for when we include a title.
358
	 *
359
	 * @param object  $cmb  This CMB2 object
360 1
	 *
361 1
	 * @return string
362 1
	 */
363 1
	public function context_box_title_markup_open( $cmb ) {
364
365
		$title = $cmb->prop( 'title' );
366
367 1
		$screen = get_current_screen();
368
		$hidden = get_hidden_meta_boxes( $screen );
369
370
		$classes = 'postbox context-' . $cmb->prop( 'context' ) . '-box context-box ';
371
		$classes .= in_array( $cmb->cmb_id, $hidden ) ? ' hide-if-js' : '';
372
		$classes .= postbox_classes( $cmb->cmb_id, $screen->id );
373
374
		echo '<div id="' . $cmb->cmb_id . '" class="' . $classes . '">' . "\n";
375
376
			echo '<button type="button" class="handlediv button-link" aria-expanded="true">';
377
				echo '<span class="screen-reader-text">' . sprintf( __( 'Toggle panel: %s' ), $title ) . '</span>';
378
				echo '<span class="toggle-indicator" aria-hidden="true"></span>';
379
			echo '</button>';
380
381
			echo '<h2 class="hndle"><span>' . esc_attr( $title ) . '</span></h2>' . "\n";
382
			echo '<div class="inside">' . "\n";
383
	}
384
385
	/**
386
	 * The closing markup for when we include a title.
387
	 *
388
	 * @return string
389
	 */
390
	public function context_box_title_markup_close() {
391
392
		// Load the closing divs for a title box.
393
		echo '</div>' . "\n";
394
		echo '</div>' . "\n";
395
	}
396
397
	/**
398
	 * Add metaboxes (to 'post' or 'comment' object types)
399
	 * @since 1.0.0
400
	 */
401
	public function add_metaboxes() {
402
403
		if ( ! $this->show_on() ) {
404
			return;
405
		}
406
407
		/**
408
		 * To keep from registering an actual post-screen metabox,
409
		 * omit the 'title' attribute from the metabox registration array.
410
		 *
411
		 * (WordPress will not display metaboxes without titles anyway)
412
		 *
413
		 * This is a good solution if you want to output your metaboxes
414
		 * Somewhere else in the post-screen
415
		 */
416
		if ( ! $this->cmb->prop( 'title' ) ) {
417
			return;
418
		}
419
420
		foreach ( $this->cmb->prop( 'object_types' ) as $post_type ) {
421
			if ( $this->cmb->prop( 'closed' ) ) {
422
				add_filter( "postbox_classes_{$post_type}_{$this->cmb->cmb_id}", array( $this, 'close_metabox_class' ) );
423
			}
424
425
			if ( count( $this->cmb->tax_metaboxes_to_remove ) ) {
426
				$this->remove_default_tax_metaboxes( $post_type );
427
			}
428
429
			add_meta_box( $this->cmb->cmb_id, $this->cmb->prop( 'title' ), array( $this, 'metabox_callback' ), $post_type, $this->cmb->prop( 'context' ), $this->cmb->prop( 'priority' ) );
430
		}
431
	}
432
433
	/**
434
	 * Remove the specified default taxonomy metaboxes for a post-type.
435
	 * @since 2.2.3
436
	 * @param string $post_type Post type to remove the metabox for.
437
	 */
438
	protected function remove_default_tax_metaboxes( $post_type ) {
439
		foreach ( $this->cmb->tax_metaboxes_to_remove as $taxonomy ) {
440
			if ( ! taxonomy_exists( $taxonomy ) ) {
441
				continue;
442
			}
443
444
			$mb_id = is_taxonomy_hierarchical( $taxonomy ) ? "{$taxonomy}div" : "tagsdiv-{$taxonomy}";
445
			remove_meta_box( $mb_id, $post_type, 'side' );
446
		}
447
	}
448
449
	/**
450
	 * Add 'closed' class to metabox
451
	 * @since  2.0.0
452
	 * @param  array  $classes Array of classes
453
	 * @return array           Modified array of classes
454
	 */
455
	public function close_metabox_class( $classes ) {
456
		$classes[] = 'closed';
457
		return $classes;
458
	}
459
460
	/**
461
	 * Display metaboxes for a post or comment object
462
	 * @since  1.0.0
463
	 */
464
	public function metabox_callback() {
465
		$object_id = 'comment' == $this->object_type ? get_comment_ID() : get_the_ID();
466
		$this->cmb->show_form( $object_id, $this->object_type );
467
	}
468
469
	/**
470
	 * Display metaboxes for new user page
471
	 * @since  1.0.0
472
	 */
473
	public function user_new_metabox( $section ) {
0 ignored issues
show
Coding Style introduced by
user_new_metabox uses the super-global variable $_REQUEST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
474
		if ( $section == $this->cmb->prop( 'new_user_section' ) ) {
475
			$object_id = $this->cmb->object_id();
476
			$this->cmb->object_id( isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id );
477
			$this->user_metabox();
478
		}
479
	}
480
481
	/**
482
	 * Display metaboxes for a user object
483
	 * @since  1.0.0
484
	 */
485
	public function user_metabox() {
486
		$this->show_form_for_type( 'user' );
487
	}
488
489
	/**
490
	 * Display metaboxes for a taxonomy term object
491
	 * @since  2.2.0
492
	 */
493
	public function term_metabox() {
494
		$this->show_form_for_type( 'term' );
495
	}
496
497
	/**
498
	 * Display metaboxes for an object type
499
	 * @since  2.2.0
500
	 * @param  string $type Object type
501
	 * @return void
502
	 */
503
	public function show_form_for_type( $type ) {
504
		if ( $type != $this->cmb->mb_object_type() ) {
505
			return;
506
		}
507
508
		if ( ! $this->show_on() ) {
509
			return;
510
		}
511
512
		if ( $this->cmb->prop( 'cmb_styles' ) ) {
513
			self::enqueue_cmb_css();
514
		}
515
		if ( $this->cmb->prop( 'enqueue_js' ) ) {
516
			self::enqueue_cmb_js();
517
		}
518
519
		$this->cmb->show_form( 0, $type );
520
	}
521
522
	/**
523
	 * Determines if metabox should be shown in current context
524
	 * @since  2.0.0
525
	 * @return bool Whether metabox should be added/shown
526
	 */
527
	public function show_on() {
528
		// If metabox is requesting to be conditionally shown
529
		$show = $this->cmb->should_show();
530
531
		/**
532
		 * Filter to determine if metabox should show. Default is true
533
		 *
534
		 * @param array  $show          Default is true, show the metabox
535
		 * @param mixed  $meta_box_args Array of the metabox arguments
536
		 * @param mixed  $cmb           The CMB2 instance
537
		 */
538
		$show = (bool) apply_filters( 'cmb2_show_on', $show, $this->cmb->meta_box, $this->cmb );
539
540
		return $show;
541
	}
542
543
	/**
544
	 * Get the CMB priority property set to numeric hook priority.
545
	 * @since  2.2.0
546
	 * @param  integer $default Default display hook priority.
547
	 * @return integer          Hook priority.
548
	 */
549
	public function get_priority( $default = 10 ) {
550
		$priority = $this->cmb->prop( 'priority' );
551
552
		if ( ! is_numeric( $priority ) ) {
553
			switch ( $priority ) {
554
555
				case 'high':
556
					$priority = 5;
557
					break;
558
559
				case 'low':
560
					$priority = 20;
561
					break;
562
563
				default:
564
					$priority = $default;
565
					break;
566
			}
567
		}
568
569
		return $priority;
570
	}
571
572
	/**
573
	 * Save data from post metabox
574
	 * @since  1.0.0
575
	 * @param  int    $post_id Post ID
576
	 * @param  mixed  $post    Post object
577
	 * @return null
578
	 */
579
	public function save_post( $post_id, $post = false ) {
0 ignored issues
show
Coding Style introduced by
save_post uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
580
581
		$post_type = $post ? $post->post_type : get_post_type( $post_id );
582
583
		$do_not_pass_go = (
584
			! $this->can_save( $post_type )
585
			// check user editing permissions
586
			|| ( 'page' == $post_type && ! current_user_can( 'edit_page', $post_id ) )
587
			|| ! current_user_can( 'edit_post', $post_id )
588
		);
589
590
		if ( $do_not_pass_go ) {
591
			// do not collect $200
592
			return;
593
		}
594
595
		// take a trip to reading railroad – if you pass go collect $200
596
		$this->cmb->save_fields( $post_id, 'post', $_POST );
597
	}
598
599
	/**
600
	 * Save data from comment metabox
601
	 * @since  2.0.9
602
	 * @param  int    $comment_id Comment ID
603
	 * @return null
604
	 */
605
	public function save_comment( $comment_id ) {
0 ignored issues
show
Coding Style introduced by
save_comment uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
606
607
		$can_edit = current_user_can( 'moderate_comments', $comment_id );
608
609
		if ( $this->can_save( get_comment_type( $comment_id ) ) && $can_edit ) {
610
			$this->cmb->save_fields( $comment_id, 'comment', $_POST );
611
		}
612
	}
613
614
	/**
615
	 * Save data from user fields
616
	 * @since  1.0.x
617
	 * @param  int   $user_id  User ID
618
	 * @return null
619
	 */
620
	public function save_user( $user_id ) {
0 ignored issues
show
Coding Style introduced by
save_user uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
621
		// check permissions
622
		if ( $this->can_save( 'user' ) ) {
623
			$this->cmb->save_fields( $user_id, 'user', $_POST );
624
		}
625
	}
626
627
	/**
628
	 * Save data from term fields
629
	 * @since  2.2.0
630
	 * @param  int    $term_id  Term ID
631
	 * @param  int    $tt_id    Term Taxonomy ID
632
	 * @param  string $taxonomy Taxonomy
633
	 * @return null
634
	 */
635
	public function save_term( $term_id, $tt_id, $taxonomy = '' ) {
0 ignored issues
show
Coding Style introduced by
save_term uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
636
		$taxonomy = $taxonomy ? $taxonomy : $tt_id;
637
638
		// check permissions
639
		if ( $this->taxonomy_can_save( $taxonomy ) && $this->can_save( 'term' ) ) {
640
			$this->cmb->save_fields( $term_id, 'term', $_POST );
641
		}
642
	}
643
644
	/**
645
	 * Delete term meta when a term is deleted.
646
	 * @since  2.2.0
647
	 * @param  int    $term_id  Term ID
648
	 * @param  int    $tt_id    Term Taxonomy ID
649
	 * @param  string $taxonomy Taxonomy
650
	 * @return null
651
	 */
652
	public function delete_term( $term_id, $tt_id, $taxonomy = '' ) {
653
		if ( $this->taxonomy_can_save( $taxonomy ) ) {
654
655
			$data_to_delete = array();
656
			foreach ( $this->cmb->prop( 'fields' ) as $field ) {
657
				$data_to_delete[ $field['id'] ] = '';
658
			}
659
660
			$this->cmb->save_fields( $term_id, 'term', $data_to_delete );
661
		}
662
	}
663
664
	/**
665
	 * Determines if the current object is able to be saved
666
	 * @since  2.0.9
667
	 * @param  string  $type Current post_type or comment_type
668
	 * @return bool          Whether object can be saved
669
	 */
670
	public function can_save( $type = '' ) {
0 ignored issues
show
Coding Style introduced by
can_save uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
671
		return apply_filters( 'cmb2_can_save', (
672
			$this->cmb->prop( 'save_fields' )
673
			// check nonce
674
			&& isset( $_POST[ $this->cmb->nonce() ] )
675
			&& wp_verify_nonce( $_POST[ $this->cmb->nonce() ], $this->cmb->nonce() )
676
			// check if autosave
677
			&& ! ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
678
			// get the metabox types & compare it to this type
679
			&& ( $type && in_array( $type, $this->cmb->prop( 'object_types' ) ) )
680
			// Don't do updates during a switch-to-blog instance.
681
			&& ! ( is_multisite() && ms_is_switched() )
682
		) );
683
	}
684
685
	/**
686
	 * Determine if taxonomy of term being modified is cmb2-editable.
687
	 * @since  2.2.0
688
	 * @param  string $taxonomy Taxonomy of term being modified.
689
	 * @return bool             Whether taxonomy is editable.
690
	 */
691
	public function taxonomy_can_save( $taxonomy ) {
692
		if ( empty( $this->taxonomies ) || ! in_array( $taxonomy, $this->taxonomies ) ) {
693
			return false;
694
		}
695
696
		$taxonomy_object = get_taxonomy( $taxonomy );
697
		// Can the user edit this term?
698
		if ( ! isset( $taxonomy_object->cap ) || ! current_user_can( $taxonomy_object->cap->edit_terms ) ) {
699
			return false;
700
		}
701
702
		return true;
703
	}
704
705
	/**
706
	 * Enqueues the 'cmb2-display-styles' if the conditions match (has columns, on the right page, etc).
707
	 * @since  2.2.2.1
708
	 */
709
	protected function maybe_enqueue_column_display_styles() {
710
		global $pagenow;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
711
		if (
712
			$pagenow
713
			&& $this->cmb->has_columns
714
			&& $this->cmb->prop( 'cmb_styles' )
715
			&& in_array( $pagenow, array( 'edit.php', 'users.php', 'edit-comments.php', 'edit-tags.php' ), 1 )
716
			) {
717
			self::enqueue_cmb_css( 'cmb2-display-styles' );
718
		}
719
	}
720
721
	/**
722
	 * Includes CMB2 styles
723
	 * @since  2.0.0
724
	 */
725
	public static function enqueue_cmb_css( $handle = 'cmb2-styles' ) {
726
		if ( ! apply_filters( 'cmb2_enqueue_css', true ) ) {
727
			return false;
728
		}
729
730
		self::register_styles();
731
732
		/*
733
		 * White list the options as this method can be used as a hook callback
734
		 * and have a different argument passed.
735
		 */
736
		return wp_enqueue_style( 'cmb2-display-styles' === $handle ? $handle : 'cmb2-styles' );
737
	}
738
739
	/**
740
	 * Includes CMB2 JS
741
	 * @since  2.0.0
742
	 */
743
	public static function enqueue_cmb_js() {
744
		if ( ! apply_filters( 'cmb2_enqueue_js', true ) ) {
745
			return false;
746
		}
747
748
		self::register_js();
749
		return true;
750
	}
751
752
}
753