Completed
Push — trunk ( 7dd985...f02feb )
by Justin
29:04 queued 15:34
created

CMB2_hookup::close_metabox_class()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
ccs 0
cts 4
cp 0
crap 2
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();
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...
52
53
		$this->universal_hooks();
54
55
		if ( is_admin() ) {
56
57
			switch ( $this->object_type ) {
58
				case 'post':
59
					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...
60
				case 'comment':
61
					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...
62
				case 'user':
63
					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...
64
				case 'term':
65
					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...
66
			}
67
68
		}
69
	}
70
71
	public function universal_hooks() {
72
		foreach ( get_class_methods( 'CMB2_Show_Filters' ) as $filter ) {
73
			add_filter( 'cmb2_show_on', array( 'CMB2_Show_Filters', $filter ), 10, 3 );
74
		}
75
76
		if ( is_admin() ) {
77
			// register our scripts and styles for cmb
78
			$this->once( 'admin_enqueue_scripts', array( __CLASS__, 'register_scripts' ), 8 );
79
			$this->once( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
80
81
			$this->maybe_enqueue_column_display_styles();
82
		}
83
	}
84
85
	public function post_hooks() {
86
		add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) );
87
		add_action( 'add_attachment', array( $this, 'save_post' ) );
88
		add_action( 'edit_attachment', array( $this, 'save_post' ) );
89
		add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
90
91
		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...
92
			foreach ( $this->cmb->prop( 'object_types' ) as $post_type ) {
93
				add_filter( "manage_{$post_type}_posts_columns", array( $this, 'register_column_headers' ) );
94
				add_action( "manage_{$post_type}_posts_custom_column", array( $this, 'column_display' ), 10, 2 );
95
			}
96
		}
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
		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...
104
			add_filter( 'manage_edit-comments_columns', array( $this, 'register_column_headers' ) );
105
			add_action( 'manage_comments_custom_column', array( $this, 'column_display'  ), 10, 3 );
106
		}
107
	}
108
109
	public function user_hooks() {
110
		$priority = $this->get_priority();
111
112
		add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority );
113
		add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority );
114
		add_action( 'user_new_form', array( $this, 'user_new_metabox' ), $priority );
115
116
		add_action( 'personal_options_update', array( $this, 'save_user' ) );
117
		add_action( 'edit_user_profile_update', array( $this, 'save_user' ) );
118
		add_action( 'user_register', array( $this, 'save_user' ) );
119
120 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...
121
			add_filter( 'manage_users_columns', array( $this, 'register_column_headers' ) );
122
			add_filter( 'manage_users_custom_column', array( $this, 'return_column_display'  ), 10, 3 );
123
		}
124
	}
125
126
	public function term_hooks() {
127
		if ( ! function_exists( 'get_term_meta' ) ) {
128
			wp_die( __( 'Term Metadata is a WordPress > 4.4 feature. Please upgrade your WordPress install.', 'cmb2' ) );
129
		}
130
131
		if ( ! $this->cmb->prop( 'taxonomies' ) ) {
132
			wp_die( __( 'Term metaboxes configuration requires a \'taxonomies\' parameter', 'cmb2' ) );
133
		}
134
135
		$this->taxonomies = (array) $this->cmb->prop( 'taxonomies' );
136
		$show_on_term_add = $this->cmb->prop( 'new_term_section' );
137
		$priority         = $this->get_priority( 8 );
138
139
		foreach ( $this->taxonomies as $taxonomy ) {
140
			// Display our form data
141
			add_action( "{$taxonomy}_edit_form", array( $this, 'term_metabox' ), $priority, 2 );
142
143
			$show_on_add = is_array( $show_on_term_add )
144
				? in_array( $taxonomy, $show_on_term_add )
145
				: (bool) $show_on_term_add;
146
147
			$show_on_add = apply_filters( "cmb2_show_on_term_add_form_{$this->cmb->cmb_id}", $show_on_add, $this->cmb );
148
149
			// Display form in add-new section (unless specified not to)
150
			if ( $show_on_add ) {
151
				add_action( "{$taxonomy}_add_form_fields", array( $this, 'term_metabox' ), $priority, 2 );
152
			}
153
154 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...
155
				add_filter( "manage_edit-{$taxonomy}_columns", array( $this, 'register_column_headers' ) );
156
				add_filter( "manage_{$taxonomy}_custom_column", array( $this, 'return_column_display'  ), 10, 3 );
157
			}
158
		}
