Completed
Push — master ( 29b812...365e74 )
by Marin
06:36
created

Helper::load_textdomain()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
ccs 0
cts 7
cp 0
rs 9.4286
cc 1
eloc 6
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Carbon_Fields\Helper;
4
5
use Carbon_Fields\Datastore\Datastore;
6
use Carbon_Fields\Container\Container;
7
use Carbon_Fields\Templater\Templater;
8
use Carbon_Fields\Manager\Sidebar_Manager;
9
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
10
11
/**
12
 * Helper functions and main initialization class.
13
 */
14
class Helper {
15
16
	/**
17
	 * Create a new helper. 
18
	 * Hook the main Carbon Fields initialization functionality.
19
	 */
20
	public function __construct() {
21
		add_action( 'wp_loaded', array( $this, 'trigger_fields_register' ) );
22
		add_action( 'carbon_after_register_fields', array( $this, 'init_containers' ) );
23
		add_action( 'admin_footer', array( $this, 'init_scripts' ), 0 );
24
		add_action( 'crb_field_activated', array( $this, 'add_templates' ) );
25
		add_action( 'crb_container_activated', array( $this, 'add_templates' ) );
26
		add_action( 'after_setup_theme', array( $this, 'load_textdomain' ), 9999 );
27
28
		# Initialize templater
29
		new Templater();
30
31
		# Initialize sidebar manager
32
		Sidebar_Manager::instance();
33
	}
34
35
	/**
36
	 * Load the plugin textdomain.
37
	 */
38
	public function load_textdomain() {
39
		$dir = dirname( dirname( dirname( __FILE__ ) ) ) . '/languages/';
40
		$domain = 'carbon_fields';
41
		$locale = get_locale();
42
		$path = $dir . $domain . '-' . $locale . '.mo';
43
		load_textdomain( $domain, $path );
44
	}
45
46
	/**
47
	 * Register containers and fields.
48
	 */
49
	public function trigger_fields_register() {
50
		try {
51
			do_action( 'carbon_register_fields' );
52
			do_action( 'carbon_after_register_fields' );	
53
		} catch ( Incorrect_Syntax_Exception $e ) {
54
			$callback = '';
55
			foreach ( $e->getTrace() as $trace ) {
56
				$callback .= '<br/>' . ( isset( $trace['file'] ) ? $trace['file'] . ':' . $trace['line'] : $trace['function'] . '()' );
57
			}
58
			wp_die( '<h3>' . $e->getMessage() . '</h3><small>' . $callback . '</small>' );
59
		}
60
	}
61
62
	/**
63
	 * Initialize containers.
64
	 */
65
	public function init_containers() {
66
		Container::init_containers();
67
	}
68
69
	/**
70
	 * Initialize main scripts
71
	 */
72
	public function init_scripts() {
73
		wp_enqueue_script( 'carbon-app', \Carbon_Fields\URL . '/assets/js/app.js', array( 'jquery', 'backbone', 'underscore', 'jquery-touch-punch', 'jquery-ui-sortable' ) );
74
		wp_enqueue_script( 'carbon-ext', \Carbon_Fields\URL . '/assets/js/ext.js', array( 'carbon-app' ) );
75
76
		wp_localize_script( 'carbon-app', 'carbon_json', $this->get_json_data() );
77
78
		$active_fields = Container::get_active_fields();
79
		$active_field_types = array();
80
81
		foreach ( $active_fields as $field ) {
82
			if ( in_array( $field->type, $active_field_types ) ) {
83
				continue;
84
			}
85
86
			$active_field_types[] = $field->type;
87
88
			$field->admin_enqueue_scripts();
89
		}
90
	}
91
92
	/**
93
	 * Retrieve containers and sidebars for use in the JS.
94
	 * 
95
	 * @return array $carbon_data
96
	 */
97
	public function get_json_data() {
98
		global $wp_registered_sidebars;
99
100
		$carbon_data = array(
101
			'containers' => array(),
102
			'sidebars' => array(),
103
		);
104
105
		$containers = Container::get_active_containers();
106
107
		foreach ( $containers as $container ) {
108
			$container_data = $container->to_json( true );
109
110
			$carbon_data['containers'][] = $container_data;
111
		}
112
113
		foreach ( $wp_registered_sidebars as $sidebar ) {
114
			// Check if we have inactive sidebars
115
			if ( isset( $sidebar['class'] ) && strpos( $sidebar['class'], 'inactive-sidebar' ) !== false ) {
1 ignored issue
show
introduced by
Found "!== false". Use Yoda Condition checks, you must
Loading history...
116
				continue;
117
			}
118
119
			$carbon_data['sidebars'][] = array(
120
				'name' => $sidebar['name'],
121
				'id'   => $sidebar['id'],
122
			);
123
		}
124
125
		return $carbon_data;
126
	}
127
128
	/**
129
	 * Retrieve post meta field for a post.
130
	 * 
131
	 * @param  int    $id   Post ID.
132
	 * @param  string $name Custom field name.
133
	 * @param  string $type Custom field type (optional).
134
	 * @return mixed        Meta value.
135
	 */
136
	public static function get_post_meta( $id, $name, $type = null ) {
137
		$name = $name[0] == '_' ? $name : '_' . $name;
138
139
		switch ( $type ) {
140
			case 'complex':
141
				$value = self::get_complex_fields( 'Post_Meta', $name, $id );
142
			break;
143
144
			case 'map':
145
			case 'map_with_address':
146
				$value =  array(
0 ignored issues
show
introduced by
Expected 1 space after "="; 2 found
Loading history...
147
					'lat' => (float) get_post_meta( $id, $name . '-lat', true ),
148
					'lng' => (float) get_post_meta( $id, $name . '-lng', true ),
149
					'address' => get_post_meta( $id, $name . '-address', true ),
150
					'zoom' => (int) get_post_meta( $id, $name . '-zoom', true ),
151
				);
152
				
153
				if ( ! array_filter( $value ) ) {
154
					$value = array();
155
				}
156
			break;
157
158
			case 'association':
159
				$raw_value = get_post_meta( $id, $name, true );
160
				$value = self::parse_relationship_field( $raw_value, $type );
161
			break;
162
163
			default:
164
				$value = get_post_meta( $id, $name, true );
165
166
				// backward compatibility for the old Relationship field
167
				$value = self::maybe_old_relationship_field( $value );
168
		}
169
170
		return $value;
171
	}
172
173
	/**
174
	 * Shorthand for get_post_meta().
175
	 * Uses the ID of the current post in the loop.
176
	 *
177
	 * @param  string $name Custom field name.
178
	 * @param  string $type Custom field type (optional).
179
	 * @return mixed        Meta value.
180
	 */
181
	public static function get_the_post_meta( $name, $type = null ) {
182
		return self::get_post_meta( get_the_ID(), $name, $type );
183
	}
184
185
	/**
186
	 * Retrieve theme option field value.
187
	 * 
188
	 * @param  string $name Custom field name.
189
	 * @param  string $type Custom field type (optional).
190
	 * @return mixed        Option value.
191
	 */
192
	public static function get_theme_option( $name, $type = null ) {
193
		switch ( $type ) {
194
			case 'complex':
195
				$value = self::get_complex_fields( 'Theme_Options', $name );
196
			break;
197
198
			case 'map':
199
			case 'map_with_address':
200
				$value =  array(
0 ignored issues
show
introduced by
Expected 1 space after "="; 2 found
Loading history...
201
					'lat' => (float) get_option( $name . '-lat' ),
202
					'lng' => (float) get_option( $name . '-lng' ),
203
					'address' => get_option( $name . '-address' ),
204
					'zoom' => (int) get_option( $name . '-zoom' ),
205
				);
206
207
				if ( ! array_filter( $value ) ) {
208
					$value = array();
209
				}
210
			break;
211
212
			case 'association':
213
				$raw_value = get_option( $name );
214
				$value = self::parse_relationship_field( $raw_value, $type );
215
			break;
216
217
			default:
218
				$value = get_option( $name );
219
220
				// backward compatibility for the old Relationship field
221
				$value = self::maybe_old_relationship_field( $value );
222
		}
223
224
		return $value;
225
	}
226
227
	/**
228
	 * Retrieve term meta field for a term.
229
	 * 
230
	 * @param  int    $id   Term ID.
231
	 * @param  string $name Custom field name.
232
	 * @param  string $type Custom field type (optional).
233
	 * @return mixed        Meta value.
234
	 */
235 View Code Duplication
	public static function get_term_meta( $id, $name, $type = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
236
		$name = $name[0] == '_' ? $name: '_' . $name;
237
238
		switch ( $type ) {
239
			case 'complex':
240
				$value = self::get_complex_fields( 'Term_Meta', $name, $id );
241
			break;
242
243
			case 'map':
244
			case 'map_with_address':
245
				$value =  array(
0 ignored issues
show
introduced by
Expected 1 space after "="; 2 found
Loading history...
246
					'lat' => (float) get_metadata( 'term', $id, $name . '-lat', true ),
247
					'lng' => (float) get_metadata( 'term', $id, $name . '-lng', true ),
248
					'address' => get_metadata( 'term', $id, $name . '-address', true ),
249
					'zoom' => (int) get_metadata( 'term', $id, $name . '-zoom', true ),
250
				);
251
252
				if ( ! array_filter( $value ) ) {
253
					$value = array();
254
				}
255
			break;
256
257
			case 'association':
258
				$raw_value = get_metadata( 'term', $id, $name, true );
259
				$value = self::parse_relationship_field( $raw_value, $type );
260
			break;
261
262
			default:
263
				$value = get_metadata( 'term', $id, $name, true );
264
265
				// backward compatibility for the old Relationship field
266
				$value = self::maybe_old_relationship_field( $value );
267
		}
268
269
		return $value;
270
	}
271
272
	/**
273
	 * Retrieve user meta field for a user.
274
	 * 
275
	 * @param  int    $id   User ID.
276
	 * @param  string $name Custom field name.
277
	 * @param  string $type Custom field type (optional).
278
	 * @return mixed        Meta value.
279
	 */
280 View Code Duplication
	public static function get_user_meta( $id, $name, $type = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
281
		$name = $name[0] == '_' ? $name: '_' . $name;
282
283
		switch ( $type ) {
284
			case 'complex':
285
				$value = self::get_complex_fields( 'User_Meta', $name, $id );
286
			break;
287
288
			case 'map':
289
			case 'map_with_address':
290
				$value =  array(
0 ignored issues
show
introduced by
Expected 1 space after "="; 2 found
Loading history...
291
					'lat' => (float) get_metadata( 'user', $id, $name . '-lat', true ),
292
					'lng' => (float) get_metadata( 'user', $id, $name . '-lng', true ),
293
					'address' => get_metadata( 'user', $id, $name . '-address', true ),
294
					'zoom' => (int) get_metadata( 'user', $id, $name . '-zoom', true ),
295
				);
296
297
				if ( ! array_filter( $value ) ) {
298
					$value = array();
299
				}
300
			break;
301
302
			case 'association':
303
				$raw_value = get_metadata( 'user', $id, $name, true );
304
				$value = self::parse_relationship_field( $raw_value, $type );
305
			break;
306
307
			default:
308
				$value = get_metadata( 'user', $id, $name, true );
309
310
				// backward compatibility for the old Relationship field
311
				$value = self::maybe_old_relationship_field( $value );
312
		}
313
314
		return $value;
315
	}
316
317
	/**
318
	 * Retrieve comment meta field for a comment.
319
	 * 
320
	 * @param  int    $id   Comment ID.
321
	 * @param  string $name Custom field name.
322
	 * @param  string $type Custom field type (optional).
323
	 * @return mixed        Meta value.
324
	 */
325 View Code Duplication
	public static function get_comment_meta( $id, $name, $type = null ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
326
		$name = $name[0] == '_' ? $name: '_' . $name;
327
328
		switch ( $type ) {
329
			case 'complex':
330
				$value = self::get_complex_fields( 'Comment_Meta', $name, $id );
331
			break;
332
333
			case 'map':
334
			case 'map_with_address':
335
				$value =  array(
0 ignored issues
show
introduced by
Expected 1 space after "="; 2 found
Loading history...
336
					'lat' => (float) get_metadata( 'comment', $id, $name . '-lat', true ),
337
					'lng' => (float) get_metadata( 'comment', $id, $name . '-lng', true ),
338
					'address' => get_metadata( 'comment', $id, $name . '-address', true ),
339
					'zoom' => (int) get_metadata( 'comment', $id, $name . '-zoom', true ),
340
				);
341
342
				if ( ! array_filter( $value ) ) {
343
					$value = array();
344
				}
345
			break;
346
347
			case 'association':
348
				$raw_value = get_metadata( 'comment', $id, $name, true );
349
				$value = self::parse_relationship_field( $raw_value, $type );
350
			break;
351
352
			default:
353
				$value = get_metadata( 'comment', $id, $name, true );
354
355
				// backward compatibility for the old Relationship field
356
				$value = self::maybe_old_relationship_field( $value );
357
		}
358
359
		return $value;
360
	}
361
362
	/**
363
	 * Adds the field/container template(s) to the templates stack.
364
	 *
365
	 * @param object $object field or container object
366
	 **/
367
	public function add_templates( $object ) {
368
		$templates = $object->get_templates();
369
370
		if ( ! $templates ) {
371
			return false;
372
		}
373
374
		foreach ( $templates as $name => $callback ) {
375
			ob_start();
376
377
			call_user_func( $callback );
378
379
			$html = ob_get_clean();
380
381
			// Add the template to the stack
382
			Templater::add_template( $name, $html );
383
		}
384
	}
385
386
	/**
387
	 * Build a string of concatenated pieces for an OR regex.
388
	 * 
389
	 * @param  array  $pieces Pieces
390
	 * @param  string $glue   Glue between the pieces
391
	 * @return string         Result string
392
	 */
393
	public static function preg_quote_array( $pieces, $glue = '|' ) {
394
		$pieces = array_map( 'preg_quote', $pieces, array( '~' ) );
395
		
396
		return implode( $glue, $pieces );
397
	}
398
399
	/**
400
	 * Build the regex for parsing a certain complex field.
401
	 * 
402
	 * @param  string $field_name  Name of the complex field.
403
	 * @param  array  $group_names Array of group names.
404
	 * @param  array  $field_names Array of subfield names.
405
	 * @return string              Regex
406
	 */
407
	public static function get_complex_field_regex( $field_name, $group_names = array(), $field_names = array() ) {
408
		if ( $group_names ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $group_names of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
409
			$group_regex = self::preg_quote_array( $group_names );
410
		} else {
411
			$group_regex = '\w*';
412
		}
413
414
		if ( $field_names ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $field_names of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
415
			$field_regex = self::preg_quote_array( $field_names );
416
		} else {
417
			$field_regex = '.*?';
418
		}
419
420
		return '~^' . preg_quote( $field_name, '~' ) . '(?P<group>' . $group_regex . ')-_?(?P<key>' . $field_regex . ')_(?P<index>\d+)_?(?P<sub>\w+)?(-(?P<trailing>.*))?$~';
421
	}
422
423
	/**
424
	 * Retrieve the complex field data for a certain field.
425
	 * 
426
	 * @param  string $type Datastore type.
427
	 * @param  string $name Name of the field.
428
	 * @param  int    $id   ID of the entry (optional).
429
	 * @return array        Complex data entries.
430
	 */
431
	public static function get_complex_fields( $type, $name, $id = null ) {
432
		$datastore = Datastore::factory( $type );
433
		
434
		if ( $id !== null ) {
435
			$datastore->set_id( $id );
436
		}
437
438
		$group_rows = $datastore->load_values( $name );
439
		$input_groups = array();
440
441
		foreach ( $group_rows as $row ) {
442
			if ( ! preg_match( self::get_complex_field_regex( $name ), $row['field_key'], $field_name ) ) {
443
					continue;
444
			}
445
			
446
			$row['field_value'] = maybe_unserialize( $row['field_value'] );
447
448
			// backward compatibility for Relationship field
449
			$row['field_value'] = self::parse_relationship_field( $row['field_value'] );
450
451
			$input_groups[ $field_name['index'] ]['_type'] = $field_name['group'];
452
			if ( ! empty( $field_name['trailing'] ) ) {
453
				$input_groups = self::expand_nested_field( $input_groups, $row, $field_name );
0 ignored issues
show
Documentation introduced by
$field_name is of type array<integer|string,str...,{"trailing":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
454 View Code Duplication
			} else if ( ! empty( $field_name['sub'] ) ) {
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...
455
				$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $field_name['sub'] ] = $row['field_value'];
456
			} else {
457
				$input_groups[ $field_name['index'] ][ $field_name['key'] ] = $row['field_value'];
458
			}
459
		}
460
461
		// create groups list with loaded fields
462
		self::ksort_recursive( $input_groups );
463
464
		return $input_groups;
465
	}
466
467
	/**
468
	 * Recursively expand the subfields of a complex field.
469
	 * 
470
	 * @param  array  $input_groups Input groups.
471
	 * @param  array  $row          Data row (key and value).
472
	 * @param  string $field_name   Name of the field.
473
	 * @return array                Expanded data.
474
	 */
475
	public static function expand_nested_field( $input_groups, $row, $field_name ) {
476
		$subfield_key_token = $field_name['key'] . '_' . $field_name['sub'] . '-' . $field_name['trailing'];
477
		if ( ! preg_match( self::get_complex_field_regex( $field_name['key'] ), $subfield_key_token, $subfield_name ) ) {
478
			return $input_groups;
479
		}
480
481
		$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $subfield_name['index'] ]['_type'] = $subfield_name['group'];
482
483
		if ( ! empty( $subfield_name['trailing'] ) ) {
484
			$input_groups[ $field_name['index'] ][ $field_name['key'] ] = self::expand_nested_field( $input_groups[ $field_name['index'] ][ $field_name['key'] ], $row, $subfield_name );
0 ignored issues
show
Documentation introduced by
$subfield_name is of type array<integer|string,str...,{"trailing":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
485 View Code Duplication
		} else if ( ! empty( $subfield_name['sub'] ) ) {
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...
486
			$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $subfield_name['index'] ][ $subfield_name['key'] ][ $subfield_name['sub'] ] = $row['field_value'];
487
		} else {
488
			$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $subfield_name['index'] ][ $subfield_name['key'] ] = $row['field_value'];
489
		}
