Completed
Push — trunk ( 3f68b1...7f1fb9 )
by Justin
05:50
created

CMB2_hookup::universal_hooks()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 10
ccs 0
cts 8
cp 0
rs 9.4285
cc 3
eloc 5
nc 4
nop 0
crap 12
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 {
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
	 * Array of all hooks done (to be run once)
18
	 * @var   array
19
	 * @since 2.0.0
20
	 */
21
	protected static $hooks_completed = array();
22
23
	/**
24
	 * Only allow JS registration once
25
	 * @var   bool
26
	 * @since 2.0.7
27
	 */
28
	protected static $js_registration_done = false;
29
30
	/**
31
	 * Only allow CSS registration once
32
	 * @var   bool
33
	 * @since 2.0.7
34
	 */
35
	protected static $css_registration_done = false;
36
37
	/**
38
	 * @var   CMB2 object
39
	 * @since 2.0.2
40
	 */
41
	protected $cmb;
42
43
	/**
44
	 * CMB taxonomies array for term meta
45
	 * @var   array
46
	 * @since 2.2.0
47
	 */
48
	protected $taxonomies = array();
49
50
	/**
51
	 * The object type we are performing the hookup for
52
	 * @var   string
53
	 * @since 2.0.9
54
	 */
55
	protected $object_type = 'post';
56
57
	public function __construct( CMB2 $cmb ) {
58
		$this->cmb = $cmb;
59
		$this->object_type = $this->cmb->mb_object_type();
60
61
		$this->universal_hooks();
62
63
		if ( is_admin() ) {
64
65
			switch ( $this->object_type ) {
66
				case 'post':
67
					return $this->post_hooks();
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
68
				case 'comment':
69
					return $this->comment_hooks();
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
70
				case 'user':
71
					return $this->user_hooks();
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
72
				case 'term':
73
					return $this->term_hooks();
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
74
			}
75
76
		}
77
	}
78
79
	public function universal_hooks() {
80
		foreach ( get_class_methods( 'CMB2_Show_Filters' ) as $filter ) {
81
			add_filter( 'cmb2_show_on', array( 'CMB2_Show_Filters', $filter ), 10, 3 );
82
		}
83
84
		if ( is_admin() ) {
85
			// register our scripts and styles for cmb
86
			$this->once( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ), 8 );
87
		}
88
	}
89
90
	public function post_hooks() {
91
		add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) );
92
		add_action( 'add_attachment', array( $this, 'save_post' ) );
93
		add_action( 'edit_attachment', array( $this, 'save_post' ) );
94
		add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
95
96
		$this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
97
	}
98
99
	public function comment_hooks() {
100
		add_action( 'add_meta_boxes_comment', array( $this, 'add_metaboxes' ) );
101
		add_action( 'edit_comment', array( $this, 'save_comment' ) );
102
103
		$this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
104
	}
105
106
	public function user_hooks() {
107
		$priority = $this->get_priority();
108
109
		add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority );
110
		add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority );
111
		add_action( 'user_new_form', array( $this, 'user_new_metabox' ), $priority );
112
113
		add_action( 'personal_options_update', array( $this, 'save_user' ) );
114
		add_action( 'edit_user_profile_update', array( $this, 'save_user' ) );
115
		add_action( 'user_register', array( $this, 'save_user' ) );
116
	}
117
118
	public function term_hooks() {
119
		if ( ! function_exists( 'get_term_meta' ) ) {
120
			wp_die( __( 'Term Metadata is a WordPress > 4.4 feature. Please upgrade your WordPress install.', 'cmb2' ) );
121
		}
122
123
		if ( ! $this->cmb->prop( 'taxonomies' ) ) {
124
			wp_die( __( 'Term metaboxes configuration requires a \'taxonomies\' parameter', 'cmb2' ) );
125
		}
126
127
		$this->taxonomies = (array) $this->cmb->prop( 'taxonomies' );
128
		$show_on_term_add = $this->cmb->prop( 'new_term_section' );
129
		$priority         = $this->get_priority( 8 );
130
131
		foreach ( $this->taxonomies as $taxonomy ) {
132
			// Display our form data
133
			add_action( "{$taxonomy}_edit_form", array( $this, 'term_metabox' ), $priority, 2 );
134
135
			$show_on_add = is_array( $show_on_term_add )
136
				? in_array( $taxonomy, $show_on_term_add )
137
				: (bool) $show_on_term_add;
138
139
			$show_on_add = apply_filters( "cmb2_show_on_term_add_form_{$this->cmb->cmb_id}", $show_on_add, $this->cmb );
140
141
			// Display form in add-new section (unless specified not to)
142
			if ( $show_on_add ) {
143
				add_action( "{$taxonomy}_add_form_fields", array( $this, 'term_metabox' ), $priority, 2 );
144
			}
145
146
		}
147
148
		add_action( 'created_term', array( $this, 'save_term' ), 10, 3 );
149
		add_action( 'edited_terms', array( $this, 'save_term' ), 10, 2 );
150
151
		add_action( 'delete_term', array( $this, 'delete_term' ), 10, 3 );
152
	}