159
160
		add_action( 'created_term', array( $this, 'save_term' ), 10, 3 );
161
		add_action( 'edited_terms', array( $this, 'save_term' ), 10, 2 );
162
		add_action( 'delete_term', array( $this, 'delete_term' ), 10, 3 );
163
164
	}
165
166
	/**
167
	 * Registers styles for CMB2
168
	 * @since 2.0.7
169
	 */
170
	protected static function register_styles() {
171
		if ( self::$css_registration_done ) {
172
			return;
173
		}
174
175
		// Only use minified files if SCRIPT_DEBUG is off
176
		$min   = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
177
		$front = is_admin() ? '' : '-front';
178
		$rtl   = is_rtl() ? '-rtl' : '';
179
180
		// Filter required styles and register stylesheet
181
		$dependencies = apply_filters( 'cmb2_style_dependencies', array() );
182
		wp_register_style( 'cmb2-styles', cmb2_utils()->url( "css/cmb2{$front}{$rtl}{$min}.css" ), $dependencies );
183
		wp_register_style( 'cmb2-display-styles', cmb2_utils()->url( "css/cmb2-display{$rtl}{$min}.css" ), $dependencies );
184
185 1
		self::$css_registration_done = true;
186 1
	}
187
188
	/**
189
	 * Registers scripts for CMB2
190
	 * @since  2.0.7
191 1
	 */
192 1
	protected static function register_js() {
193 1
		if ( self::$js_registration_done ) {
194
			return;
195
		}
196 1
197 1
		$hook = is_admin() ? 'admin_footer' : 'wp_footer';
198 1
		add_action( $hook, array( 'CMB2_JS', 'enqueue' ), 8 );
199
200 1
		self::$js_registration_done = true;
201 1
	}
202
203
	/**
204
	 * Registers scripts and styles for CMB2
205
	 * @since  1.0.0
206
	 */
207 1
	public static function register_scripts() {
208 1
		self::register_styles();
209
		self::register_js();
210
	}
211
212 1
	/**
213 1
	 * Enqueues scripts and styles for CMB2 in admin_head.
214
	 * @since  1.0.0
215 1
	 */
216 1
	public function do_scripts( $hook ) {
217
		$hooks = array(
218
			'post.php',
219
			'post-new.php',
220
			'page-new.php',
221
			'page.php',
222
			'comment.php',
223
			'edit-tags.php',
224
			'term.php',
225
			'user-new.php',
226
			'profile.php',
227
			'user-edit.php',
228
		);
229
		// only pre-enqueue our scripts/styles on the proper pages
230
		// show_form_for_type will have us covered if we miss something here.
231
		if ( in_array( $hook, $hooks, true ) ) {
232
			if ( $this->cmb->prop( 'cmb_styles' ) ) {
233
				self::enqueue_cmb_css();
234
			}
235
			if ( $this->cmb->prop( 'enqueue_js' ) ) {
236
				self::enqueue_cmb_js();
237
			}
238
		}
239
	}
240
241
	/**
242
	 * Register the CMB2 field column headers.
243
	 * @since 2.2.2
244
	 */
245
	public function register_column_headers( $columns ) {
246
		$fields = $this->cmb->prop( 'fields' );
247
248
		foreach ( $fields as $key => $field ) {
249
			if ( ! isset( $field['column'] ) ) {
250
				continue;
251
			}
252
253
			$column = $field['column'];
254
255
			if ( false === $column['position'] ) {
256
257
				$columns[ $field['id'] ] = $column['name'];
258
259
			} else {
260
261
				$before = array_slice( $columns, 0, absint( $column['position'] ) );
262
				$before[ $field['id'] ] = $column['name'];
263
				$columns = $before + $columns;
264
			}
265
266
			$column['field'] = $field;
267
			$this->columns[ $field['id'] ] = $column;
268
		}
269
270
		return $columns;
271
	}
