Completed
Push — trunk ( 5d123b...5dfd19 )
by Justin
06:53
created

CMB2_hookup::comment_hooks()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 2
Metric Value
cc 2
eloc 6
c 2
b 0
f 2
nc 2
nop 0
dl 0
loc 9
rs 9.6666
ccs 0
cts 8
cp 0
crap 6
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
	 * Custom field columns.
52
	 * @var   array
53
	 * @since 2.2.2
54
	 */
55
	protected $columns = array();
56
57
	/**
58
	 * The object type we are performing the hookup for
59
	 * @var   string
60
	 * @since 2.0.9
61
	 */
62
	protected $object_type = 'post';
63
64
	public function __construct( CMB2 $cmb ) {
65
		$this->cmb = $cmb;
66
		$this->object_type = $this->cmb->mb_object_type();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->cmb->mb_object_type() can also be of type false. However, the property $object_type is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
67
68
		$this->universal_hooks();
69
70
		if ( is_admin() ) {
71
72
			switch ( $this->object_type ) {
73
				case 'post':
74
					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...
75
				case 'comment':
76
					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...
77
				case 'user':
78
					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...
79
				case 'term':
80
					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...
81
			}
82
83
		}
84
	}
85
86
	public function universal_hooks() {
87
		foreach ( get_class_methods( 'CMB2_Show_Filters' ) as $filter ) {
88
			add_filter( 'cmb2_show_on', array( 'CMB2_Show_Filters', $filter ), 10, 3 );
89
		}
90
91
		if ( is_admin() ) {
92
			// register our scripts and styles for cmb
93
			$this->once( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ), 8 );
94
			$this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
95
96
			if ( $this->cmb->has_columns && $this->cmb->prop( 'cmb_styles' ) ) {
0 ignored issues
show
Documentation introduced by
The property $has_columns is declared protected in CMB2. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
97
				self::enqueue_cmb_css( 'cmb2-display-styles' );
98
			}
99
		}
100
	}
101
102
	public function post_hooks() {
103
		add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) );
104
		add_action( 'add_attachment', array( $this, 'save_post' ) );
105
		add_action( 'edit_attachment', array( $this, 'save_post' ) );
106
		add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
107
108
		if ( $this->cmb->has_columns ) {
0 ignored issues
show
Documentation introduced by
The property $has_columns is declared protected in CMB2. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
109
			foreach ( $this->cmb->prop( 'object_types' ) as $post_type ) {
110
				add_filter( "manage_{$post_type}_posts_columns", array( $this, 'register_column_headers' ) );
111
				add_action( "manage_{$post_type}_posts_custom_column", array( $this, 'column_display' ), 10, 2 );
112
			}
113
		}
114
	}
115
116
	public function comment_hooks() {
117
		add_action( 'add_meta_boxes_comment', array( $this, 'add_metaboxes' ) );
118
		add_action( 'edit_comment', array( $this, 'save_comment' ) );
119
120
		if ( $this->cmb->has_columns ) {
0 ignored issues
show
Documentation introduced by
The property $has_columns is declared protected in CMB2. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
121
			add_filter( 'manage_edit-comments_columns', array( $this, 'register_column_headers' ) );
122
			add_action( 'manage_comments_custom_column', array( $this, 'column_display'  ), 10, 3 );
123
		}
124
	}
125
126
	public function user_hooks() {
127
		$priority = $this->get_priority();
128
129
		add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority );
130
		add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority );
131
		add_action( 'user_new_form', array( $this, 'user_new_metabox' ), $priority );
132
133
		add_action( 'personal_options_update', array( $this, 'save_user' ) );
134
		add_action( 'edit_user_profile_update', array( $this, 'save_user' ) );
135
		add_action( 'user_register', array( $this, 'save_user' ) );
136
137 View Code Duplication
		if ( $this->cmb->has_columns ) {
0 ignored issues
show
Documentation introduced by
The property $has_columns is declared protected in CMB2. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
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...
138
			add_filter( 'manage_users_columns', array( $this, 'register_column_headers' ) );
139
			add_filter( 'manage_users_custom_column', array( $this, 'return_column_display'  ), 10, 3 );
140
		}
141
	}