153
154
	/**
155
	 * Registers styles for CMB2
156
	 * @since 2.0.7
157
	 */
158 1
	protected static function register_styles() {
159 1
		if ( self::$css_registration_done ) {
160
			return;
161
		}
162
163
		// Only use minified files if SCRIPT_DEBUG is off
164 1
		$min   = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
165 1
		$front = is_admin() ? '' : '-front';
166 1
		$rtl = is_rtl() ? '-rtl' : '';
167
168
		// Filter required styles and register stylesheet
169 1
		$styles = apply_filters( 'cmb2_style_dependencies', array() );
170 1
		wp_register_style( 'cmb2-styles', cmb2_utils()->url( "css/cmb2{$front}{$rtl}{$min}.css" ), $styles );
171
172 1
		self::$css_registration_done = true;
173 1
	}
174
175
	/**
176
	 * Registers scripts for CMB2
177
	 * @since  2.0.7
178
	 */
179 1
	protected static function register_js() {
180 1
		if ( self::$js_registration_done ) {
181
			return;
182
		}
183
184 1
		$hook = is_admin() ? 'admin_footer' : 'wp_footer';
185 1
		add_action( $hook, array( 'CMB2_JS', 'enqueue' ), 8 );
186
187 1
		self::$js_registration_done = true;
188 1
	}
189
190
	/**
191
	 * Registers scripts and styles for CMB2
192
	 * @since  1.0.0
193
	 */
194
	public static function register_scripts() {
195
		self::register_styles();
196
		self::register_js();
197
	}
198
199
	/**
200
	 * Enqueues scripts and styles for CMB2
201
	 * @since  1.0.0
202
	 */
203
	public function do_scripts( $hook ) {
204
		// only enqueue our scripts/styles on the proper pages
205
		if ( in_array( $hook, array( 'post.php', 'post-new.php', 'page-new.php', 'page.php', 'comment.php' ), true ) ) {
206
			if ( $this->cmb->prop( 'cmb_styles' ) ) {
207
				self::enqueue_cmb_css();
208
			}
209
			if ( $this->cmb->prop( 'enqueue_js' ) ) {
210
				self::enqueue_cmb_js();
211
			}
212
		}
213
	}
214
215
	/**
216
	 * Add metaboxes (to 'post' or 'comment' object types)
217
	 * @since 1.0.0
218
	 */
219
	public function add_metaboxes() {
220
221
		if ( ! $this->show_on() ) {
222
			return;
223
		}
224
225
		foreach ( $this->cmb->prop( 'object_types' ) as $post_type ) {
226
			/**
227
			 * To keep from registering an actual post-screen metabox,
228
			 * omit the 'title' attribute from the metabox registration array.
229
			 *
230
			 * (WordPress will not display metaboxes without titles anyway)
231
			 *
232
			 * This is a good solution if you want to output your metaboxes
233
			 * Somewhere else in the post-screen
234
			 */
235
			if ( $this->cmb->prop( 'title' ) ) {
236
237
				if ( $this->cmb->prop( 'closed' ) ) {
238
					add_filter( "postbox_classes_{$post_type}_{$this->cmb->cmb_id}", array( $this, 'close_metabox_class' ) );
239
				}
240
241
				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' ) );
242
			}
243
		}
244
	}
245
246
	/**
247
	 * Add 'closed' class to metabox
248
	 * @since  2.0.0
249
	 * @param  array  $classes Array of classes
250
	 * @return array           Modified array of classes
251
	 */
252
	public function close_metabox_class( $classes ) {
253
		$classes[] = 'closed';
254
		return $classes;
255
	}
256
257
	/**
258
	 * Display metaboxes for a post or comment object
259
	 * @since  1.0.0
260
	 */
261
	public function metabox_callback() {
262
		$object_id = 'comment' == $this->object_type ? get_comment_ID() : get_the_ID();
263
		$this->cmb->show_form( $object_id, $this->object_type );
264
	}
265
266
	/**
267
	 * Display metaboxes for new user page
268
	 * @since  1.0.0
269
	 */
270
	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...