272
273
	/**
274
	 * The CMB2 field column display output.
275
	 * @since 2.2.2
276
	 */
277
	public function column_display( $column_name, $object_id ) {
278
		if ( isset( $this->columns[ $column_name ] ) ) {
279
 			$field = new CMB2_Field( array(
280
				'field_args'  => $this->columns[ $column_name ]['field'],
281
				'object_type' => $this->object_type,
282
				'object_id'   => $this->cmb->object_id( $object_id ),
283
				'cmb_id'      => $this->cmb->cmb_id,
284
			) );
285
286
			$this->cmb->get_field( $field )->render_column();
287
		}
288
	}
289
290
	/**
291
	 * Returns the column display.
292
	 * @since 2.2.2
293
	 */
294
	public function return_column_display( $empty, $custom_column, $object_id ) {
295
		ob_start();
296
		$this->column_display( $custom_column, $object_id );
297
		$column = ob_get_clean();
298
299
		return $column ? $column : $empty;
300
	}
301
302
	/**
303
	 * Add metaboxes (to 'post' or 'comment' object types)
304
	 * @since 1.0.0
305
	 */
306
	public function add_metaboxes() {
307
308
		if ( ! $this->show_on() ) {
309
			return;
310
		}
311
312
		/**
313
		 * To keep from registering an actual post-screen metabox,
314
		 * omit the 'title' attribute from the metabox registration array.
315
		 *
316
		 * (WordPress will not display metaboxes without titles anyway)
317
		 *
318
		 * This is a good solution if you want to output your metaboxes
319
		 * Somewhere else in the post-screen
320
		 */
321
		if ( ! $this->cmb->prop( 'title' ) ) {
322
			return;
323
		}
324
325
		foreach ( $this->cmb->prop( 'object_types' ) as $post_type ) {
326
			if ( $this->cmb->prop( 'closed' ) ) {
327
				add_filter( "postbox_classes_{$post_type}_{$this->cmb->cmb_id}", array( $this, 'close_metabox_class' ) );
328
			}
329
330
			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' ) );
331
		}
332
	}
333
334
	/**
335
	 * Add 'closed' class to metabox
336
	 * @since  2.0.0
337
	 * @param  array  $classes Array of classes
338
	 * @return array           Modified array of classes
339
	 */
340
	public function close_metabox_class( $classes ) {
341
		$classes[] = 'closed';
342
		return $classes;
343
	}
344
345
	/**
346
	 * Display metaboxes for a post or comment object
347
	 * @since  1.0.0
348
	 */
349
	public function metabox_callback() {
350
		$object_id = 'comment' == $this->object_type ? get_comment_ID() : get_the_ID();
351
		$this->cmb->show_form( $object_id, $this->object_type );
352
	}
353
354
	/**
355
	 * Display metaboxes for new user page
356
	 * @since  1.0.0
357
	 */
358
	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...
359
		if ( $section == $this->cmb->prop( 'new_user_section' ) ) {
360
			$object_id = $this->cmb->object_id();
361
			$this->cmb->object_id( isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id );
362
			$this->user_metabox();
363
		}
364
	}
365
366
	/**
367
	 * Display metaboxes for a user object
368
	 * @since  1.0.0
369
	 */
370
	public function user_metabox() {
371
		$this->show_form_for_type( 'user' );
372
	}
373
374
	/**
375
	 * Display metaboxes for a taxonomy term object
376
	 * @since  2.2.0
377
	 */
378
	public function term_metabox() {
379
		$this->show_form_for_type( 'term' );
380
	}
381
382
	/**
383
	 * Display metaboxes for an object type
384
	 * @since  2.2.0
385
	 * @param  string $type Object type
386
	 * @return void
387
	 */