142
143
	public function term_hooks() {
144
		if ( ! function_exists( 'get_term_meta' ) ) {
145
			wp_die( __( 'Term Metadata is a WordPress > 4.4 feature. Please upgrade your WordPress install.', 'cmb2' ) );
146
		}
147
148
		if ( ! $this->cmb->prop( 'taxonomies' ) ) {
149
			wp_die( __( 'Term metaboxes configuration requires a \'taxonomies\' parameter', 'cmb2' ) );
150
		}
151
152
		$this->taxonomies = (array) $this->cmb->prop( 'taxonomies' );
153
		$show_on_term_add = $this->cmb->prop( 'new_term_section' );
154
		$priority         = $this->get_priority( 8 );
155
156
		foreach ( $this->taxonomies as $taxonomy ) {
157
			// Display our form data
158
			add_action( "{$taxonomy}_edit_form", array( $this, 'term_metabox' ), $priority, 2 );
159
160
			$show_on_add = is_array( $show_on_term_add )
161
				? in_array( $taxonomy, $show_on_term_add )
162
				: (bool) $show_on_term_add;
163
164
			$show_on_add = apply_filters( "cmb2_show_on_term_add_form_{$this->cmb->cmb_id}", $show_on_add, $this->cmb );
165
166
			// Display form in add-new section (unless specified not to)
167
			if ( $show_on_add ) {
168
				add_action( "{$taxonomy}_add_form_fields", array( $this, 'term_metabox' ), $priority, 2 );
169
			}
170
171 View Code Duplication
			if ( $this->cmb->has_columns ) {
0 ignored issues
show
Documentation introduced by
The property $has_columns is declared protected in CMB2. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
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...
172
				add_filter( "manage_edit-{$taxonomy}_columns", array( $this, 'register_column_headers' ) );
173
				add_filter( "manage_{$taxonomy}_custom_column", array( $this, 'return_column_display'  ), 10, 3 );
174
			}
175
		}
176
177
		add_action( 'created_term', array( $this, 'save_term' ), 10, 3 );
178
		add_action( 'edited_terms', array( $this, 'save_term' ), 10, 2 );
179
		add_action( 'delete_term', array( $this, 'delete_term' ), 10, 3 );
180
181
	}
182
183
	/**
184
	 * Registers styles for CMB2
185
	 * @since 2.0.7
186
	 */
187 1
	protected static function register_styles() {
188 1
		if ( self::$css_registration_done ) {
189
			return;
190
		}
191
192
		// Only use minified files if SCRIPT_DEBUG is off
193 1
		$min   = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
194 1
		$front = is_admin() ? '' : '-front';
195 1
		$rtl   = is_rtl() ? '-rtl' : '';
196
197
		// Filter required styles and register stylesheet
198 1
		$dependencies = apply_filters( 'cmb2_style_dependencies', array() );
199 1
		wp_register_style( 'cmb2-styles', cmb2_utils()->url( "css/cmb2{$front}{$rtl}{$min}.css" ), $dependencies );
200 1
		wp_register_style( 'cmb2-display-styles', cmb2_utils()->url( "css/cmb2-display{$rtl}{$min}.css" ), $dependencies );
201
202 1
		self::$css_registration_done = true;
203 1
	}
204
205
	/**
206
	 * Registers scripts for CMB2
207
	 * @since  2.0.7
208
	 */
209 1
	protected static function register_js() {
210 1
		if ( self::$js_registration_done ) {
211
			return;
212
		}
213
214 1
		$hook = is_admin() ? 'admin_footer' : 'wp_footer';
215 1
		add_action( $hook, array( 'CMB2_JS', 'enqueue' ), 8 );
216
217 1
		self::$js_registration_done = true;
218 1
	}
219
220
	/**
221
	 * Registers scripts and styles for CMB2
222
	 * @since  1.0.0
223
	 */
224
	public static function register_scripts() {
225
		self::register_styles();
226
		self::register_js();
227
	}
228
229
	/**
230
	 * Enqueues scripts and styles for CMB2 in admin_head.
231
	 * @since  1.0.0
232
	 */
233
	public function do_scripts( $hook ) {
234
		$hooks = array(
235
			'post.php',
236
			'post-new.php',
237
			'page-new.php',
238
			'page.php',
239
			'comment.php',
240
			'edit-tags.php',
241
			'term.php',
242
			'user-new.php',
243
			'profile.php',
244
			'user-edit.php',
245
		);
246
		// only pre-enqueue our scripts/styles on the proper pages
247
		// show_form_for_type will have us covered if we miss something here.
248
		if ( in_array( $hook, $hooks, true ) ) {
249
			if ( $this->cmb->prop( 'cmb_styles' ) ) {
250
				self::enqueue_cmb_css();
251
			}
252
			if ( $this->cmb->prop( 'enqueue_js' ) ) {
253
				self::enqueue_cmb_js();
254
			}
255
		}
256
	}
