MetaboxTypes   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 313
Duplicated Lines 9.58 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 30
loc 313
rs 8.3157
c 0
b 0
f 0
wmc 43
lcom 1
cbo 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
B get_metaboxes() 0 22 4
B get_acf_free_metaboxes() 0 32 5
B is_acf_field_in_post_type() 0 18 5
C get_all_acf_field_groups() 0 50 10
C get_cmb2_metaboxes() 15 58 10
B get_cmb1_metaboxes() 15 35 5
A add_source() 0 13 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like MetaboxTypes often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MetaboxTypes, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace DummyPress;
3
4
/**
5
 * Class for handling CMB data
6
 *
7
 * @package    WordPress
8
 * @subpackage Evans
9
 * @author     Mike Selander
10
 */
11
class MetaboxTypes {
12
13
	/**
14
	 * Decide which cmb library to try and loop to get our metaboxes.
15
	 *
16
	 * Due to supporting multiple CMB libraries, we need to check which library
17
	 * is used on our site and then run the appropriate function. Currently
18
	 * supported libraries are CMB2 & Custom Metaboxes and Fields.
19
	 *
20
	 * @see get_cmb2_metaboxes, get_cmb1_metaboxes
21
	 *
22
	 * @param string $slug Post Type slug ID.
23
	 * @return array Fields to fill in for our post object.
24
	 */
25
	public function get_metaboxes( $slug ) {
26
		$cmb2_fields = $cmb_fields = $acf_fields = array();
27
28
		// CMB2
29
		if ( class_exists( 'CMB2', false ) ) {
30
			$cmb2_fields = $this->get_cmb2_metaboxes( $slug );
31
		}
32
33
		// Custom Metaboxes and Fields (CMB1)
34
		if ( class_exists( 'cmb_Meta_Box', false ) ) {
35
			$cmb_fields = $this->get_cmb1_metaboxes( $slug );
36
		}
37
38
		// Advanced Custom Fields (ACF Free)
39
		if ( class_exists( 'acf', false ) ) {
40
			$acf_fields = $this->get_acf_free_metaboxes( $slug );
41
		}
42
43
		// Return our array
44
		return array_merge( $cmb2_fields, $cmb_fields, $acf_fields );
45
46
	}
47
48
49
	/**
50
	 * Gets the metaboxes assigned to a custom post type in ACF.
51
	 *
52
	 * @access private
53
	 *
54
	 * @see get_all_acf_field_groups, is_acf_field_in_post_type
55
	 *
56
	 * @param string $slug Post type.
57
	 * @return array Fields array.
58
	 */
59
	private function get_acf_free_metaboxes( $slug ) {
60
61
		$fields = array();
62
63
		// This damn plugin. Is. A. Freaking. Nightmare.
64
		$fieldsets = $this->get_all_acf_field_groups();
65
66
		// Return empty array if there are no fieldsets at all
67
		if ( empty( $fieldsets ) ) {
68
			return $fields;
69
		}
70
71
		// Loop through each fieldset for possible matches
72
		foreach ( $fieldsets as $fieldset ) {
73
74
			if ( $this->is_acf_field_in_post_type( $slug, $fieldset ) ) {
75
76
				// If this is the first group of fields, simply set the value
77
				// Else, merge this group with the previous one
78
				if ( empty( $fields ) ) {
79
					$fields = $fieldset->fields;
80
				} else {
81
					$fields = array_merge( $fields, $fieldset->fields );
82
				}
83
84
			}
85
86
		}
87
88
		return $fields;
89
90
	}
91
92
93
	/**
94
	 * Check if a group of fields is in a custom post type.
95
	 *
96
	 * @access private
97
	 *
98
	 * @param string $slug Post type slug.
99
	 * @param object $fieldset Fieldset group.
100
	 * @return boolean Whether or not the grouping is assigned to the post type.
101
	 */
102
	private function is_acf_field_in_post_type( $slug, $fieldset ) {
103
104
		// Make sure we have something to parse
105
		if ( empty( $fieldset ) ) {
106
			return false;
107
		}
108
109
		// Loop through the rules to check for post type matches
110
		foreach ( $fieldset->rules as $rule ) {
111
			if ( $rule['param'] === 'post_type' && $rule['value'] === $slug ) {
112
				return true;
113
			}
114
		}
115
116
		// Everything passed, yay!
117
		return false;
118
119
	}
120
121
122
	/**
123
	 * Loop through and retrive all acf cpts and cmb.
124
	 *
125
	 * ACF stores their data in custom post types and unfortunately named cmbs.
126
	 * Therefore, we have to loop through all acfs and sort through the mish-mash
127
	 * of messy data and make something clean of it.
128
	 *
129
	 * @access private
130
	 *
131
	 * @return array All acf fieldsets.
132
	 */
133
	private function get_all_acf_field_groups() {
134
		$info = $rules = $fields = array();
135
136
		$args = array(
137
			'post_type'		=> 'acf',
138
			'posts_per_page'=> 500
139
		);
140
141
		$objects = new \WP_Query( $args );
142
143
		if ( $objects->have_posts() ) :
144
			while ( $objects->have_posts() ) : $objects->the_post();
145
146
				$data = get_metadata( 'post', get_the_id() );
147
148
				foreach ( $data['rule'] as $rule ) {
149
					$rules[] = unserialize( $rule );
150
				}
151
152
				foreach ( $data as $key => $value ) {
153
					if ( substr( $key, 0, 6 ) == 'field_' ) :
154
						$field_detail = unserialize( $value[0] );
155
						$fields[] = array(
156
							'key'	 => $field_detail['key'],
157
							'type'	 => $field_detail['type'],
158
							'name'	 => $field_detail['label'],
159
							'id'	 => $field_detail['name'],
160
							'extras' => (object) array(
161
								'chars'	 => ( isset( $field_detail['maxlength'] ) ? $field_detail['maxlength'] : '' ),
162
								'max'	 => ( isset( $field_detail['max'] ) ? $field_detail['max'] : '' ),
163
								'min'	 => ( isset( $field_detail['min'] ) ? $field_detail['min'] : '' ),
164
							),
165
							'options' => ( isset( $field_detail['choices'] ) ? $field_detail['choices'] : '' ),
166
							'source' =>'acf',
167
						);
168
169
					endif;
170
				}
171
172
				$info[] = (object) array(
173
					'rules'		=> $rules,
174
					'fields'	=> $fields
175
				);
176
177
			endwhile;
178
		endif;
179
180
		return $info;
181
182
	}
183
184
185
	/**
186
	 * Gets all CMB2 custom metaboxes associated with a post type.
187
	 *
188
	 * Loops through all custom metabox fields registered with CMB2 and
189
	 * looks through them for matches on the given post type ID. Returns a single
190
	 * array of all boxes associated with the post type.
191
	 *
192
	 * @access private
193
	 *
194
	 * @see cmb2_meta_boxes
195
	 *
196
	 * @param string $slug a custom post type ID.
197
	 * @return array Array of fields.
198
	 */
199
	private function get_cmb2_metaboxes( $slug ) {
200
201
		$fields = array();
202
203
		// Get all metaboxes from CMB2 library
204
		$all_metaboxes = apply_filters( 'cmb2_meta_boxes', array() );
205
206
		// Loop through all possible sets of metaboxes added the old way
207 View Code Duplication
		foreach ( $all_metaboxes as $metabox_array ) {
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...
208
209
			// If the custom post type ID matches this set of fields, set & stop
210
			if ( in_array( $slug, $metabox_array['object_types'] ) ) {
211
212
				// If this is the first group of fields, simply set the value
213
				// Else, merge this group with the previous one
214
				if ( empty( $fields ) ) {
215
					$fields = $metabox_array['fields'];
216
				} else {
217
					$fields = array_merge( $fields, $metabox_array['fields'] );
218
				}
219
			}
220
221
		}
222
223
		// Loop through all metaboxes added the new way
224
		foreach ( \CMB2_Boxes::get_all() as $cmb ) {
225
226
			// Create the default
227
			$match = false;
228
229
			// Establish correct cmb types
230
			if ( is_string( $cmb->meta_box['object_types'] ) ) {
231
				if ( $cmb->meta_box['object_types'] == $slug ) {
232
					$match = true;
233
				}
234
			} else {
235
				if ( in_array( $slug, $cmb->meta_box['object_types'] ) ) {
236
					$match = true;
237
				}
238
			}
239
240
			if ( $match !== true ) {
241
				continue;
242
			}
243
244
			if ( empty( $fields ) ) {
245
				$fields = $cmb->meta_box['fields'];
246
			} else {
247
				$fields = array_merge( $fields, $cmb->meta_box['fields'] );
248
			}
249
250
		}
251
252
		$fields = $this->add_source( $fields, 'cmb2' );
253
254
		return $fields;
255
256
	}
257
258
259
	/**
260
	 * Gets all CMB1 custom metaboxes associated with a post type.
261
	 *
262
	 * Loops through all custom metabox fields registered with CMB2 and
263
	 * looks through them for matches on the given post type ID. Returns a single
264
	 * array of all boxes associated with the post type.
265
	 *
266
	 * @access private
267
	 *
268
	 * @see cmb_meta_boxes
269
	 *
270
	 * @param string $slug a custom post type ID.
271
	 * @return array Array of fields.
272
	 */
273
	private function get_cmb1_metaboxes( $slug ) {
274
275
		$fields = array();
276
277
		// Get all metaboxes from CMB2 library
278
		$all_metaboxes = apply_filters( 'cmb_meta_boxes', array() );
279
280
		// Loop through all possible sets of metaboxes
281 View Code Duplication
		foreach ( $all_metaboxes as $metabox_array ) {
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...
282
283
			// If the custom post type ID matches this set of fields, set & stop
284
			if ( in_array( $slug, $metabox_array['pages'] ) ) {
285
286
				// If this is the first group of fields, simply set the value
287
				// Else, merge this group with the previous one
288
				if ( empty( $fields ) ) {
289
					$fields = $metabox_array['fields'];
290
				} else {
291
					$fields = array_merge( $fields, $metabox_array['fields'] );
292
				}
293
			}
294
295
		}
296
297
		// Identify Human Made's CMB library
298
		if ( defined( 'CMB_DEV' ) ) {
299
			$fields = $this->add_source( $fields, 'cmb_hm' );
300
		// Default to CMB1 library
301
		} else {
302
			$fields = $this->add_source( $fields, 'cmb1' );
303
		}
304
305
		return $fields;
306
307
	}
308
309
	private function add_source( $fields, $source ) {
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
310
311
		if ( empty( $fields ) || empty( $source ) ) {
312
			return $fields;
313
		}
314
315
		foreach ( $fields as $key => $value ) {
316
			$fields[ $key ]['source'] = $source;
317
		}
318
319
		return $fields;
320
321
	}
322
323
}
324