388
	public function show_form_for_type( $type ) {
389
		if ( $type != $this->cmb->mb_object_type() ) {
390
			return;
391
		}
392
393
		if ( ! $this->show_on() ) {
394
			return;
395
		}
396
397
		if ( $this->cmb->prop( 'cmb_styles' ) ) {
398
			self::enqueue_cmb_css();
399
		}
400
		if ( $this->cmb->prop( 'enqueue_js' ) ) {
401
			self::enqueue_cmb_js();
402
		}
403
404
		$this->cmb->show_form( 0, $type );
405
	}
406
407
	/**
408
	 * Determines if metabox should be shown in current context
409
	 * @since  2.0.0
410
	 * @return bool Whether metabox should be added/shown
411
	 */
412
	public function show_on() {
413
		// If metabox is requesting to be conditionally shown
414
		$show = $this->cmb->should_show();
415
416
		/**
417
		 * Filter to determine if metabox should show. Default is true
418
		 *
419
		 * @param array  $show          Default is true, show the metabox
420
		 * @param mixed  $meta_box_args Array of the metabox arguments
421
		 * @param mixed  $cmb           The CMB2 instance
422
		 */
423
		$show = (bool) apply_filters( 'cmb2_show_on', $show, $this->cmb->meta_box, $this->cmb );
424
425
		return $show;
426
	}
427
428
	/**
429
	 * Get the CMB priority property set to numeric hook priority.
430
	 * @since  2.2.0
431
	 * @param  integer $default Default display hook priority.
432
	 * @return integer          Hook priority.
433
	 */
434
	public function get_priority( $default = 10 ) {
435
		$priority = $this->cmb->prop( 'priority' );
436
437
		if ( ! is_numeric( $priority ) ) {
438
			switch ( $priority ) {
439
440
				case 'high':
441
					$priority = 5;
442
					break;
443
444
				case 'low':
445
					$priority = 20;
446
					break;
447
448
				default:
449
					$priority = $default;
450
					break;
451
			}
452
		}
453
454
		return $priority;
455
	}
456
457
	/**
458
	 * Save data from post metabox
459
	 * @since  1.0.0
460
	 * @param  int    $post_id Post ID
461
	 * @param  mixed  $post    Post object
462
	 * @return null
463
	 */
464
	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...
465
466
		$post_type = $post ? $post->post_type : get_post_type( $post_id );
467
468
		$do_not_pass_go = (
469
			! $this->can_save( $post_type )
470
			// check user editing permissions
471
			|| ( 'page' == $post_type && ! current_user_can( 'edit_page', $post_id ) )
472
			|| ! current_user_can( 'edit_post', $post_id )
473
		);
474
475
		if ( $do_not_pass_go ) {
476
			// do not collect $200
477
			return;
478
		}
479
480
		// take a trip to reading railroad – if you pass go collect $200
481
		$this->cmb->save_fields( $post_id, 'post', $_POST );
482
	}
483
484
	/**
485
	 * Save data from comment metabox
486
	 * @since  2.0.9
487
	 * @param  int    $comment_id Comment ID
488
	 * @return null
489
	 */
490
	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...
491
492
		$can_edit = current_user_can( 'moderate_comments', $comment_id );
493
494
		if ( $this->can_save( get_comment_type( $comment_id ) ) && $can_edit ) {
495
			$this->cmb->save_fields( $comment_id, 'comment', $_POST );
496
		}
497
	}
498
499
	/**
500
	 * Save data from user fields
501
	 * @since  1.0.x
502
	 * @param  int   $user_id  User ID
503
	 * @return null
504
	 */
505
	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...
506
		// check permissions
507
		if ( $this->can_save( 'user' ) ) {
508
			$this->cmb->save_fields( $user_id, 'user', $_POST );
509
		}
510
	}
511
512
	/**
513
	 * Save data from term fields
514
	 * @since  2.2.0
515
	 * @param  int    $term_id  Term ID
516
	 * @param  int    $tt_id    Term Taxonomy ID
517
	 * @param  string $taxonomy Taxonomy
518
	 * @return null
519
	 */