257
258
	/**
259
	 * Register the CMB2 field column headers.
260
	 * @since 2.2.2
261
	 */
262
	public function register_column_headers( $columns ) {
263
		$fields = $this->cmb->prop( 'fields' );
264
265
		foreach ( $fields as $key => $field ) {
266
			if ( ! isset( $field['column'] ) ) {
267
				continue;
268
			}
269
270
			$column = $field['column'];
271
272
			if ( false === $column['position'] ) {
273
274
				$columns[ $field['id'] ] = $column['name'];
275
276
			} else {
277
278
				$before = array_slice( $columns, 0, absint( $column['position'] ) );
279
				$before[ $field['id'] ] = $column['name'];
280
				$columns = $before + $columns;
281
			}
282
283
			$column['field'] = $field;
284
			$this->columns[ $field['id'] ] = $column;
285
		}
286
287
		return $columns;
288
	}
289
290
	/**
291
	 * The CMB2 field column display output.
292
	 * @since 2.2.2
293
	 */
294
	public function column_display( $column_name, $object_id ) {
295
		if ( isset( $this->columns[ $column_name ] ) ) {
296
 			$field = new CMB2_Field( array(
297
				'field_args'  => $this->columns[ $column_name ]['field'],
298
				'object_type' => $this->object_type,
299
				'object_id'   => $this->cmb->object_id( $object_id ),
300
				'cmb_id'      => $this->cmb->cmb_id,
301
			) );
302
303
			$this->cmb->get_field( $field )->render_column();
304
		}
305
	}
306
307
	/**
308
	 * Returns the column display.
309
	 * @since 2.2.2
310
	 */
311
	public function return_column_display( $empty, $custom_column, $object_id ) {
312
		ob_start();
313
		$this->column_display( $custom_column, $object_id );
314
		$column = ob_get_clean();
315
316
		return $column ? $column : $empty;
317
	}
318
319
	/**
320
	 * Add metaboxes (to 'post' or 'comment' object types)
321
	 * @since 1.0.0
322
	 */
323
	public function add_metaboxes() {
324
325
		if ( ! $this->show_on() ) {
326
			return;
327
		}
328
329
		/**
330
		 * To keep from registering an actual post-screen metabox,
331
		 * omit the 'title' attribute from the metabox registration array.
332
		 *
333
		 * (WordPress will not display metaboxes without titles anyway)
334
		 *
335
		 * This is a good solution if you want to output your metaboxes
336
		 * Somewhere else in the post-screen
337
		 */
338
		if ( ! $this->cmb->prop( 'title' ) ) {
339
			return;
340
		}
341
342
		foreach ( $this->cmb->prop( 'object_types' ) as $post_type ) {
343
			if ( $this->cmb->prop( 'closed' ) ) {
344
				add_filter( "postbox_classes_{$post_type}_{$this->cmb->cmb_id}", array( $this, 'close_metabox_class' ) );
345
			}
346
347
			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' ) );
348
		}
349
	}
350
351
	/**
352
	 * Add 'closed' class to metabox
353
	 * @since  2.0.0
354
	 * @param  array  $classes Array of classes
355
	 * @return array           Modified array of classes
356
	 */
357
	public function close_metabox_class( $classes ) {
358
		$classes[] = 'closed';
359
		return $classes;
360
	}
361
362
	/**
363
	 * Display metaboxes for a post or comment object
364
	 * @since  1.0.0
365
	 */
366
	public function metabox_callback() {
367
		$object_id = 'comment' == $this->object_type ? get_comment_ID() : get_the_ID();
368
		$this->cmb->show_form( $object_id, $this->object_type );
369
	}
370
371
	/**
372
	 * Display metaboxes for new user page
373
	 * @since  1.0.0
374
	 */
375
	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...
376
		if ( $section == $this->cmb->prop( 'new_user_section' ) ) {
377
			$object_id = $this->cmb->object_id();
378
			$this->cmb->object_id( isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id );
379
			$this->user_metabox();
380
		}
381
	}
