Completed
Push — master ( 76a15f...c3bbc4 )
by Leon
03:22
created

CMB2_Meta_Box::string_to_bool()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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 ) || current_user_can( 'administrator' ) ) {
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', array(), '0.0.8' );
127
				wp_enqueue_style( 'cmb2_admin_styles' );
128
				wp_enqueue_script( 'cmb2_admin_scripts', CMB2AE_URI . '/js/meta-box-fields.js', array( 'jquery' ), '0.0.8', true );
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 boolean.
0 ignored issues
show
Documentation introduced by
The doc-type boolean. could not be parsed: Unknown type name "boolean." 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 boolean.
0 ignored issues
show
Documentation introduced by
The doc-type boolean. could not be parsed: Unknown type name "boolean." 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
		private 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 $field_options String of options for fields liek select.
196
		 */
197
		private function add_option_arg( $field_options ) {
198
			$field_options = preg_split( "/\\r\\n|\\r|\\n/", $field_options );
199
			$options       = array();
200
			foreach ( $field_options as $option ) {
201
				$opt_arr = explode( ',', $option );
202
				if ( ! isset( $opt_arr[1] ) ) {
203
					$options[ $option ] = $option;
204
					continue;
205
				}
206
				$options[ $opt_arr[0] ] = $opt_arr[1];
207
			}
208
			$this->field_args['options'] = $options;
209
		}
210
211
		/**
212
		 * Conditional to check if the field argument should be added..
213
		 *
214
		 * @since 1.1.4
215
		 * @param array $arg_value A CMB2 field type.
216
		 */
217
		public function add_strpos_arg( $arg_value ) {
218
219
			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...
220
221 View Code Duplication
				if ( is_array( $arg_value[1] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
222
					$this->field_args[ $arg_value[1][0] ][ $arg_value[1][1] ] = $this->field[ $arg_value[2] ];
223
					return;
224
				}
225
				$this->field_args[ $arg_value[1] ] = $this->field[ $arg_value[2] ];
226
			}
227
		}
228
229
		/**
230
		 * Add the field argument.
231
		 *
232
		 * @since 1.1.4
233
		 * @param string       $arg   Field definition.
234
		 * @param string|array $value A CMB2 field type.
235
		 */
236
		public function add_arg( $arg, $value ) {
237
238
			if ( $this->should_add_arg( $this->field, $arg, $value[1] ) ) {
239
240 View Code Duplication
				if ( is_array( $value[1] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
241
242
					$this->field_args[ $value[0] ][ $value[1][0] ] = $this->field[ $value[1][1] ];
243
					return;
244
				}
245
				$this->field_args[ $value[0] ] = $this->field[ $value[1] ];
246
			}
247
		}
248
249
		/**
250
		 * Conditional to check if the field argument should be added.
251
		 *
252
		 * @since  0.1.4
253
		 * @param  array  $field      Field definition.
254
		 * @param  string $field_type A CMB2 field type.
255
		 * @param  string $field_key  Field key to check.
256
		 * @return boolean.
0 ignored issues
show
Documentation introduced by
The doc-type boolean. could not be parsed: Unknown type name "boolean." 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...
257
		 */
258
		public static function should_add_arg( $field, $field_type, $field_key ) {
259
260
			return ( $field['_cmb2_field_type_select'] === $field_type && ( ! empty( $field[ $field_key ] ) && $field[ $field_key ] !== '' ) );
261
		}
262
263
		/**
264
		 * Add the current field to the metabox.
265
		 *
266
		 * @since  0.2.0
267
		 * @param array  $field Field definition.
268
		 * @param object $metabox Metabox object.
269
		 * @param mixed  $group_field_id If is reaptable group this is the ID, and false otherwise.
270
		 */
271
		public function add_field( $field, $metabox, $group_field_id ) {
272
273
			$field = wp_parse_args( $field, array(
274
				'_cmb2_name_text'           => null,
275
				'_cmb2_decription_textarea' => null,
276
				'_cmb2_field_type_select'   => null,
277
				'_cmb2_options_textarea'    => false,
278
				'_cmb2_repeatable_checkbox' => null,
279
				'_cmb2_none_checkbox'       => null,
280
			) );
281
282
			$this->field = $field;
283
			$field_id    = '_' . strtolower( str_replace( ' ', '_', $field['_cmb2_name_text'] ) );
284
285
			$this->field_args = array(
286
				'name' => $field['_cmb2_name_text'],
287
				'desc' => $field['_cmb2_decription_textarea'],
288
				'id'   => $field_id,
289
				'type' => $field['_cmb2_field_type_select'],
290
			);
291
292
			$field_options = $field['_cmb2_options_textarea'];
293
			if ( $field_options ) {
294
				$this->add_option_arg( $field_options );
295
			}
296
			$should_add_strpos = array(
297
				array( 'tax', 'taxonomy', '_cmb2_tax_options_radio_inline' ),
298
				array( 'tax', array( 'options', 'no_terms_text' ), '_cmb2_no_terms_text' ),
299
				array( 'multicheck', 'select_all_button', '_cmb2_select_all_checkbox' ),
300
			);
301
			foreach ( $should_add_strpos as $arg_value ) {
302
				$this->add_strpos_arg( $arg_value );
303
			}
304
			if ( $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...
305
				$this->field_args['repeatable'] = true;
306
			}
307
			if ( $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...
308
				$this->field_args['show_option_none'] = true;
309
			}
310
			$should_add = array(
311
				'text_url'                         => array( 'protocols', '_cmb2_protocols_checkbox' ),
312
				'text_money'                       => array( 'before_field', '_cmb2_currency_text' ),
313
				'text_time'                        => array( 'time_format', '_cmb2_time_format' ),
314
				'text_datetime_timestamp_timezone' => array( 'time_format', '_cmb2_time_format' ),
315
				'text_datetime_timestamp'          => array( 'time_format', '_cmb2_time_format' ),
316
				'text_date'                        => array( 'date_format', '_cmb2_date_format' ),
317
				'text_date_timestamp'              => array( 'date_format', '_cmb2_date_format' ),
318
				'select_timezone'                  => array( 'timezone_meta_key', '_cmb2_time_zone_key_select' ),
319
				'text_datetime_timestamp_timezone' => array( 'timezone_meta_key', '_cmb2_time_zone_key_select' ),
320
			);
321
			foreach ( $should_add as $arg => $value ) {
322
				$this->add_arg( $arg, $value );
323
			}
324
			if ( $group_field_id ) {
325
				$metabox->add_group_field( $group_field_id, array(
326
					'name' => 'Entry Title',
327
					'id'   => 'title',
328
					'type' => 'text',
329
				) );
330
				return;
331
			}
332
			$metabox->add_field( $this->field_args );
333
		}
334
335
		/**
336
		 * Covert the checkbox value of 'on' / '' to boolean.
337
		 *
338
		 * @since  0.2.0
339
		 * @param string $meta Sting value of checkbox on.
340
		 */
341
		public function string_to_bool( $meta ) {
0 ignored issues
show
Coding Style introduced by
function string_to_bool() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
342
343
			return $meta === 'on' ? true : false;
344
		}
345
346
		/**
347
		 * Get the metabox post meta.
348
		 *
349
		 * @since  0.2.0
350
		 * @param object $user_meta_box Post object.
351
		 */
352
		public function get_meta_data( $user_meta_box ) {
353
354
			$prefix     = $this->prefix;
355
			$metabox_id = $user_meta_box->ID;
356
357
			$meta_data['title']          = get_the_title( $metabox_id );
0 ignored issues
show
Coding Style Comprehensibility introduced by
$meta_data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $meta_data = 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...
358
			$meta_data['id']             = str_replace( '-', '_', $user_meta_box->post_name );
359
			$meta_data['post_type']      = cmbf( $metabox_id, $prefix . 'post_type_multicheckbox' );
360
			$meta_data['post_id_text']   = cmbf( $metabox_id, $prefix . 'post_id_text' );
361
			$meta_data['context']        = cmbf( $metabox_id, $prefix . 'context_radio' );
362
			$meta_data['priority']       = cmbf( $metabox_id, $prefix . 'priority_radio' );
363
			$meta_data['show_names']     = $this->string_to_bool( cmbf( $metabox_id, $prefix . 'show_names' ) );
364
			$meta_data['disable_styles'] = $this->string_to_bool( cmbf( $metabox_id, $prefix . 'disable_styles' ) );
365
			$meta_data['closed']         = $this->string_to_bool( cmbf( $metabox_id, $prefix . 'closed' ) );
366
			$meta_data['repeatable']     = $this->string_to_bool( cmbf( $metabox_id, $prefix . 'repeatable_group' ) );
367
			$meta_data['fields']         = cmbf( $metabox_id, $prefix . 'custom_field' );
368
369
			return $meta_data;
370
		}
371
372
		/**
373
		 * Loop through user defined meta_box and creates the custom meta boxes and fields.
374
		 *
375
		 * @since 0.0.1
376
		 */
377
		public function init_user_defined_meta_boxes_and_fields() {
378
379
			$args = array(
380
				'post_type'        => 'meta_box',
381
				'post_status'      => 'publish',
382
				'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...
383
				'suppress_filters' => false,
384
			);
385
386
			$user_meta_boxes = new WP_Query( $args );
387
388
			foreach ( $user_meta_boxes->posts as $user_meta_box ) {
389
390
				$meta_data = $this->get_meta_data( $user_meta_box );
391
				/**
392
				 * Initiate the metabox.
393
				 */
394
				$new_cmb2_args = array(
395
					'id'           => $meta_data['id'],
396
					'title'        => $meta_data['title'],
397
					'object_types' => $meta_data['post_type'], // Post type.
398
					'context'      => $meta_data['context'],
399
					'priority'     => $meta_data['priority'],
400
					'show_names'   => $meta_data['show_names'],
401
					'cmb_styles'   => $meta_data['disable_styles'],
402
					'closed'       => $meta_data['closed'],
403
				);
404
				if ( $meta_data['post_id_text'] !== '' ) {
405
406
					$new_cmb2_args['show_on'] = array(
407
						'key'   => 'id',
408
						'value' => explode( ',', $meta_data['post_id_text'] ),
409
					);
410
				}
411
				${ 'cmb_' . $meta_data['id'] } = new_cmb2_box( $new_cmb2_args );
412
				$meta_box                      = ${ 'cmb_' . $meta_data['id'] };
413
				$group_field_id                = false;
414
				if ( $meta_data['repeatable'] ) {
415
416
					$group_field_id = ${ 'cmb_' . $meta_data['id'] }->add_field( array(
417
						'id'          => $this->prefix . $meta_data['id'] . 'repeatable_group',
418
						'type'        => 'group',
419
						'description' => __( 'Generates reusable form entries', 'cmb2' ),
420
						'options'     => array(
421
							'group_title'   => __( 'Entry {#}', 'cmb2' ),
422
							'add_button'    => __( 'Add Another Entry', 'cmb2' ),
423
							'remove_button' => __( 'Remove Entry', 'cmb2' ),
424
							'sortable'      => true,
425
						),
426
					) );
427
				}
428
				foreach ( $meta_data['fields'] as $field ) {
429
430
					$this->add_field( $field, $meta_box, $group_field_id );
431
				}
432
			}
433
		}
434
	}
435
}
436
437
if ( ! function_exists( 'cmb2ae_metabox' ) ) {
438
	/**
439
	 * Main instance of CMB2_Meta_Box.
440
	 *
441
	 * @since  0.1.0
442
	 * @return object Main instance of the CMB2_Meta_Box class.
443
	 */
444
	function cmb2ae_metabox() {
445
		return CMB2_Meta_Box::get_instance();
446
	}
447
}
448