271
		if ( $section == $this->cmb->prop( 'new_user_section' ) ) {
272
			$object_id = $this->cmb->object_id();
273
			$this->cmb->object_id( isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id );
274
			$this->user_metabox();
275
		}
276
	}
277
278
	/**
279
	 * Display metaboxes for a user object
280
	 * @since  1.0.0
281
	 */
282
	public function user_metabox() {
283
		$this->show_form_for_type( 'user' );
284
	}
285
286
	/**
287
	 * Display metaboxes for a taxonomy term object
288
	 * @since  2.2.0
289
	 */
290
	public function term_metabox() {
291
		$this->show_form_for_type( 'term' );
292
	}
293
294
	/**
295
	 * Display metaboxes for an object type
296
	 * @since  2.2.0
297
	 * @param  string $type Object type
298
	 * @return void
299
	 */
300
	public function show_form_for_type( $type ) {
301
		if ( $type != $this->cmb->mb_object_type() ) {
302
			return;
303
		}
304
305
		if ( ! $this->show_on() ) {
306
			return;
307
		}
308
309
		if ( $this->cmb->prop( 'cmb_styles' ) ) {
310
			self::enqueue_cmb_css();
311
		}
312
		if ( $this->cmb->prop( 'enqueue_js' ) ) {
313
			self::enqueue_cmb_js();
314
		}
315
316
		$this->cmb->show_form( 0, $type );
317
	}
318
319
	/**
320
	 * Determines if metabox should be shown in current context
321
	 * @since  2.0.0
322
	 * @return bool Whether metabox should be added/shown
323
	 */
324
	public function show_on() {
325
		// If metabox is requesting to be conditionally shown
326
		$show = $this->cmb->should_show();
327
328
		/**
329
		 * Filter to determine if metabox should show. Default is true
330
		 *
331
		 * @param array  $show          Default is true, show the metabox
332
		 * @param mixed  $meta_box_args Array of the metabox arguments
333
		 * @param mixed  $cmb           The CMB2 instance
334
		 */
335
		$show = (bool) apply_filters( 'cmb2_show_on', $show, $this->cmb->meta_box, $this->cmb );
336
337
		return $show;
338
	}
339
340
	/**
341
	 * Get the CMB priority property set to numeric hook priority.
342
	 * @since  2.2.0
343
	 * @param  integer $default Default display hook priority.
344
	 * @return integer          Hook priority.
345
	 */
346
	public function get_priority( $default = 10 ) {
347
		$priority = $this->cmb->prop( 'priority' );
348
349
		if ( ! is_numeric( $priority ) ) {
350
			switch ( $priority ) {
351
352
				case 'high':
353
					$priority = 5;
354
					break;
355
356
				case 'low':
357
					$priority = 20;
358
					break;
359
360
				default:
361
					$priority = $default;
362
					break;
363
			}
364
		}
365
366
		return $priority;
367
	}
368
369
	/**
370
	 * Save data from post metabox
371
	 * @since  1.0.0
372
	 * @param  int    $post_id Post ID
373
	 * @param  mixed  $post    Post object
374
	 * @return null
375
	 */
376
	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...
377
378
		$post_type = $post ? $post->post_type : get_post_type( $post_id );
379
380
		$do_not_pass_go = (
381
			! $this->can_save( $post_type )
382
			// check user editing permissions
383
			|| ( 'page' == $post_type && ! current_user_can( 'edit_page', $post_id ) )
384
			|| ! current_user_can( 'edit_post', $post_id )
385
		);
386
387
		if ( $do_not_pass_go ) {
388
			// do not collect $200
389
			return;
390
		}
391
392
		// take a trip to reading railroad – if you pass go collect $200
393
		$this->cmb->save_fields( $post_id, 'post', $_POST );
394
	}
395
396
	/**
397
	 * Save data from comment metabox
398
	 * @since  2.0.9
399
	 * @param  int    $comment_id Comment ID
400
	 * @return null
401
	 */
402
	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...
403
404
		$can_edit = current_user_can( 'moderate_comments', $comment_id );
405
406
		if ( $this->can_save( get_comment_type( $comment_id ) ) && $can_edit ) {
407
			$this->cmb->save_fields( $comment_id, 'comment', $_POST );
408
		}
409
	}
410
411
	/**
412
	 * Save data from user fields
413
	 * @since  1.0.x
414
	 * @param  int   $user_id  User ID
415
	 * @return null
416
	 */
417
	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...
418
		// check permissions
419
		if ( $this->can_save( 'user' ) ) {
420
			$this->cmb->save_fields( $user_id, 'user', $_POST );
421
		}
422
	}
