Completed
Pull Request — 2.x (#4569)
by Scott Kingsley
08:49
created

PodsComponents   D

Complexity

Total Complexity 168

Size/Duplication

Total Lines 843
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 843
rs 4.4444
c 0
b 0
f 0
wmc 168
lcom 2
cbo 2

16 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 8 2
B __construct() 0 29 4
F menu() 0 141 32
D load() 0 74 20
D get_components() 0 182 45
B options() 0 12 6
B admin_handler() 0 19 7
A admin() 0 10 2
A is_component_active() 0 11 4
B activate_component() 0 24 4
A deactivate_component() 0 11 3
A toggle() 0 17 2
C admin_capabilities() 0 34 11
D admin_ajax() 0 65 17
C admin_ajax_settings() 0 34 7
A update_settings() 0 11 2

How to fix   Complexity   

Complex Class

Complex classes like PodsComponents 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 PodsComponents, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Component managing class
5
 *
6
 * @package Pods
7
 */
8
class PodsComponents {
9
10
	/**
11
	 * @var PodsComponents
12
	 */
13
	public static $instance = null;
14
15
	/**
16
	 * Root of Components directory
17
	 *
18
	 * @var string
19
	 *
20
	 * @private
21
	 * @since 2.0
22
	 */
23
	private $components_dir = null;
24
25
	/**
26
	 * Available components
27
	 *
28
	 * @var array
29
	 *
30
	 * @since 2.0
31
	 */
32
	public $components = array();
33
34
	/**
35
	 * Components settings
36
	 *
37
	 * @var array
38
	 *
39
	 * @since 2.0
40
	 */
41
	public $settings = array();
42
43
	/**
44
	 * Singleton handling for a basic pods_components() request
45
	 *
46
	 * @return \PodsComponents
47
	 *
48
	 * @since 2.3.5
49
	 */
50
	public static function init() {
51
52
		if ( ! is_object( self::$instance ) ) {
53
			self::$instance = new self();
54
		}
55
56
		return self::$instance;
57
	}
58
59
	/**
60
	 * Setup actions and get options
61
	 *
62
	 * @since 2.0
63
	 */
64
	public function __construct() {
65
66
		$this->components_dir = realpath( apply_filters( 'pods_components_dir', PODS_DIR . 'components' ) ) . '/';
67
68
		$settings = get_option( 'pods_component_settings', '' );
69
70
		if ( ! empty( $settings ) ) {
71
			$this->settings = (array) json_decode( $settings, true );
72
		}
73
74
		if ( ! isset( $this->settings['components'] ) ) {
75
			$this->settings['components'] = array();
76
		}
77
78
		// Get components (give it access to theme)
79
		add_action( 'setup_theme', array( $this, 'get_components' ), 11 );
80
81
		// Load in components
82
		add_action( 'setup_theme', array( $this, 'load' ), 12 );
83
84
		// AJAX handling
85
		if ( is_admin() ) {
86
			add_action( 'wp_ajax_pods_admin_components', array( $this, 'admin_ajax' ) );
87
			add_action( 'wp_ajax_nopriv_pods_admin_components', array( $this, 'admin_ajax' ) );
88
89
			// Add the Pods Components capabilities
90
			add_filter( 'members_get_capabilities', array( $this, 'admin_capabilities' ) );
91
		}
92
	}
93
94
	/**
95
	 * Add menu item
96
	 *
97
	 * @param string $parent The parent slug.
98
	 *
99
	 * @since 2.0
100
	 *
101
	 * @uses  add_submenu_page
102
	 */
103
	public function menu( $parent ) {
104
105
		global $submenu;
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...
106
107
		$custom_component_menus = array();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $custom_component_menus exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
108
109
		$pods_component_menu_items = array();
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $pods_component_menu_items exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
110
111
		foreach ( $this->components as $component => $component_data ) {
112
			$component_id = $component_data['ID'];
113
114
			$component_data['MustUse'] = apply_filters( 'pods_component_require_' . $component_id, $component_data['MustUse'], $component_data );
115
116
			if ( empty( $component_data['MustUse'] ) && ( ! isset( $this->settings['components'][ $component ] ) || 0 === $this->settings['components'][ $component ] ) ) {
117
				continue;
118
			}
119
120
			if ( ! empty( $component_data['Hide'] ) ) {
121
				continue;
122
			}
123
124
			if ( ! empty( $component_data['DeveloperMode'] ) && ! pods_developer() ) {
125
				continue;
126
			}
127
128
			if ( empty( $component_data['TablelessMode'] ) && pods_tableless() ) {
129
				continue;
130
			}
131
132
			if ( empty( $component_data['MenuPage'] ) ) {
133
				if ( ! isset( $component_data['object'] ) ) {
134
					continue;
135
				} elseif ( ! method_exists( $component_data['object'], 'admin' ) && ! method_exists( $component_data['object'], 'options' ) ) {
136
					continue;
137
				}
138
			}
139
140
			if ( false === $component_data['External'] ) {
141
				$component_data['File'] = realpath( $this->components_dir . $component_data['File'] );
142
			}
143
144
			if ( ! file_exists( $component_data['File'] ) ) {
145
				pods_message( 'Pods Component not found: ' . $component_data['File'] );
146
147
				pods_transient_clear( 'pods_components' );
148
149
				continue;
150
			}
151
152
			$capability = 'pods_component_' . str_replace( '-', '_', sanitize_title( $component ) );
153
154
			if ( 0 < strlen( $component_data['Capability'] ) ) {
155
				$capability = $component_data['Capability'];
156
			}
157
158
			if ( ! pods_is_admin( array( 'pods', 'pods_components', $capability ) ) ) {
159
				continue;
160
			}
161
162
			$menu_page = 'pods-component-' . $component;
163
164
			if ( ! empty( $component_data['MenuPage'] ) ) {
165
				$custom_component_menus[ $menu_page ] = $component_data;
166
			}
167
168
			$pods_component_menu_items[ $component_data['MenuName'] ] = array(
169
				'menu_page'  => $menu_page,
170
				'page_title' => $component_data['Name'],
171
				'capability' => 'read',
172
				'callback'   => array( $this, 'admin_handler' ),
173
			);
174
175
			if ( isset( $component_data['object'] ) && method_exists( $component_data['object'], 'admin_assets' ) ) {
176
				$pods_component_menu_items[ $component_data['MenuName'] ]['assets'] = array(
177
					$component_data['object'],
178
					'admin_assets',
179
				);
180
			}
181
		}//end foreach
182
183
		/**
184
		 * Add or change the items in the Pods Components Submenu.
185
		 *
186
		 * Can also be used to change which menu components is a submenu of or change title of menu.
187
		 *
188
		 * @param array $pods_component_menu_items {
189
		 *      An array of arguments for add_submenu_page
190
		 *
191
		 *     @type string $parent_slug The slug name for the parent menu (or the file name of a standard WordPress admin page)
192
		 *     @type string $page_title  The text to be displayed in the title tags of the page when the menu is selected
193
		 *     @type string $menu_title  The text to be used for the menu
194
		 *     @type string $capability  The capability required for this menu to be displayed to the user.
195
		 *     @type string $menu_slug   The slug name to refer to this menu by (should be unique for this menu)
196
		 *     @type string $function    The function to be called to output the content for this page.
197
		 * }
198
		 *
199
		 * @since  2.4.1
200
		 */
201
		$pods_component_menu_items = apply_filters( 'pods_admin_components_menu', $pods_component_menu_items );
202
203
		ksort( $pods_component_menu_items );
204
205
		foreach ( $pods_component_menu_items as $menu_title => $menu_data ) {
206
			if ( ! is_callable( $menu_data['callback'] ) ) {
207
				continue;
208
			}
209
210
			$page = add_submenu_page( $parent, strip_tags( $menu_data['page_title'] ), '- ' . strip_tags( $menu_title ), pods_v( 'capability', $menu_data, 'read', true ), $menu_data['menu_page'], $menu_data['callback'] );
211
212
			if ( isset( $menu_data['assets'] ) && is_callable( $menu_data['assets'] ) ) {
213
				add_action( 'admin_print_styles-' . $page, $menu_data['assets'] );
214
			}
215
		}
216
217
		if ( ! empty( $custom_component_menus ) ) {
218
			foreach ( $custom_component_menus as $menu_page => $component_data ) {
219
				if ( isset( $submenu[ $parent ] ) ) {
220
					foreach ( $submenu[ $parent ] as $sub => &$menu ) {
221
						if ( $menu[2] === $menu_page ) {
222
							$menu_page = $component_data['MenuPage'];
223
224
							$menu[2] = $menu_page;
225
226
							$page = current( explode( '?', $menu[2] ) );
227
228
							if ( isset( $component_data['object'] ) && method_exists( $component_data['object'], 'admin_assets' ) ) {
229
								add_action(
230
									'admin_print_styles-' . $page, array(
231
										$component_data['object'],
232
										'admin_assets',
233
									)
234
								);
235
							}
236
237
							break;
238
						}//end if
239
					}//end foreach
240
				}//end if
241
			}//end foreach
242
		}//end if
243
	}
244
245
	/**
246
	 * Load activated components and init component
247
	 *
248
	 * @since 2.0
249
	 */
250
	public function load() {
251
252
		do_action( 'pods_components_load' );
253
254
		foreach ( (array) $this->components as $component => $component_data ) {
255
			$component_id = $component_data['ID'];
256
257
			$component_data['MustUse'] = apply_filters( 'pods_component_require_' . $component_id, $component_data['MustUse'], $component_data );
258
259
			if ( false === $component_data['MustUse'] && ( ! isset( $this->settings['components'][ $component ] ) || 0 === $this->settings['components'][ $component ] ) ) {
260
				continue;
261
			}
262
263
			if ( ! empty( $component_data['PluginDependency'] ) ) {
264
				$dependency = explode( '|', $component_data['PluginDependency'] );
265
266
				if ( ! pods_is_plugin_active( $dependency[1] ) ) {
267
					continue;
268
				}
269
			}
270
271
			if ( ! empty( $component_data['ThemeDependency'] ) ) {
272
				$dependency = explode( '|', $component_data['ThemeDependency'] );
273
274
				$check = strtolower( $dependency[1] );
275
276
				if ( strtolower( get_template() ) !== $check && strtolower( get_stylesheet() ) !== $check ) {
277
					continue;
278
				}
279
			}
280
281
			if ( false === $component_data['External'] ) {
282
				$component_data['File'] = realpath( $this->components_dir . $component_data['File'] );
283
			}
284
285
			if ( empty( $component_data['File'] ) ) {
286
				pods_transient_clear( 'pods_components' );
287
288
				continue;
289
			}
290
291
			if ( ! file_exists( $component_data['File'] ) ) {
292
				pods_message( 'Pods Component not found: ' . $component_data['File'] );
293
294
				pods_transient_clear( 'pods_components' );
295
296
				continue;
297
			}
298
299
			include_once $component_data['File'];
300
301
			if ( ( ! empty( $component_data['Class'] ) && class_exists( $component_data['Class'] ) ) || isset( $component_data['object'] ) ) {
302
				if ( ! isset( $this->components[ $component ]['object'] ) ) {
303
					$this->components[ $component ]['object'] = new $component_data['Class']();
304
				}
305
306
				if ( method_exists( $this->components[ $component ]['object'], 'options' ) ) {
307
					if ( isset( $this->settings['components'][ $component ] ) ) {
308
						$this->components[ $component ]['options'] = $this->components[ $component ]['object']->options( $this->settings['components'][ $component ] );
309
					} else {
310
						$this->components[ $component ]['options'] = $this->components[ $component ]['object']->options( array() );
311
					}
312
313
					$this->options( $component, $this->components[ $component ]['options'] );
314
				} else {
315
					$this->options( $component, array() );
316
				}
317
318
				if ( method_exists( $this->components[ $component ]['object'], 'handler' ) ) {
319
					$this->components[ $component ]['object']->handler( $this->settings['components'][ $component ] );
320
				}
321
			}//end if
322
		}//end foreach
323
	}
324
325
	/**
326
	 * Get list of components available
327
	 *
328
	 * @since 2.0
329
	 */
330
	public function get_components() {
331
332
		$components = pods_transient_get( 'pods_components' );
333
334
		if ( 1 === (int) pods_v( 'pods_debug_components', 'get', 0 ) && pods_is_admin( array( 'pods' ) ) ) {
335
			$components = array();
336
		}
337
338
		if ( PODS_VERSION !== PodsInit::$version || ! is_array( $components ) || empty( $components ) || ( is_admin() && 'pods-components' === pods_v( 'page', 'get' ) && 1 !== (int) pods_transient_get( 'pods_components_refresh' ) ) ) {
339
			do_action( 'pods_components_get' );
340
341
			// @codingStandardsIgnoreLine
342
			$component_dir   = @opendir( untrailingslashit( $this->components_dir ) );
343
			$component_files = array();
344
345
			if ( false !== $component_dir ) {
346
				$file = readdir( $component_dir );
347
348
				while ( false !== $file ) {
349
					if ( '.' === substr( $file, 0, 1 ) ) {
350
						// Get next file
351
						$file = readdir( $component_dir );
352
353
						continue;
354
					} elseif ( is_dir( $this->components_dir . $file ) ) {
355
						// @codingStandardsIgnoreLine
356
						$component_subdir = @opendir( $this->components_dir . $file );
357
358
						if ( $component_subdir ) {
359
							$subfile = readdir( $component_subdir );
360
361
							while ( false !== $subfile ) {
362
								if ( '.' === substr( $subfile, 0, 1 ) ) {
363
									// Get next file
364
									$subfile = readdir( $component_subdir );
365
366
									continue;
367
								} elseif ( '.php' === substr( $subfile, - 4 ) ) {
368
									$component_files[] = str_replace( '\\', '/', $file . '/' . $subfile );
369
								}
370
371
								// Get next file
372
								$subfile = readdir( $component_subdir );
373
							}
374
375
							closedir( $component_subdir );
376
						}
377
					} elseif ( '.php' === substr( $file, - 4 ) ) {
378
						$component_files[] = $file;
379
					}//end if
380
381
					// Get next file
382
					$file = readdir( $component_dir );
383
				}//end while
384
385
				closedir( $component_dir );
386
			}//end if
387
388
			$default_headers = array(
389
				'ID'               => 'ID',
390
				'Name'             => 'Name',
391
				'ShortName'        => 'Short Name',
392
				'PluginName'       => 'Plugin Name',
393
				'ComponentName'    => 'Component Name',
394
				'URI'              => 'URI',
395
				'MenuName'         => 'Menu Name',
396
				'MenuPage'         => 'Menu Page',
397
				'MenuAddPage'      => 'Menu Add Page',
398
				'MustUse'          => 'Must Use',
399
				'Description'      => 'Description',
400
				'Version'          => 'Version',
401
				'Category'         => 'Category',
402
				'Author'           => 'Author',
403
				'AuthorURI'        => 'Author URI',
404
				'Class'            => 'Class',
405
				'Hide'             => 'Hide',
406
				'PluginDependency' => 'Plugin Dependency',
407
				'ThemeDependency'  => 'Theme Dependency',
408
				'DeveloperMode'    => 'Developer Mode',
409
				'TablelessMode'    => 'Tableless Mode',
410
				'Capability'       => 'Capability',
411
				'Plugin'           => 'Plugin',
412
			);
413
414
			$component_files = apply_filters( 'pods_components_register', $component_files );
415
416
			$components = array();
417
418
			foreach ( $component_files as $component_file ) {
419
				$external = false;
420
421
				if ( is_array( $component_file ) && isset( $component_file['File'] ) ) {
422
					$component_file = $component_file['File'];
423
					$component      = $component_file;
424
425
					$external = true;
426
				} else {
427
					$component = $this->components_dir . $component_file;
428
				}
429
430
				if ( ! is_readable( $component ) ) {
431
					continue;
432
				}
433
434
				$component_data = get_file_data( $component, $default_headers, 'pods_component' );
435
436
				if ( ( empty( $component_data['Name'] ) && empty( $component_data['ComponentName'] ) && empty( $component_data['PluginName'] ) ) || 'yes' === $component_data['Hide'] ) {
437
					continue;
438
				}
439
440
				if ( isset( $component_data['Plugin'] ) && pods_is_plugin_active( $component_data['Plugin'] ) ) {
441
					continue;
442
				}
443
444
				if ( empty( $component_data['Name'] ) ) {
445
					if ( ! empty( $component_data['ComponentName'] ) ) {
446
						$component_data['Name'] = $component_data['ComponentName'];
447
					} elseif ( ! empty( $component_data['PluginName'] ) ) {
448
						$component_data['Name'] = $component_data['PluginName'];
449
					}
450
				}
451
452
				if ( empty( $component_data['ShortName'] ) ) {
453
					$component_data['ShortName'] = $component_data['Name'];
454
				}
455
456
				if ( empty( $component_data['MenuName'] ) ) {
457
					$component_data['MenuName'] = $component_data['Name'];
458
				}
459
460
				if ( empty( $component_data['Class'] ) ) {
461
					$component_data['Class'] = 'Pods_' . pods_js_name( basename( $component, '.php' ), false );
462
				}
463
464
				if ( empty( $component_data['ID'] ) ) {
465
					$component_data['ID'] = $component_data['Name'];
466
				}
467
468
				$component_data['ID'] = sanitize_title( $component_data['ID'] );
469
470
				if ( 'on' === strtolower( $component_data['DeveloperMode'] ) || 1 === $component_data['DeveloperMode'] ) {
471
					$component_data['DeveloperMode'] = true;
472
				} else {
473
					$component_data['DeveloperMode'] = false;
474
				}
475
476
				if ( 'on' === strtolower( $component_data['TablelessMode'] ) || 1 === $component_data['TablelessMode'] ) {
477
					$component_data['TablelessMode'] = true;
478
				} else {
479
					$component_data['TablelessMode'] = false;
480
				}
481
482
				$component_data['External'] = (boolean) $external;
483
484
				if ( 'on' === strtolower( $component_data['MustUse'] ) || '1' === $component_data['MustUse'] ) {
485
					$component_data['MustUse'] = true;
486
				} elseif ( 'off' === strtolower( $component_data['MustUse'] ) || '0' === $component_data['MustUse'] ) {
487
					$component_data['MustUse'] = false;
488
				} else {
489
					$component_data['MustUse'] = $component_data['External'];
490
				}
491
492
				$component_data['File'] = $component_file;
493
494
				$components[ $component_data['ID'] ] = $component_data;
495
			}//end foreach
496
497
			ksort( $components );
498
499
			pods_transient_set( 'pods_components_refresh', 1, ( 60 * 60 * 12 ) );
500
501
			pods_transient_set( 'pods_components', $components );
502
		}//end if
503
504
		if ( 1 === (int) pods_v( 'pods_debug_components', 'get', 0 ) && pods_is_admin( array( 'pods' ) ) ) {
505
			pods_debug( $components );
506
		}
507
508
		$this->components = $components;
509
510
		return $this->components;
511
	}
512
513
	/**
514
	 * Set component options
515
	 *
516
	 * @param string $component Component name.
517
	 * @param array  $options   Component options.
518
	 *
519
	 * @since 2.0
520
	 */
521
	public function options( $component, $options ) {
522
523
		if ( ! isset( $this->settings['components'][ $component ] ) || ! is_array( $this->settings['components'][ $component ] ) ) {
524
			$this->settings['components'][ $component ] = array();
525
		}
526
527
		foreach ( $options as $option => $data ) {
528
			if ( ! isset( $this->settings['components'][ $component ][ $option ] ) && isset( $data['default'] ) ) {
529
				$this->settings['components'][ $component ][ $option ] = $data['default'];
530
			}
531
		}
532
	}
533
534
	/**
535
	 * Call component specific admin functions
536
	 *
537
	 * @since 2.0
538
	 */
539
	public function admin_handler() {
540
541
		$component = str_replace( 'pods-component-', '', pods_v_sanitized( 'page', 'get' ) );
542
543
		if ( isset( $this->components[ $component ] ) && isset( $this->components[ $component ]['object'] ) && is_object( $this->components[ $component ]['object'] ) ) {
544
			// Component init
545
			if ( method_exists( $this->components[ $component ]['object'], 'init' ) ) {
546
				$this->components[ $component ]['object']->init( $this->settings['components'][ $component ], $component );
547
			}
548
549
			if ( method_exists( $this->components[ $component ]['object'], 'admin' ) ) {
550
				// Component Admin handler
551
				$this->components[ $component ]['object']->admin( $this->settings['components'][ $component ], $component );
552
			} elseif ( method_exists( $this->components[ $component ]['object'], 'options' ) ) {
553
				// Built-in Admin Handler
554
				$this->admin( $this->components[ $component ]['object']->options( $this->settings['components'][ $component ] ), $this->settings['components'][ $component ], $component );
555
			}
556
		}
557
	}
558
559
	/**
560
	 * Render components admin.
561
	 *
562
	 * @param array  $options   Component options.
563
	 * @param array  $settings  Component setting values.
564
	 * @param string $component Component name.
565
	 */
566
	public function admin( $options, $settings, $component ) {
567
568
		if ( ! isset( $this->components[ $component ] ) ) {
569
			wp_die( 'Invalid Component', '', array( 'back_link' => true ) );
570
		}
571
572
		$component_label = $this->components[ $component ]['Name'];
573
574
		include PODS_DIR . 'ui/admin/components-admin.php';
575
	}
576
577
	/**
578
	 * Check if a component is active or not
579
	 *
580
	 * @param string $component The component name to check if active.
581
	 *
582
	 * @return bool
583
	 *
584
	 * @since 2.7
585
	 */
586
	public function is_component_active( $component ) {
587
588
		$active = false;
589
590
		if ( isset( $this->components[ $component ] ) && isset( $this->settings['components'][ $component ] ) && 0 !== $this->settings['components'][ $component ] ) {
591
			$active = true;
592
		}
593
594
		return $active;
595
596
	}
597
598
	/**
599
	 * Activate a component
600
	 *
601
	 * @param string $component The component name to activate.
602
	 *
603
	 * @return boolean Whether the component was activated.
604
	 *
605
	 * @since 2.7
606
	 */
607
	public function activate_component( $component ) {
608
609
		$activated = false;
610
611
		if ( ! $this->is_component_active( $component ) ) {
612
			if ( empty( $this->components ) ) {
613
				// Setup components
614
				PodsInit::$components->get_components();
615
			}
616
617
			if ( isset( $this->components[ $component ] ) ) {
618
				$this->settings['components'][ $component ] = array();
619
620
				$this->update_settings( $this->settings );
621
622
				$activated = true;
623
			}
624
		} else {
625
			$activated = true;
626
		}//end if
627
628
		return $activated;
629
630
	}
631
632
	/**
633
	 * Deactivate a component
634
	 *
635
	 * @param string $component The component name to deactivate.
636
	 *
637
	 * @since 2.7
638
	 */
639
	public function deactivate_component( $component ) {
640
641
		if ( $this->is_component_active( $component ) ) {
642
			if ( isset( $this->components[ $component ] ) ) {
643
				$this->settings['components'][ $component ] = 0;
644
645
				$this->update_settings( $this->settings );
646
			}
647
		}
648
649
	}
650
651
	/**
652
	 * Toggle a component on or off
653
	 *
654
	 * @param string $component The component name to toggle.
655
	 *
656
	 * @return bool
657
	 *
658
	 * @since 2.0
659
	 */
660
	public function toggle( $component ) {
661
662
		$toggle = null;
663
664
		$toggle_mode = (int) pods_v( 'toggle', 'get' );
665
666
		if ( 1 === $toggle_mode ) {
667
			$this->activate_component( $component );
668
			$toggle = true;
669
		} else {
670
			$this->deactivate_component( $component );
671
			$toggle = false;
672
		}
673
674
		return $toggle;
675
676
	}
677
678
	/**
679
	 * Add pods specific capabilities.
680
	 *
681
	 * @param array $capabilities List of extra capabilities to add.
682
	 *
683
	 * @return array
684
	 */
685
	public function admin_capabilities( $capabilities ) {
686
687
		foreach ( $this->components as $component => $component_data ) {
688
			if ( ! empty( $component_data['Hide'] ) ) {
689
				continue;
690
			}
691
692
			if ( ! pods_developer() ) {
693
				if ( true === (boolean) pods_v( 'DeveloperMode', $component_data, false ) ) {
694
					continue;
695
				}
696
697
				if ( true === (boolean) pods_v( 'TablelessMode', $component_data, false ) ) {
698
					continue;
699
				}
700
			}
701
702
			if ( empty( $component_data['MenuPage'] ) && ( ! isset( $component_data['object'] ) || ! method_exists( $component_data['object'], 'admin' ) ) ) {
703
				continue;
704
			}
705
706
			$capability = 'pods_component_' . str_replace( '-', '_', sanitize_title( str_replace( ' and ', ' ', strip_tags( $component_data['Name'] ) ) ) );
707
708
			if ( 0 < strlen( $component_data['Capability'] ) ) {
709
				$capability = $component_data['Capability'];
710
			}
711
712
			if ( ! in_array( $capability, $capabilities, true ) ) {
713
				$capabilities[] = $capability;
714
			}
715
		}//end foreach
716
717
		return $capabilities;
718
	}
719
720
	/**
721
	 * Handle admin ajax
722
	 *
723
	 * @since 2.0
724
	 */
725
	public function admin_ajax() {
726
727
		if ( false === headers_sent() ) {
728
			pods_session_start();
729
730
			header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) );
731
		}
732
733
		// Sanitize input @codingStandardsIgnoreLine
734
		$params = pods_unslash( (array) $_POST );
735
736
		foreach ( $params as $key => $value ) {
737
			if ( 'action' === $key ) {
738
				continue;
739
			}
740
741
			unset( $params[ $key ] );
742
743
			$params[ str_replace( '_podsfix_', '', $key ) ] = $value;
744
		}
745
746
		$params = (object) $params;
747
748
		$component = $params->component;
749
		$method    = $params->method;
750
751
		if ( ! isset( $component ) || ! isset( $this->components[ $component ] ) || ! isset( $this->settings['components'][ $component ] ) ) {
752
			pods_error( 'Invalid AJAX request', $this );
753
		}
754
755
		if ( ! isset( $params->_wpnonce ) || false === wp_verify_nonce( $params->_wpnonce, 'pods-component-' . $component . '-' . $method ) ) {
756
			pods_error( 'Unauthorized request', $this );
757
		}
758
759
		// Cleaning up $params
760
		unset( $params->action, $params->component, $params->method, $params->_wpnonce );
761
762
		$params = (object) apply_filters( 'pods_component_ajax_' . $component . '_' . $method, $params, $component, $method );
763
764
		$output = false;
765
766
		// Component init
767
		if ( isset( $this->components[ $component ]['object'] ) && method_exists( $this->components[ $component ]['object'], 'init' ) ) {
768
			$this->components[ $component ]['object']->init( $this->settings['components'][ $component ], $component );
769
		}
770
771
		if ( isset( $this->components[ $component ]['object'] ) && ! method_exists( $this->components[ $component ]['object'], 'ajax_' . $method ) && method_exists( $this, 'admin_ajax_' . $method ) ) {
772
			// Handle internal methods
773
			$output = call_user_func( array( $this, 'admin_ajax_' . $method ), $component, $params );
774
		} elseif ( ! isset( $this->components[ $component ]['object'] ) || ! method_exists( $this->components[ $component ]['object'], 'ajax_' . $method ) ) {
775
			// Make sure method exists
776
			pods_error( 'API method does not exist', $this );
777
		} else {
778
			// Dynamically call the component method
779
			$output = call_user_func( array( $this->components[ $component ]['object'], 'ajax_' . $method ), $params );
780
		}
781
782
		if ( ! is_bool( $output ) ) {
783
			// @codingStandardsIgnoreLine
784
			echo $output;
785
		}
786
787
		die();
788
		// KBAI!
789
	}