490
491
		return $input_groups;
492
	}
493
494
	/**
495
	 * Parse the raw value of the relationship and association fields.
496
	 * 
497
	 * @param  string $raw_value Raw relationship value.
498
	 * @param  string $type      Field type.
499
	 * @return array             Array of parsed data.
500
	 */
501
	public static function parse_relationship_field( $raw_value = '', $type = '' ) {
502
		if ( $raw_value && is_array( $raw_value ) ) {
503
			$value = array();
504
			foreach ( $raw_value as $raw_value_item ) {
505
				if ( is_string( $raw_value_item ) && strpos( $raw_value_item, ':' ) !== false ) {
1 ignored issue
show
introduced by
Found "!== false". Use Yoda Condition checks, you must
Loading history...
506
					$item_data = explode( ':', $raw_value_item );
507
					$item = array(
508
						'id' => $item_data[2],
509
						'type' => $item_data[0],
510
					);
511
512
					if ( $item_data[0] === 'post' ) {
1 ignored issue
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
513
						$item['post_type'] = $item_data[1];
514
					} elseif ( $item_data[0] === 'term' ) {
1 ignored issue
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
515
						$item['taxonomy'] = $item_data[1];
516
					}
517
518
					$value[] = $item;
519
				} elseif ( $type === 'association' ) {
1 ignored issue
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
520
					$value[] = array(
521
						'id' => $raw_value_item,
522
						'type' => 'post',
523
						'post_type' => get_post_type( $raw_value_item ),
524
					);
525
				} else {
526
					$value[] = $raw_value_item;
527
				}
528
			}
529
530
			$raw_value = $value;
531
		}
532
533
		return $raw_value;
534
	}