520
	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...
521
		$taxonomy = $taxonomy ? $taxonomy : $tt_id;
522
523
		// check permissions
524
		if ( $this->taxonomy_can_save( $taxonomy ) && $this->can_save( 'term' ) ) {
525
			$this->cmb->save_fields( $term_id, 'term', $_POST );
526
		}
527
	}
528
529
	/**
530
	 * Delete term meta when a term is deleted.
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 delete_term( $term_id, $tt_id, $taxonomy = '' ) {
538
		if ( $this->taxonomy_can_save( $taxonomy ) ) {
539
540
			foreach ( $this->cmb->prop( 'fields' ) as $field ) {
541
				$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...
542
			}
543
544
			$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...
545
		}
546
	}
547
548
	/**
549
	 * Determines if the current object is able to be saved
550
	 * @since  2.0.9
551
	 * @param  string  $type Current post_type or comment_type
552
	 * @return bool          Whether object can be saved
553
	 */
554
	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...
555
		return (
556
			$this->cmb->prop( 'save_fields' )
557
			// check nonce
558
			&& isset( $_POST[ $this->cmb->nonce() ] )
559
			&& wp_verify_nonce( $_POST[ $this->cmb->nonce() ], $this->cmb->nonce() )
560
			// check if autosave
561
			&& ! ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
562
			// get the metabox types & compare it to this type
563
			&& ( $type && in_array( $type, $this->cmb->prop( 'object_types' ) ) )
564
		);
565
	}
566
567
	/**
568
	 * Determine if taxonomy of term being modified is cmb2-editable.
569
	 * @since  2.2.0
570
	 * @param  string $taxonomy Taxonomy of term being modified.
571
	 * @return bool             Whether taxonomy is editable.
572
	 */
573
	public function taxonomy_can_save( $taxonomy ) {
574
		if ( empty( $this->taxonomies ) || ! in_array( $taxonomy, $this->taxonomies ) ) {
575
			return false;
576
		}
577
578
		$taxonomy_object = get_taxonomy( $taxonomy );
579
		// Can the user edit this term?
580
		if ( ! isset( $taxonomy_object->cap ) || ! current_user_can( $taxonomy_object->cap->edit_terms ) ) {
581
			return false;
582
		}
583
584
		return true;
585
	}
586
587
	/**
588
	 * Enqueues the 'cmb2-display-styles' if the conditions match (has columns, on the right page, etc).
589
	 * @since  2.2.2.1
590
	 */
591
	protected function maybe_enqueue_column_display_styles() {
592
		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...
593
		if (
594
			$pagenow
595
			&& $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...
596
			&& $this->cmb->prop( 'cmb_styles' )
597
			&& in_array( $pagenow, array( 'edit.php', 'users.php', 'edit-comments.php', 'edit-tags.php' ), 1 )
598
			) {
599
			self::enqueue_cmb_css( 'cmb2-display-styles' );
600
		}
601
	}
602
603
	/**
604
	 * Includes CMB2 styles
605
	 * @since  2.0.0
606
	 */
607
	public static function enqueue_cmb_css( $handle = 'cmb2-styles' ) {
608
		if ( ! apply_filters( 'cmb2_enqueue_css', true ) ) {
609
			return false;
610
		}
611
612
		self::register_styles();
613
614
		/*
615
		 * White list the options as this method can be used as a hook callback
616
		 * and have a different argument passed.
617
		 */
618
		return wp_enqueue_style( 'cmb2-display-styles' === $handle ? $handle : 'cmb2-styles' );
619
	}
620
621
	/**
622
	 * Includes CMB2 JS
623
	 * @since  2.0.0
624
	 */
625
	public static function enqueue_cmb_js() {
626
		if ( ! apply_filters( 'cmb2_enqueue_js', true ) ) {
627
			return false;
628
		}
629
630
		self::register_js();
631
		return true;
632
	}
633
634
}
635