Completed
Push — master ( ff21ec...826c43 )
by Leon
03:17
created

CMB2_Meta_Box::add_strpos_arg()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 6
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 11
rs 8.8571
1
<?php
2
/**
3
 * CMB2 Meta Box
4
 *
5
 * @since  0.1.0
6
 *
7
 * @category  WordPress_Plugin
8
 * @package   CMB2 Admin Extension
9
 * @author    twoelevenjay
10
 * @license   GPL-2.0+
11
 */
12
13
if ( ! class_exists( 'CMB2_Meta_Box' ) ) {
14
15
	/**
16
	 * Class CMB2_Meta_Box.
17
	 */
18
	class CMB2_Meta_Box {
19
20
		/**
21
		 * Field prefix.
22
		 *
23
		 * @var string
24
		 */
25
		private $prefix = '_cmb2_';
26
27
		/**
28
		 * Current field array.
29
		 * Store the current field while adding user defined fields
30
		 *
31
		 * @var array
32
		 */
33
		private $field = array();
34
35
		/**
36
		 * Current field arguments array.
37
		 * Store the current field arguments while adding user defined fields
38
		 *
39
		 * @var array
40
		 */
41
		private $field_args = array();
42
43
		/**
44
		 * Instance of this class.
45
		 *
46
		 * @var object
47
		 */
48
		protected static $instance;
49
50
		/**
51
		 * Initiate CMB2 Admin Extension object.
52
		 *
53
		 * @since 0.0.1
54
		 */
55
		public function __construct() {
56
57
			add_action( 'pre_current_active_plugins', array( $this, 'hide_cmb2_plugins' ) );
58
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
59
			add_action( 'cmb2_init', array( $this, 'init_user_defined_meta_boxes_and_fields' ) );
60
		}
61
62
		/**
63
		 * Return an instance of this class.
64
		 *
65
		 * @return object A single instance of this class.
66
		 */
67
		public static function get_instance() {
68
			// If the single instance hasn't been set, set it now.
69
			if ( self::$instance === null ) {
70
				self::$instance = new self;
71
			}
72
73
			return self::$instance;
74
		}
75
76
77
		/**
78
		 * Determine if current user has permission to CMB2 view plugins.
79
		 *
80
		 * @since  0.0.1
81
		 */
82
		public function is_cmb2_allowed() {
83
84
			$cmb2_settings = get_option( '_cmb2_settings' );
85
86
			if ( empty( $cmb2_settings ) ) {
87
				// No settings saved.
88
				return true;
89
			}
90
91
			$current_user  = wp_get_current_user();
92
			$allowed_users = isset( $cmb2_settings['_cmb2_user_multicheckbox'] ) ? $cmb2_settings['_cmb2_user_multicheckbox'] : array();
93
94
			return empty( $allowed_users ) || in_array( $current_user->ID, $allowed_users, true );
95
		}
96
97
		/**
98
		 * Only show CMB2 plugins to users defined in settings.
99
		 *
100
		 * @since  0.0.1
101
		 */
102
		public function hide_cmb2_plugins() {
103
104
			global $wp_list_table;
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...
105
			if ( ! $this->is_cmb2_allowed() ) {
106
				$to_hide = array( CMB2AE_CMB2_PLUGIN_FILE, 'cmb2-admin-extension/cmb2-admin-extension.php' );
107
				$plugins = $wp_list_table->items;
108
				foreach ( array_keys( $plugins ) as $key ) {
109
					if ( in_array( $key, $to_hide, true ) ) {
110
						unset( $wp_list_table->items[ $key ] );
111
					}
112
				}
113
			}
114
		}
115
116
		/**
117
		 * Enqueue CMB2 Admin Extension scripts and styles.
118
		 *
119
		 * @since  0.0.8
120
		 */
121
		public function enqueue_scripts() {
122
123
			$screen = get_current_screen();
124
			if ( $screen->post_type === 'meta_box' ) {
0 ignored issues
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
125
126
				wp_register_style( 'cmb2_admin_styles', CMB2AE_URI . '/css/meta-box-fields.css', false, '0.0.8' );
127
				wp_enqueue_style( 'cmb2_admin_styles' );
128
				wp_enqueue_script( 'cmb2_admin_scripts', CMB2AE_URI . '/js/meta-box-fields.js', true, array( 'jquery' ), '0.0.8' );
129
			}
130
		}
131
132
		/**
133
		 * Check if the field type is repeatable.
134
		 *
135
		 * @since  0.0.6
136
		 * @param  string $field_type A CMB2 field type.
137
		 * @return bollean.
0 ignored issues
show
Documentation introduced by
The doc-type bollean. could not be parsed: Unknown type name "bollean." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
138
		 */
139
		public function is_repeatable( $field_type ) {
140
141
			$repeatable_fields = array(
142
				'text',
143
				'text_small',
144
				'text_medium',
145
				'text_email',
146
				'text_url',
147
				'text_money',
148
				'textarea',
149
				'textarea_small',
150
				'textarea_code',
151
				'text_date',
152
				'text_time',
153
				'select_timezone',
154
				'text_date_timestamp',
155
				'text_datetime_timestamp',
156
				'text_datetime_timestamp_timezone',
157
				'colorpicker',
158
				'select',
159
				'multicheck',
160
				'multicheck_inline',
161
				'file',
162
				'file_list',
163
			);
164
			return in_array( $field_type, $repeatable_fields, true );
165
		}
166
167
		/**
168
		 * Check if field types should have the options argument.
169
		 *
170
		 * @since  0.0.6
171
		 * @param  string $field_type A CMB2 field type.
172
		 * @return bollean.
0 ignored issues
show
Documentation introduced by
The doc-type bollean. could not be parsed: Unknown type name "bollean." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
173
		 */
174
		public function has_options( $field_type ) {
175
176
			$options_fields = array(
177
				'radio',
178
				'radio_inline',
179
				'taxonomy_radio',
180
				'taxonomy_radio_inline',
181
				'select',
182
				'taxonomy_select',
183
				'multicheck',
184
				'multicheck_inline',
185
				'taxonomy_multicheck',
186
				'taxonomy_multicheck_inline',
187
			);
188
			return in_array( $field_type, $options_fields, true );
189
		}
190
191
		/**
192
		 * Conditional to check if the field argument should be added..
193
		 *
194
		 * @since 1.1.4
195
		 * @param string $options string of options for fields liek select.
196
		 */
197
		public function add_option_arg( $options ) {
198
199
			$options = explode( PHP_EOL, $options );
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $options. This often makes code more readable.
Loading history...
200
			foreach ( $options as $option ) {
201
				$opt_arr = explode( ',', $option );
202
				if ( ! isset( $opt_arr[1] ) ) {
203
					continue;
204
				}
205
				$field_options[ $opt_arr[0] ] = $opt_arr[1];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$field_options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $field_options = 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...
206
			}
207
			$this->field_args['options'] = $field_options;
0 ignored issues
show
Bug introduced by
The variable $field_options 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...
208
		}
209
210
		/**
211
		 * Conditional to check if the field argument should be added..
212
		 *
213
		 * @since 1.1.4
214
		 * @param array $arg_value A CMB2 field type.
215
		 */
216
		public function add_strpos_arg( $arg_value ) {
217
218
			if ( strpos( $this->field['_cmb2_field_type_select'], $arg_value[0] ) !== false && isset( $this->field[ $arg_value[2] ] ) && $this->field[ $arg_value[2] ] !== '' ) {
0 ignored issues
show
introduced by
Found "!== false". Use Yoda Condition checks, you must
Loading history...
219
220
				if ( is_array( $arg_value[1] ) ) {
221
					$this->field_args[ $arg_value[1][0] ][ $arg_value[1][1] ] = $this->field[ $arg_value[2] ];
222
					return;
223
				}
224
				$this->field_args[ $arg_value[1] ] = $this->field[ $arg_value[2] ];
225
			}
226
		}
227
228
		/**
229
		 * Conditional to check if the field argument should be added..
230
		 *
231
		 * @since 1.1.4
232
		 * @param string       $arg   Field definition.
233
		 * @param string|array $value A CMB2 field type.
234
		 */
235
		public function add_arg( $arg, $value ) {
236
237
			if ( $this->should_add_arg( $this->field, $arg, $value ) ) {
0 ignored issues
show
Bug introduced by
It seems like $value defined by parameter $value on line 235 can also be of type array; however, CMB2_Meta_Box::should_add_arg() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
238
239
				if ( is_array( $value ) ) {
240
241
					$this->field_args[ $arg ][ $value[0] ] = $this->field[ $value[1] ];
242
					return;
243
				}
244
				$this->field_args[ $arg ] = $this->field[ $value ];
245
			}
246
		}
247
248
		/**
249
		 * Conditional to check if the field argument should be added..
250
		 *
251
		 * @since  1.1.4
252
		 * @param  array  $field      Field definition.
253
		 * @param  string $field_type A CMB2 field type.
254
		 * @param  string $field_key  $field key to check.
255
		 * @return bollean.
0 ignored issues
show
Documentation introduced by
The doc-type bollean. could not be parsed: Unknown type name "bollean." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
256
		 */
257
		static function should_add_arg( $field, $field_type, $field_key ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
258
259
			return ( $field['_cmb2_field_type_select'] === $field_type && ( ! empty( $field[ $field_key ] ) && $field[ $field_key ] !== '' ) );
260
		}
261
262
		/**
263
		 * Loop through user defined meta_box and creates the custom meta boxes and fields.
264
		 *
265
		 * @since 0.0.1
266
		 */
267
		public function init_user_defined_meta_boxes_and_fields() {
268
269
			$args = array(
270
				'post_type'        => 'meta_box',
271
				'post_status'      => 'publish',
272
				'posts_per_page'   => -1,
0 ignored issues
show
introduced by
Disabling pagination is prohibited in VIP context, do not set posts_per_page to -1 ever.
Loading history...
273
				'suppress_filters' => false,
274
			);
275
276
			$prefix = $this->prefix;
277
278
			$user_meta_boxes = get_posts( $args );
279
280
			foreach ( $user_meta_boxes as $user_meta_box ) {
281
282
				$metabox_id = $user_meta_box->ID;
283
284
				$title          = get_the_title( $metabox_id );
285
				$id             = str_replace( '-', '_', $user_meta_box->post_name );
286
				$post_type      = cmbf( $metabox_id, $prefix . 'post_type_multicheckbox' );
287
				$context        = cmbf( $metabox_id, $prefix . 'context_radio' );
288
				$priority       = cmbf( $metabox_id, $prefix . 'priority_radio' );
289
				$show_names     = cmbf( $metabox_id, $prefix . 'show_names' ) === 'on' ? true : false;
290
				$disable_styles = cmbf( $metabox_id, $prefix . 'disable_styles' ) === 'on' ? true : false;
291
				$closed         = cmbf( $metabox_id, $prefix . 'closed' ) === 'on' ? true : false;
292
				$fields         = cmbf( $metabox_id, $prefix . 'custom_field' );
293
294
				/**
295
				 * Initiate the metabox.
296
				 */
297
				${ 'cmb_' . $id } = new_cmb2_box( array(
298
					'id'           => $id,
299
					'title'        => $title,
300
					'object_types' => $post_type, // Post type.
301
					'context'      => $context,
302
					'priority'     => $priority,
303
					'show_names'   => $show_names,
304
					'cmb_styles'   => $disable_styles,
305
					'closed'       => $closed,
306
				) );
307
308
				foreach ( $fields as $field ) {
309
310
					$this->field = $field;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
311
					$field_id    = '_' . strtolower( str_replace( ' ', '_', $field['_cmb2_name_text'] ) );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 4 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
312
					$this->field_args  = array(
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 1 space but found 2 spaces

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
313
						'name' => $field['_cmb2_name_text'],
314
						'desc' => $field['_cmb2_decription_textarea'],
315
						'id'   => $field_id,
316
						'type' => $field['_cmb2_field_type_select'],
317
					);
318
319
					$options = isset( $field['_cmb2_options_textarea'] ) ? $field['_cmb2_options_textarea'] : false;
320
					if ( $options ) {
321
						$this->add_option_arg( $options );
322
					}
323
					$should_add_strpos = array(
324
						array( 'tax', 'taxonomy', '_cmb2_tax_options_radio_inline' ),
325
						array( 'tax', array( 'options', 'no_terms_text' ), '_cmb2_no_terms_text' ),
326
						array( 'multicheck', 'select_all_button', '_cmb2_select_all_checkbox' ),
327
					);
328
					foreach ( $should_add_strpos as $arg_value ) {
329
						$this->add_strpos_arg( $arg_value );
330
					}
331
					if ( isset( $field['_cmb2_repeatable_checkbox'] ) && $field['_cmb2_repeatable_checkbox'] === 'on' && $this->is_repeatable( $field['_cmb2_field_type_select'] ) ) {
0 ignored issues
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
332
						$field_args['repeatable'] = true;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$field_args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $field_args = 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...
333
					}
334
					if ( isset( $field['_cmb2_none_checkbox'] ) && $field['_cmb2_none_checkbox'] === 'on' && $this->has_options( $field['_cmb2_field_type_select'] ) ) {
0 ignored issues
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
335
						$field_args['show_option_none'] = true;
0 ignored issues
show
Bug introduced by
The variable $field_args 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...
336
					}
337
					$should_add = array(
338
						'protocols' => '_cmb2_protocols_checkbox',
339
						'before_field' => '_cmb2_currency_text',
340
						'time_format' => '_cmb2_time_format',
341
						'date_format' => '_cmb2_date_format',
342
						'timezone_meta_key' => '_cmb2_time_zone_key_select',
343
						'options' => array( 'add_upload_file_text', '_cmb2_add_upload_file_text' ),
344
					);
345
					foreach ( $should_add as $arg => $value ) {
346
						$this->add_arg( $arg, $value );
347
					}
348
					${ 'cmb_' . $id }->add_field( $this->field_args );
349
350
				}
351
			}
352
		}
353
	}
354
}
355
356
if ( ! function_exists( 'cmb2ae_metabox' ) ) {
357
	/**
358
	 * Main instance of CMB2_Meta_Box.
359
	 *
360
	 * @since  0.1.0
361
	 * @return object Main instance of the CMB2_Meta_Box class.
362
	 */
363
	function cmb2ae_metabox() {
364
		return CMB2_Meta_Box::get_instance();
365
	}
366
}
367