423
424
	/**
425
	 * Save data from term fields
426
	 * @since  2.2.0
427
	 * @param  int    $term_id  Term ID
428
	 * @param  int    $tt_id    Term Taxonomy ID
429
	 * @param  string $taxonomy Taxonomy
430
	 * @return null
431
	 */
432
	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...
433
		$taxonomy = $taxonomy ? $taxonomy : $tt_id;
434
435
		// check permissions
436
		if ( $this->taxonomy_can_save( $taxonomy ) && $this->can_save( 'term' ) ) {
437
			$this->cmb->save_fields( $term_id, 'term', $_POST );
438
		}
439
	}
440
441
	/**
442
	 * Delete term meta when a term is deleted.
443
	 * @since  2.2.0
444
	 * @param  int    $term_id  Term ID
445
	 * @param  int    $tt_id    Term Taxonomy ID
446
	 * @param  string $taxonomy Taxonomy
447
	 * @return null
448
	 */
449
	public function delete_term( $term_id, $tt_id, $taxonomy = '' ) {
450
		if ( $this->taxonomy_can_save( $taxonomy ) ) {
451
452
			foreach ( $this->cmb->prop( 'fields' ) as $field ) {
453
				$data_to_delete[ $field['id'] ] = '';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$data_to_delete was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data_to_delete = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
454
			}
455
456
			$this->cmb->save_fields( $term_id, 'term', $data_to_delete );
0 ignored issues
show
Bug introduced by
The variable $data_to_delete does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
457
		}
458
	}
459
460
	/**
461
	 * Determines if the current object is able to be saved
462
	 * @since  2.0.9
463
	 * @param  string  $type Current post_type or comment_type
464
	 * @return bool          Whether object can be saved
465
	 */
466
	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...
467
		return (
468
			$this->cmb->prop( 'save_fields' )
469
			// check nonce
470
			&& isset( $_POST[ $this->cmb->nonce() ] )
471
			&& wp_verify_nonce( $_POST[ $this->cmb->nonce() ], $this->cmb->nonce() )
472
			// check if autosave
473
			&& ! ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
474
			// get the metabox types & compare it to this type
475
			&& ( $type && in_array( $type, $this->cmb->prop( 'object_types' ) ) )
476
		);
477
	}
478
479
	/**
480
	 * Determine if taxonomy of term being modified is cmb2-editable.
481
	 * @since  2.2.0
482
	 * @param  string $taxonomy Taxonomy of term being modified.
483
	 * @return bool             Whether taxonomy is editable.
484
	 */
485
	public function taxonomy_can_save( $taxonomy ) {
486
		if ( empty( $this->taxonomies ) || ! in_array( $taxonomy, $this->taxonomies ) ) {
487
			return false;
488
		}
489
490
		$taxonomy_object = get_taxonomy( $taxonomy );
491
		// Can the user edit this term?
492
		if ( ! isset( $taxonomy_object->cap ) || ! current_user_can( $taxonomy_object->cap->edit_terms ) ) {
493
			return false;
494
		}
495
496
		return true;
497
	}
498
499
	/**
500
	 * Ensures WordPress hook only gets fired once
501
	 * @since  2.0.0
502
	 * @param string   $action        The name of the filter to hook the $hook callback to.
503
	 * @param callback $hook          The callback to be run when the filter is applied.
504
	 * @param integer  $priority      Order the functions are executed
505
	 * @param int      $accepted_args The number of arguments the function accepts.
506
	 */
507
	public function once( $action, $hook, $priority = 10, $accepted_args = 1 ) {
508
		$key = md5( serialize( func_get_args() ) );
509
510
		if ( in_array( $key, self::$hooks_completed ) ) {
511
			return;
512
		}
513
514
		self::$hooks_completed[] = $key;
515
		add_filter( $action, $hook, $priority, $accepted_args );
516
	}
517
518
	/**
519
	 * Includes CMB2 styles
520
	 * @since  2.0.0
521
	 */
522 1
	public static function enqueue_cmb_css() {
523 1
		if ( ! apply_filters( 'cmb2_enqueue_css', true ) ) {
524
			return false;
525
		}
526
527 1
		self::register_styles();
528 1
		return wp_enqueue_style( 'cmb2-styles' );
529
	}
530
531
	/**
532
	 * Includes CMB2 JS
533
	 * @since  2.0.0
534
	 */
535 1
	public static function enqueue_cmb_js() {
536 1
		if ( ! apply_filters( 'cmb2_enqueue_js', true ) ) {
537
			return false;
538
		}
539
540 1
		self::register_js();
541 1
		return true;
542
	}
543
544
}
545