Issues (2873)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

classes/PodsComponents.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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' ) && 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' ) );
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
	 * @param boolean $toggle_mode Force toggle on or off.
656
	 *
657
	 * @return bool
658
	 *
659
	 * @since 2.0
660
	 */
661
	public function toggle( $component, $toggle_mode = false ) {
662
663
		$toggled = null;
664
665
		$toggle_mode = (boolean) pods_v( 'toggle', 'get', $toggle_mode );
666
667
		if ( $toggle_mode ) {
668
			$toggled = $this->activate_component( $component );
669
		} else {
670
			$this->deactivate_component( $component );
671
672
			$toggled = false;
673
		}
674
675
		return $toggled;
676
677
	}
678
679
	/**
680
	 * Add pods specific capabilities.
681
	 *
682
	 * @param array $capabilities List of extra capabilities to add.
683
	 *
684
	 * @return array
685
	 */
686
	public function admin_capabilities( $capabilities ) {
687
688
		foreach ( $this->components as $component => $component_data ) {
689
			if ( ! empty( $component_data['Hide'] ) ) {
690
				continue;
691
			}
692
693
			if ( ! pods_developer() ) {
694
				if ( true === (boolean) pods_v( 'DeveloperMode', $component_data, false ) ) {
695
					continue;
696
				}
697
698
				if ( true === (boolean) pods_v( 'TablelessMode', $component_data, false ) ) {
699
					continue;
700
				}
701
			}
702
703
			if ( empty( $component_data['MenuPage'] ) && ( ! isset( $component_data['object'] ) || ! method_exists( $component_data['object'], 'admin' ) ) ) {
704
				continue;
705
			}
706
707
			$capability = 'pods_component_' . str_replace( '-', '_', sanitize_title( str_replace( ' and ', ' ', strip_tags( $component_data['Name'] ) ) ) );
708
709
			if ( 0 < strlen( $component_data['Capability'] ) ) {
710
				$capability = $component_data['Capability'];
711
			}
712
713
			if ( ! in_array( $capability, $capabilities, true ) ) {
714
				$capabilities[] = $capability;
715
			}
716
		}//end foreach
717
718
		return $capabilities;
719
	}
720
721
	/**
722
	 * Handle admin ajax
723
	 *
724
	 * @since 2.0
725
	 */
726
	public function admin_ajax() {
727
728
		if ( false === headers_sent() ) {
729
			pods_session_start();
730
731
			header( 'Content-Type: text/html; charset=' . get_bloginfo( 'charset' ) );
732
		}
733
734
		// Sanitize input @codingStandardsIgnoreLine
735
		$params = pods_unslash( (array) $_POST );
736
737
		foreach ( $params as $key => $value ) {
738
			if ( 'action' === $key ) {
739
				continue;
740
			}
741
742
			unset( $params[ $key ] );
743
744
			$params[ str_replace( '_podsfix_', '', $key ) ] = $value;
745
		}
746
747
		$params = (object) $params;
748
749
		$component = $params->component;
750
		$method    = $params->method;
751
752
		if ( ! isset( $component ) || ! isset( $this->components[ $component ] ) || ! isset( $this->settings['components'][ $component ] ) ) {
753
			pods_error( 'Invalid AJAX request', $this );
754
		}
755
756
		if ( ! isset( $params->_wpnonce ) || false === wp_verify_nonce( $params->_wpnonce, 'pods-component-' . $component . '-' . $method ) ) {
757
			pods_error( 'Unauthorized request', $this );
758
		}
759
760
		// Cleaning up $params
761
		unset( $params->action, $params->component, $params->method, $params->_wpnonce );
762
763
		$params = (object) apply_filters( 'pods_component_ajax_' . $component . '_' . $method, $params, $component, $method );
764
765
		$output = false;
766
767
		// Component init
768
		if ( isset( $this->components[ $component ]['object'] ) && method_exists( $this->components[ $component ]['object'], 'init' ) ) {
769
			$this->components[ $component ]['object']->init( $this->settings['components'][ $component ], $component );
770
		}
771
772
		if ( isset( $this->components[ $component ]['object'] ) && ! method_exists( $this->components[ $component ]['object'], 'ajax_' . $method ) && method_exists( $this, 'admin_ajax_' . $method ) ) {
773
			// Handle internal methods
774
			$output = call_user_func( array( $this, 'admin_ajax_' . $method ), $component, $params );
775
		} elseif ( ! isset( $this->components[ $component ]['object'] ) || ! method_exists( $this->components[ $component ]['object'], 'ajax_' . $method ) ) {
776
			// Make sure method exists
777
			pods_error( 'API method does not exist', $this );
778
		} else {
779
			// Dynamically call the component method
780
			$output = call_user_func( array( $this->components[ $component ]['object'], 'ajax_' . $method ), $params );
781
		}
782
783
		if ( ! is_bool( $output ) ) {
784
			// @codingStandardsIgnoreLine
785
			echo $output;
786
		}
787
788
		die();
789
		// KBAI!
790
	}
791
792
	/**
793
	 * Handle admin AJAX settings saving.
794
	 *
795
	 * @param string $component Component name.
796
	 * @param array  $params    AJAX parameters.
797
	 *
798
	 * @return string
799
	 */
800
	public function admin_ajax_settings( $component, $params ) {
801
802
		if ( ! isset( $this->components[ $component ] ) ) {
803
			wp_die( 'Invalid Component', '', array( 'back_link' => true ) );
804
		} elseif ( ! method_exists( $this->components[ $component ]['object'], 'options' ) ) {
805
			pods_error( 'Component options method does not exist', $this );
806
		}
807
808
		$options = $this->components[ $component ]['object']->options( $this->settings['components'][ $component ] );
809
810
		if ( empty( $this->settings['components'][ $component ] ) ) {
811
			$this->settings['components'][ $component ] = array();
812
		}
813
814
		foreach ( $options as $field_name => $field_option ) {
815
			$field_option = PodsForm::field_setup( $field_option, null, $field_option['type'] );
816
817
			if ( ! is_array( $field_option['group'] ) ) {
818
				$field_value = pods_v( 'pods_setting_' . $field_name, $params );
819
820
				$this->settings['components'][ $component ][ $field_name ] = $field_value;
821
			} else {
822
				foreach ( $field_option['group'] as $field_group_name => $field_group_option ) {
823
					$field_value = pods_v( 'pods_setting_' . $field_group_name, $params );
824
825
					$this->settings['components'][ $component ][ $field_group_name ] = $field_value;
826
				}
827
			}
828
		}
829
830
		$this->update_settings( $this->settings );
831
832
		return '1';
833
	}
834
835
	/**
836
	 * Update settings.
837
	 *
838
	 * @param array $settings Component settings.
839
	 */
840
	public function update_settings( $settings ) {
841
842
		if ( version_compare( PHP_VERSION, '5.4.0', '>=' ) ) {
843
			$settings = wp_json_encode( $settings, JSON_UNESCAPED_UNICODE );
844
		} else {
845
			$settings = wp_json_encode( $settings );
846
		}
847
848
		update_option( 'pods_component_settings', $settings );
849
850
	}
851
}
852