382
383
	/**
384
	 * Display metaboxes for a user object
385
	 * @since  1.0.0
386
	 */
387
	public function user_metabox() {
388
		$this->show_form_for_type( 'user' );
389
	}
390
391
	/**
392
	 * Display metaboxes for a taxonomy term object
393
	 * @since  2.2.0
394
	 */
395
	public function term_metabox() {
396
		$this->show_form_for_type( 'term' );
397
	}
398
399
	/**
400
	 * Display metaboxes for an object type
401
	 * @since  2.2.0
402
	 * @param  string $type Object type
403
	 * @return void
404
	 */
405
	public function show_form_for_type( $type ) {
406
		if ( $type != $this->cmb->mb_object_type() ) {
407
			return;
408
		}
409
410
		if ( ! $this->show_on() ) {
411
			return;
412
		}
413
414
		if ( $this->cmb->prop( 'cmb_styles' ) ) {
415
			self::enqueue_cmb_css();
416
		}
417
		if ( $this->cmb->prop( 'enqueue_js' ) ) {
418
			self::enqueue_cmb_js();
419
		}
420
421
		$this->cmb->show_form( 0, $type );
422
	}
423
424
	/**
425
	 * Determines if metabox should be shown in current context
426
	 * @since  2.0.0
427
	 * @return bool Whether metabox should be added/shown
428
	 */
429
	public function show_on() {
430
		// If metabox is requesting to be conditionally shown
431
		$show = $this->cmb->should_show();
432
433
		/**
434
		 * Filter to determine if metabox should show. Default is true
435
		 *
436
		 * @param array  $show          Default is true, show the metabox
437
		 * @param mixed  $meta_box_args Array of the metabox arguments
438
		 * @param mixed  $cmb           The CMB2 instance
439
		 */
440
		$show = (bool) apply_filters( 'cmb2_show_on', $show, $this->cmb->meta_box, $this->cmb );
441
442
		return $show;
443
	}
444
445
	/**
446
	 * Get the CMB priority property set to numeric hook priority.
447
	 * @since  2.2.0
448
	 * @param  integer $default Default display hook priority.
449
	 * @return integer          Hook priority.
450
	 */
451
	public function get_priority( $default = 10 ) {
452
		$priority = $this->cmb->prop( 'priority' );
453
454
		if ( ! is_numeric( $priority ) ) {
455
			switch ( $priority ) {
456
457
				case 'high':
458
					$priority = 5;
459
					break;
460
461
				case 'low':
462
					$priority = 20;
463
					break;
464
465
				default:
466
					$priority = $default;
467
					break;
468
			}
469
		}
470
471
		return $priority;
472
	}
473
474
	/**
475
	 * Save data from post metabox
476
	 * @since  1.0.0
477
	 * @param  int    $post_id Post ID
478
	 * @param  mixed  $post    Post object
479
	 * @return null
480
	 */
481
	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...
482
483
		$post_type = $post ? $post->post_type : get_post_type( $post_id );
484
485
		$do_not_pass_go = (
486
			! $this->can_save( $post_type )
487
			// check user editing permissions
488
			|| ( 'page' == $post_type && ! current_user_can( 'edit_page', $post_id ) )
489
			|| ! current_user_can( 'edit_post', $post_id )
490
		);
491
492
		if ( $do_not_pass_go ) {
493
			// do not collect $200
494
			return;
495
		}
496
497
		// take a trip to reading railroad – if you pass go collect $200
498
		$this->cmb->save_fields( $post_id, 'post', $_POST );
499
	}
500
501
	/**
502
	 * Save data from comment metabox
503
	 * @since  2.0.9
504
	 * @param  int    $comment_id Comment ID
505
	 * @return null
506
	 */
507
	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...
508
509
		$can_edit = current_user_can( 'moderate_comments', $comment_id );
510
511
		if ( $this->can_save( get_comment_type( $comment_id ) ) && $can_edit ) {
512
			$this->cmb->save_fields( $comment_id, 'comment', $_POST );
513
		}
514
	}
515
516
	/**
517
	 * Save data from user fields
518
	 * @since  1.0.x
519
	 * @param  int   $user_id  User ID
520
	 * @return null
521
	 */
522
	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...
523
		// check permissions
524
		if ( $this->can_save( 'user' ) ) {
525
			$this->cmb->save_fields( $user_id, 'user', $_POST );
526
		}
527
	}