790
791
	/**
792
	 * Handle admin AJAX settings saving.
793
	 *
794
	 * @param string $component Component name.
795
	 * @param array  $params    AJAX parameters.
796
	 *
797
	 * @return string
798
	 */
799
	public function admin_ajax_settings( $component, $params ) {
800
801
		if ( ! isset( $this->components[ $component ] ) ) {
802
			wp_die( 'Invalid Component', '', array( 'back_link' => true ) );
803
		} elseif ( ! method_exists( $this->components[ $component ]['object'], 'options' ) ) {
804
			pods_error( 'Component options method does not exist', $this );
805
		}
806
807
		$options = $this->components[ $component ]['object']->options( $this->settings['components'][ $component ] );
808
809
		if ( empty( $this->settings['components'][ $component ] ) ) {
810
			$this->settings['components'][ $component ] = array();
811
		}
812
813
		foreach ( $options as $field_name => $field_option ) {
814
			$field_option = PodsForm::field_setup( $field_option, null, $field_option['type'] );
815
816
			if ( ! is_array( $field_option['group'] ) ) {
817
				$field_value = pods_v( 'pods_setting_' . $field_name, $params );
818
819
				$this->settings['components'][ $component ][ $field_name ] = $field_value;
820
			} else {
821
				foreach ( $field_option['group'] as $field_group_name => $field_group_option ) {
822
					$field_value = pods_v( 'pods_setting_' . $field_group_name, $params );
823
824
					$this->settings['components'][ $component ][ $field_group_name ] = $field_value;
825
				}
826
			}
827
		}
828
829
		$this->update_settings( $this->settings );
830
831
		return '1';
832
	}
833
834
	/**
835
	 * Update settings.
836
	 *
837
	 * @param array $settings Component settings.
838
	 */
839
	public function update_settings( $settings ) {
840
841
		if ( version_compare( PHP_VERSION, '5.4.0', '>=' ) ) {
842
			$settings = wp_json_encode( $settings, JSON_UNESCAPED_UNICODE );
843
		} else {
844
			$settings = wp_json_encode( $settings );
845
		}
846
847
		update_option( 'pods_component_settings', $settings );
848
849
	}
850
}
851