535
536
	/**
537
	 * Detect if using the old way of storing the relationship field values.
538
	 * If so, parse them to the new way of storing the data. 
539
	 * 
540
	 * @param  mixed $value Old field value.
541
	 * @return mixed        New field value.
542
	 */
543
	public static function maybe_old_relationship_field( $value ) {
544
		if ( is_array( $value ) && ! empty( $value ) ) {
545
			if ( preg_match( '~^\w+:\w+:\d+$~', $value[0] ) ) {
546
				$new_value = array();
547
				foreach ( $value as $value_entry ) {
548
					$pieces = explode( ':', $value_entry );
549
					$new_value[] = $pieces[2];
550
				}
551
				$value = $new_value;
552
			}
553
		}
554
555
		return $value;
556
	}
557
558
	/**
559
	 * Recursive sorting function by array key.
560
	 * @param  array  &$array     The input array.
561
	 * @param  int    $sort_flags Flags for controlling sorting behavior.
562
	 * @return array              Sorted array.
563
	 */
564
	public static function ksort_recursive( &$array, $sort_flags = SORT_REGULAR ) {
565
		if ( ! is_array( $array ) ) {
566
			return false;
567
		}
568
569
		ksort( $array, $sort_flags );
570
		foreach ( $array as $key => $value ) {
571
			self::ksort_recursive( $array[ $key ], $sort_flags );
572
		}
573
574
		return true;
575
	}
576
577
}