528
529
	/**
530
	 * Save data from term fields
531
	 * @since  2.2.0
532
	 * @param  int    $term_id  Term ID
533
	 * @param  int    $tt_id    Term Taxonomy ID
534
	 * @param  string $taxonomy Taxonomy
535
	 * @return null
536
	 */
537
	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...
538
		$taxonomy = $taxonomy ? $taxonomy : $tt_id;
539
540
		// check permissions
541
		if ( $this->taxonomy_can_save( $taxonomy ) && $this->can_save( 'term' ) ) {
542
			$this->cmb->save_fields( $term_id, 'term', $_POST );
543
		}
544
	}
545
546
	/**
547
	 * Delete term meta when a term is deleted.
548
	 * @since  2.2.0
549
	 * @param  int    $term_id  Term ID
550
	 * @param  int    $tt_id    Term Taxonomy ID
551
	 * @param  string $taxonomy Taxonomy
552
	 * @return null
553
	 */
554
	public function delete_term( $term_id, $tt_id, $taxonomy = '' ) {
555
		if ( $this->taxonomy_can_save( $taxonomy ) ) {
556
557
			foreach ( $this->cmb->prop( 'fields' ) as $field ) {
558
				$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...
559
			}
560
561
			$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...
562
		}
563
	}
564
565
	/**
566
	 * Determines if the current object is able to be saved
567
	 * @since  2.0.9
568
	 * @param  string  $type Current post_type or comment_type
569
	 * @return bool          Whether object can be saved
570
	 */
571
	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...
572
		return (
573
			$this->cmb->prop( 'save_fields' )
574
			// check nonce
575
			&& isset( $_POST[ $this->cmb->nonce() ] )
576
			&& wp_verify_nonce( $_POST[ $this->cmb->nonce() ], $this->cmb->nonce() )
577
			// check if autosave
578
			&& ! ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
579
			// get the metabox types & compare it to this type
580
			&& ( $type && in_array( $type, $this->cmb->prop( 'object_types' ) ) )
581
		);
582
	}
583
584
	/**
585
	 * Determine if taxonomy of term being modified is cmb2-editable.
586
	 * @since  2.2.0
587
	 * @param  string $taxonomy Taxonomy of term being modified.
588
	 * @return bool             Whether taxonomy is editable.
589
	 */
590
	public function taxonomy_can_save( $taxonomy ) {
591
		if ( empty( $this->taxonomies ) || ! in_array( $taxonomy, $this->taxonomies ) ) {
592
			return false;
593
		}
594
595
		$taxonomy_object = get_taxonomy( $taxonomy );
596
		// Can the user edit this term?
597
		if ( ! isset( $taxonomy_object->cap ) || ! current_user_can( $taxonomy_object->cap->edit_terms ) ) {
598
			return false;
599
		}
600
601
		return true;
602
	}
603
604
	/**
605
	 * Ensures WordPress hook only gets fired once
606
	 * @since  2.0.0
607
	 * @param string   $action        The name of the filter to hook the $hook callback to.
608
	 * @param callback $hook          The callback to be run when the filter is applied.
609
	 * @param integer  $priority      Order the functions are executed
610
	 * @param int      $accepted_args The number of arguments the function accepts.
611
	 */
612
	public function once( $action, $hook, $priority = 10, $accepted_args = 1 ) {
613
		$key = md5( serialize( func_get_args() ) );
614
615
		if ( in_array( $key, self::$hooks_completed ) ) {
616
			return;
617
		}
618
619
		self::$hooks_completed[] = $key;
620
		add_filter( $action, $hook, $priority, $accepted_args );
621
	}
622
623
	/**
624
	 * Includes CMB2 styles
625
	 * @since  2.0.0
626
	 */
627 1
	public static function enqueue_cmb_css( $handle = 'cmb2-styles' ) {
628 1
		if ( ! apply_filters( 'cmb2_enqueue_css', true ) ) {
629
			return false;
630
		}
631
632 1
		self::register_styles();
633 1
		return wp_enqueue_style( $handle );
634
	}
635
636
	/**
637
	 * Includes CMB2 JS
638
	 * @since  2.0.0
639
	 */
640 1
	public static function enqueue_cmb_js() {
641 1
		if ( ! apply_filters( 'cmb2_enqueue_js', true ) ) {
642
			return false;
643
		}
644
645 1
		self::register_js();
646 1
		return true;
647
	}
648
649
}
650