Issues (1282)

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.

includes/admin/class-admin-settings.php (8 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
 * Give Admin Settings Class
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Admin_Settings
7
 * @copyright   Copyright (c) 2016, GiveWP
8
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
 * @since       1.8
10
 */
11
12
if ( ! defined( 'ABSPATH' ) ) {
13
	exit;
14
}
15
16
if ( ! class_exists( 'Give_Admin_Settings' ) ) :
17
18
	/**
19
	 * Give_Admin_Settings Class.
20
	 *
21
	 * @since 1.8
22
	 */
23
	class Give_Admin_Settings {
24
25
		/**
26
		 * Setting pages.
27
		 *
28
		 * @since 1.8
29
		 * @var   array List of settings.
30
		 */
31
		private static $settings = array();
32
33
		/**
34
		 * Setting filter and action prefix.
35
		 *
36
		 * @since 1.8
37
		 * @var   string setting fileter and action anme prefix.
38
		 */
39
		private static $setting_filter_prefix = '';
40
41
		/**
42
		 * Error messages.
43
		 *
44
		 * @since 1.8
45
		 * @var   array List of errors.
46
		 */
47
		private static $errors = array();
48
49
		/**
50
		 * Update messages.
51
		 *
52
		 * @since 1.8
53
		 * @var   array List of messages.
54
		 */
55
		private static $messages = array();
56
57
		/**
58
		 * Include the settings page classes.
59
		 *
60
		 * @since  1.8
61
		 * @return array
62
		 */
63
		public static function get_settings_pages() {
64
			/**
65
			 * Filter the setting page.
66
			 *
67
			 * Note: filter dynamically fire on basis of setting page slug.
68
			 * For example: if you register a setting page with give-settings menu slug
69
			 *              then filter will be give-settings_get_settings_pages
70
			 *
71
			 * @since 1.8
72
			 *
73
			 * @param array $settings Array of settings class object.
74
			 */
75
			self::$settings = apply_filters( self::$setting_filter_prefix . '_get_settings_pages', array() );
76
77
			return self::$settings;
78
		}
79
80
		/**
81
		 * Verify admin setting nonce
82
		 *
83
		 * @since  1.8.14
84
		 * @access public
85
		 *
86
		 * @return bool
87
		 */
88 View Code Duplication
		public static function verify_nonce() {
0 ignored issues
show
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...
89
			if ( empty( $_REQUEST['_give-save-settings'] ) || ! wp_verify_nonce( $_REQUEST['_give-save-settings'], 'give-save-settings' ) ) {
90
				return false;
91
			}
92
93
			return true;
94
		}
95
96
		/**
97
		 * Save the settings.
98
		 *
99
		 * @since  1.8
100
		 * @return void
101
		 */
102
		public static function save() {
103
			$current_tab = give_get_current_setting_tab();
104
105
			if ( ! self::verify_nonce() ) {
106
				echo '<div class="notice error"><p>' . esc_attr__( 'Action failed. Please refresh the page and retry.', 'give' ) . '</p></div>';
107
				die();
108
			}
109
110
			/**
111
			 * Trigger Action.
112
			 *
113
			 * Note: action dynamically fire on basis of setting page slug and current tab.
114
			 * For example: if you register a setting page with give-settings menu slug and general current tab name
115
			 *              then action will be give-settings_save_general
116
			 *
117
			 * @since 1.8
118
			 */
119
			do_action( self::$setting_filter_prefix . '_save_' . $current_tab );
120
121
			self::add_message( 'give-setting-updated', __( 'Your settings have been saved.', 'give' ) );
122
123
			/**
124
			 * Trigger Action.
125
			 *
126
			 * Note: action dynamically fire on basis of setting page slug.
127
			 * For example: if you register a setting page with give-settings menu slug
128
			 *              then action will be give-settings_saved
129
			 *
130
			 * @since 1.8
131
			 */
132
			do_action( self::$setting_filter_prefix . '_saved' );
133
		}
134
135
		/**
136
		 * Add a message.
137
		 *
138
		 * @since  1.8
139
		 *
140
		 * @param  string $code    Message code (Note: This should be unique).
141
		 * @param  string $message Message text.
142
		 *
143
		 * @return void
144
		 */
145
		public static function add_message( $code, $message ) {
146
			self::$messages[ $code ] = $message;
147
		}
148
149
		/**
150
		 * Add an error.
151
		 *
152
		 * @since  1.8
153
		 *
154
		 * @param  string $code    Message code (Note: This should be unique).
155
		 * @param  string $message Message text.
156
		 *
157
		 * @return void
158
		 */
159
		public static function add_error( $code, $message ) {
160
			self::$errors[ $code ] = $message;
161
		}
162
163
		/**
164
		 * Output messages + errors.
165
		 *
166
		 * @since  1.8
167
		 * @return void
168
		 */
169
		public static function show_messages() {
170
			$notice_html = '';
171
			$classes     = 'give-notice settings-error notice is-dismissible';
172
173
			self::$errors   = apply_filters( self::$setting_filter_prefix . '_error_notices', self::$errors );
174
			self::$messages = apply_filters( self::$setting_filter_prefix . '_update_notices', self::$messages );
175
176
			if ( 0 < count( self::$errors ) ) {
177
				foreach ( self::$errors as $code => $message ) {
178
					$notice_html .= sprintf(
179
						'<div id="setting-error-%1$s" class="%2$s error" style="display: none"><p><strong>%3$s</strong></p></div>',
180
						$code,
181
						$classes,
182
						$message
183
					);
184
				}
185
			}
186
187
			if ( 0 < count( self::$messages ) ) {
188
				foreach ( self::$messages as $code => $message ) {
189
					$notice_html .= sprintf(
190
						'<div id="setting-error-%1$s" class="%2$s updated" style="display: none"><p><strong>%3$s</strong></p></div>',
191
						$code,
192
						$classes,
193
						$message
194
					);
195
				}
196
			}
197
198
			echo $notice_html;
199
		}
200
201
		/**
202
		 * Settings page.
203
		 *
204
		 * Handles the display of the main give settings page in admin.
205
		 *
206
		 * @since  1.8
207
		 * @return bool
208
		 */
209
		public static function output() {
210
			// Get current setting page.
211
			self::$setting_filter_prefix = give_get_current_setting_page();
212
213
			// Bailout: Exit if setting page is not defined.
214
			if ( empty( self::$setting_filter_prefix ) ) {
215
				return false;
216
			}
217
218
			/**
219
			 * Trigger Action.
220
			 *
221
			 * Note: action dynamically fire on basis of setting page slug
222
			 * For example: if you register a setting page with give-settings menu slug
223
			 *              then action will be give-settings_start
224
			 *
225
			 * @since 1.8
226
			 */
227
			do_action( self::$setting_filter_prefix . '_start' );
228
229
			$current_tab = give_get_current_setting_tab();
230
231
			// Include settings pages.
232
			$all_setting = self::get_settings_pages();
233
234
			/* @var object $current_setting_obj */
235
			$current_setting_obj = new StdClass;
236
237
			foreach ( $all_setting as $setting ) {
238
				if (
239
					method_exists( $setting, 'get_id' ) &&
240
					$current_tab === $setting->get_id()
241
				) {
242
					$current_setting_obj = $setting;
243
					break;
244
				}
245
			}
246
247
			// Save settings if data has been posted.
248
			if ( isset( $_POST['_give-save-settings'] ) ) {
249
				self::save();
250
			}
251
252
			/**
253
			 * Filter the tabs for current setting page.
254
			 *
255
			 * Note: filter dynamically fire on basis of setting page slug.
256
			 * For example: if you register a setting page with give-settings menu slug and general current tab name
257
			 *              then action will be give-settings_tabs_array
258
			 *
259
			 * @since 1.8
260
			 */
261
			$tabs = apply_filters( self::$setting_filter_prefix . '_tabs_array', array() );
262
263
			include 'views/html-admin-settings.php';
264
265
			return true;
266
		}
267
268
		/**
269
		 * Get a setting from the settings API.
270
		 *
271
		 * @since  1.8
272
		 *
273
		 * @param string $option_name Option Name.
274
		 * @param string $field_id    Field ID.
275
		 * @param mixed  $default     Default.
276
		 *
277
		 * @return string|bool
278
		 */
279
		public static function get_option( $option_name = '', $field_id = '', $default = false ) {
280
			// Bailout.
281
			if ( empty( $option_name ) && empty( $field_id ) ) {
282
				return false;
283
			}
284
285
			if ( ! empty( $field_id ) && ! empty( $option_name ) ) {
286
				// Get field value if any.
287
				$option_value = get_option( $option_name );
288
289
				$option_value = ( is_array( $option_value ) && array_key_exists( $field_id, $option_value ) )
290
					? $option_value[ $field_id ]
291
					: $default;
292
			} else {
293
				// If option name is empty but not field name then this means, setting is direct store to option table under there field name.
294
				$option_name = ! $option_name ? $field_id : $option_name;
295
296
				// Get option value if any.
297
				$option_value = get_option( $option_name, $default );
298
			}
299
300
			/**
301
			 * Filter the option value
302
			 *
303
			 * @since 2.2.3
304
			 *
305
			 * @param mixed  $option_value
306
			 * @param string $option_name
307
			 * @param string $field_id
308
			 * @param mixed  $default
309
			 */
310
			return apply_filters( 'give_admin_field_get_value', $option_value, $option_name, $field_id, $default );
311
		}
312
313
		/**
314
		 * Output admin fields.
315
		 *
316
		 * Loops though the give options array and outputs each field.
317
		 *
318
		 * @todo   : Refactor this function
319
		 * @since  1.8
320
		 *
321
		 * @param  array  $options     Opens array to output.
322
		 * @param  string $option_name Opens array to output.
323
		 *
324
		 * @return void
325
		 */
326
		public static function output_fields( $options, $option_name = '' ) {
327
			$current_tab = give_get_current_setting_tab();
328
329
			// Field Default values.
330
			$defaults = array(
331
				'id'                  => '',
332
				'class'               => '',
333
				'css'                 => '',
334
				'default'             => '',
335
				'desc'                => '',
336
				'table_html'          => true,
337
				'repeat'              => false,
338
				'repeat_btn_title'    => __( 'Add Field', 'give' ),
339
			);
340
341
			foreach ( $options as $value ) {
342
				if ( ! isset( $value['type'] ) ) {
343
					continue;
344
				}
345
346
				// Set title.
347
				$defaults['title'] = isset( $value['name'] ) ? $value['name'] : '';
348
349
				// Set default setting.
350
				$value = wp_parse_args( $value, $defaults );
351
352
				// Colorpicker field.
353
				$value['class'] = ( 'colorpicker' === $value['type'] ? trim( $value['class'] ) . ' give-colorpicker' : $value['class'] );
354
				$value['type']  = ( 'colorpicker' === $value['type'] ? 'text' : $value['type'] );
355
356
357
				// Custom attribute handling.
358
				$custom_attributes = array();
359
360 View Code Duplication
				if ( ! empty( $value['attributes'] ) && is_array( $value['attributes'] ) ) {
0 ignored issues
show
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...
361
					foreach ( $value['attributes'] as $attribute => $attribute_value ) {
362
						$custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
363
					}
364
				}
365
366
				// Description handling.
367
				$description = self::get_field_description( $value );
368
369
				// Switch based on type.
370
				switch ( $value['type'] ) {
371
372
					// Section Titles.
373
					case 'title':
374
						if ( ! empty( $value['title'] ) || ! empty( $value['desc'] ) ) {
375
							?>
376
							<div class="give-setting-tab-header give-setting-tab-header-<?php echo $current_tab; ?>">
377
								<?php if ( ! empty( $value['title'] ) ) : ?>
378
									<h2><?php echo self::get_field_title( $value ); ?></h2>
379
									<hr>
380
								<?php endif; ?>
381
382
								<?php if ( ! empty( $value['desc'] ) ) : ?>
383
									<?php echo wpautop( wptexturize( wp_kses_post( $value['desc'] ) ) ); ?>
384
								<?php endif; ?>
385
							</div>
386
							<?php
387
						}
388
389
						if ( $value['table_html'] ) {
390
							echo '<table class="form-table give-setting-tab-body give-setting-tab-body-' . $current_tab . '">' . "\n\n";
391
						}
392
393
						if ( ! empty( $value['id'] ) ) {
394
395
							/**
396
							 * Trigger Action.
397
							 *
398
							 * Note: action dynamically fire on basis of field id.
399
							 *
400
							 * @since 1.8
401
							 */
402
							do_action( 'give_settings_' . sanitize_title( $value['id'] ) );
403
						}
404
405
						break;
406
407
					// Section Ends.
408
					case 'sectionend':
409 View Code Duplication
						if ( ! empty( $value['id'] ) ) {
0 ignored issues
show
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...
410
411
							/**
412
							 * Trigger Action.
413
							 *
414
							 * Note: action dynamically fire on basis of field id.
415
							 *
416
							 * @since 1.8
417
							 */
418
							do_action( 'give_settings_' . sanitize_title( $value['id'] ) . '_end' );
419
						}
420
421
						if ( $value['table_html'] ) {
422
							echo '</table>';
423
						}
424
425 View Code Duplication
						if ( ! empty( $value['id'] ) ) {
0 ignored issues
show
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...
426
427
							/**
428
							 * Trigger Action.
429
							 *
430
							 * Note: action dynamically fire on basis of field id.
431
							 *
432
							 * @since 1.8
433
							 */
434
							do_action( 'give_settings_' . sanitize_title( $value['id'] ) . '_after' );
435
						}
436
437
						break;
438
439
					// Standard text inputs and subtypes like 'number'.
440
					case 'colorpicker':
441
					case 'hidden' :
442
						$value['wrapper_class'] = empty( $value['wrapper_class'] ) ? 'give-hidden' : trim( $value['wrapper_class'] ) . ' give-hidden';
443
					case 'text':
444
					case 'email':
445
					case 'number':
446
					case 'password' :
447
						$type = $value['type'];
448
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
449
450
						// Set default value for repeater field if not any value set yet.
451
						if ( $value['repeat'] && is_string( $option_value ) ) {
452
							$option_value = array( $value['default'] );
453
						}
454
						?>
455
					<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
456
						<th scope="row" class="titledesc">
457
							<label
458
									for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
459
						</th>
460
						<td class="give-forminp give-forminp-<?php echo sanitize_title( $value['type'] ) ?>">
461
							<?php if ( $value['repeat'] ) : ?>
462
								<?php foreach ( $option_value as $index => $field_value ) : ?>
0 ignored issues
show
The expression $option_value of type string|boolean|array<integer,?,{"0":"?"}> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
463
									<p>
464
										<input
465
												name="<?php echo esc_attr( $value['id'] ); ?>[]"
466
												type="<?php echo esc_attr( $type ); ?>"
467
												style="<?php echo esc_attr( $value['css'] ); ?>"
468
												value="<?php echo esc_attr( $field_value ); ?>"
469
												class="give-input-field<?php echo( empty( $value['class'] ) ? '' : ' ' . esc_attr( $value['class'] ) ); ?> <?php echo esc_attr( $value['id'] ); ?>"
470
											<?php echo implode( ' ', $custom_attributes ); ?>
471
										/>
472
										<span class="give-remove-setting-field"
473
												title="<?php esc_html_e( 'Remove setting field', 'give' ); ?>">-</span>
474
									</p>
475
								<?php endforeach; ?>
476
								<a href="#" data-id="<?php echo $value['id']; ?>"
477
										class="give-repeat-setting-field button-secondary"><?php echo $value['repeat_btn_title']; ?></a>
478
							<?php else : ?>
479
								<input
480
										name="<?php echo esc_attr( $value['id'] ); ?>"
481
										id="<?php echo esc_attr( $value['id'] ); ?>"
482
										type="<?php echo esc_attr( $type ); ?>"
483
										style="<?php echo esc_attr( $value['css'] ); ?>"
484
										value="<?php echo esc_attr( $option_value ); ?>"
485
										class="give-input-field<?php echo( empty( $value['class'] ) ? '' : ' ' . esc_attr( $value['class'] ) ); ?>"
486
									<?php echo implode( ' ', $custom_attributes ); ?>
487
								/>
488
							<?php endif; ?>
489
							<?php echo $description; ?>
490
						</td>
491
						</tr><?php
492
						break;
493
494
					// Textarea.
495
					case 'textarea':
496
497
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
498
						$default_attributes = array(
499
							'rows' => 10,
500
							'cols' => 60
501
						);
502
						$textarea_attributes = isset( $value['attributes'] ) ? $value['attributes'] : array();
503
						?>
504
						<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
505
							<th scope="row" class="titledesc">
506
								<label
507
										for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
508
							</th>
509
							<td class="give-forminp give-forminp-<?php echo sanitize_title( $value['type'] ) ?>">
510
										<textarea
511
											name="<?php echo esc_attr( $value['id'] ); ?>"
512
											id="<?php echo esc_attr( $value['id'] ); ?>"
513
											style="<?php echo esc_attr( $value['css'] ); ?>"
514
											class="<?php echo esc_attr( $value['class'] ); ?>"
515
											<?php echo give_get_attribute_str( $textarea_attributes, $default_attributes ); ?>
516
										><?php echo esc_textarea( $option_value ); ?></textarea>
517
								<?php echo $description; ?>
518
							</td>
519
						</tr>
520
						<?php
521
						break;
522
523
					// Select boxes.
524
					case 'select' :
525
					case 'multiselect' :
526
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
527
528
						/**
529
						 * Insert page in option if missing.
530
						 *
531
						 * Check success_page setting in general settings.
532
						 */
533
						if (
534
							isset( $value['attributes'] ) &&
535
							false !== strpos( $value['class'], 'give-select-chosen' ) &&
536
							in_array( 'data-search-type', array_keys( $value['attributes' ] ) ) &&
537
							'pages' === $value['attributes' ]['data-search-type'] &&
538
							! in_array( $option_value, array_keys( $value['options'] ) )
539
						) {
540
							$value['options'][ $option_value ] = get_the_title( $option_value );
541
						}
542
						?>
543
					<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
544
						<th scope="row" class="titledesc">
545
							<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
546
						</th>
547
						<td class="give-forminp give-forminp-<?php echo sanitize_title( $value['type'] ) ?>">
548
							<select
549
									name="<?php echo esc_attr( $value['id'] ); ?><?php if ( 'multiselect' === $value['type'] ) echo '[]'; ?>"
550
									id="<?php echo esc_attr( $value['id'] ); ?>"
551
									style="<?php echo esc_attr( $value['css'] ); ?>"
552
									class="<?php echo esc_attr( $value['class'] ); ?>"
553
								<?php echo implode( ' ', $custom_attributes ); ?>
554
								<?php echo ( 'multiselect' === $value['type'] ) ? 'multiple="multiple"' : ''; ?>
555
							>
556
557
								<?php
558
								if ( ! empty( $value['options'] ) ) {
559
									foreach ( $value['options'] as $key => $val ) {
560
										?>
561
										<option value="<?php echo esc_attr( $key ); ?>" <?php
562
563
										if ( is_array( $option_value ) ) {
564
											selected( in_array( $key, $option_value ), true );
565
										} else {
566
											selected( $option_value, $key );
567
										}
568
569
										?>><?php echo $val ?></option>
570
										<?php
571
									}
572
								}
573
								?>
574
575
							</select> <?php echo $description; ?>
576
						</td>
577
						</tr><?php
578
						break;
579
580
					// Radio inputs.
581
					case 'radio_inline' :
582
						$value['class'] = empty( $value['class'] ) ? 'give-radio-inline' : $value['class'] . ' give-radio-inline';
583
					case 'radio' :
584
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
585
						?>
586
					<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
587
						<th scope="row" class="titledesc">
588
							<label
589
									for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
590
						</th>
591
						<td class="give-forminp give-forminp-<?php echo sanitize_title( $value['type'] ) ?> <?php echo( ! empty( $value['class'] ) ? $value['class'] : '' ); ?>">
592
							<fieldset>
593
								<ul>
594
									<?php
595 View Code Duplication
									foreach ( $value['options'] as $key => $val ) {
0 ignored issues
show
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...
596
										?>
597
										<li>
598
											<label><input
599
														name="<?php echo esc_attr( $value['id'] ); ?>"
600
														value="<?php echo $key; ?>"
601
														type="radio"
602
														style="<?php echo esc_attr( $value['css'] ); ?>"
603
													<?php echo implode( ' ', $custom_attributes ); ?>
604
													<?php checked( $key, $option_value ); ?>
605
												/> <?php echo $val ?></label>
606
										</li>
607
										<?php
608
									}
609
									?>
610
									<?php echo $description; ?>
611
							</fieldset>
612
						</td>
613
						</tr><?php
614
						break;
615
616
					// Checkbox input.
617
					case 'checkbox' :
618
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
619
						?>
620
						<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
621
							<th scope="row" class="titledesc">
622
								<label
623
										for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
624
							</th>
625
							<td class="give-forminp">
626
								<input
627
										name="<?php echo esc_attr( $value['id'] ); ?>"
628
										id="<?php echo esc_attr( $value['id'] ); ?>"
629
										type="checkbox"
630
										class="<?php echo esc_attr( isset( $value['class'] ) ? $value['class'] : '' ); ?>"
631
										value="1"
632
									<?php checked( $option_value, 'on' ); ?>
633
									<?php echo implode( ' ', $custom_attributes ); ?>
634
								/>
635
								<?php echo $description; ?>
636
							</td>
637
						</tr>
638
						<?php
639
						break;
640
641
					// Multi Checkbox input.
642
					case 'multicheck' :
643
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
644
						$option_value = is_array( $option_value ) ? $option_value : array();
645
						?>
646
						<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
647
							<th scope="row" class="titledesc">
648
								<label
649
										for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
650
							</th>
651
							<td class="give-forminp give-forminp-<?php echo sanitize_title( $value['type'] ) ?> <?php echo( ! empty( $value['class'] ) ? $value['class'] : '' ); ?>">
652
								<fieldset>
653
									<ul>
654
										<?php
655 View Code Duplication
										foreach ( $value['options'] as $key => $val ) {
0 ignored issues
show
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...
656
											?>
657
											<li>
658
												<label>
659
													<input
660
															name="<?php echo esc_attr( $value['id'] ); ?>[]"
661
															value="<?php echo $key; ?>"
662
															type="checkbox"
663
															style="<?php echo esc_attr( $value['css'] ); ?>"
664
														<?php echo implode( ' ', $custom_attributes ); ?>
665
														<?php if ( in_array( $key, $option_value ) ) {
666
															echo 'checked="checked"';
667
														} ?>
668
													/> <?php echo $val ?>
669
												</label>
670
											</li>
671
											<?php
672
										}
673
										?>
674
										<?php echo $description; ?>
675
								</fieldset>
676
							</td>
677
						</tr>
678
						<?php
679
						break;
680
681
					// File input field.
682
					case 'file' :
683
					case 'media' :
684
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
685
						$button_label = sprintf( __( 'Add or Upload %s', 'give' ), ( 'file' === $value['type'] ? __( 'File', 'give' ) : __( 'Image', 'give' ) ) );
686
						$fvalue       = empty( $value['fvalue'] ) ? 'url' : $value['fvalue'];
687
688
						$allow_media_preview_tags = array( 'jpg', 'jpeg', 'png', 'gif', 'ico' );
689
						$preview_image_src        = $option_value ? ( 'id' === $fvalue ? wp_get_attachment_url( $option_value ) : $option_value ) : '';
690
						$preview_image_extension  = $preview_image_src ? pathinfo( $preview_image_src, PATHINFO_EXTENSION ) : '';
691
						$is_show_preview          = in_array( $preview_image_extension, $allow_media_preview_tags );
692
						?>
693
						<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
694
							<th scope="row" class="titledesc">
695
								<label
696
										for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
697
							</th>
698
							<td class="give-forminp">
699
								<div class="give-field-wrap">
700
									<label for="<?php echo $value['id'] ?>">
701
										<input
702
												name="<?php echo esc_attr( $value['id'] ); ?>"
703
												id="<?php echo esc_attr( $value['id'] ); ?>"
704
												type="text"
705
												class="give-input-field<?php echo esc_attr( isset( $value['class'] ) ? ' ' . $value['class'] : '' ); ?>"
706
												value="<?php echo $option_value; ?>"
707
												style="<?php echo esc_attr( $value['css'] ); ?>"
708
											<?php echo implode( ' ', $custom_attributes ); ?>
709
										/>&nbsp;&nbsp;&nbsp;&nbsp;<input class="give-upload-button button" type="button"
710
												data-fvalue="<?php echo $fvalue; ?>"
711
												data-field-type="<?php echo $value['type']; ?>"
712
												value="<?php echo $button_label; ?>">
713
										<?php echo $description ?>
714
										<div
715
												class="give-image-thumb<?php echo ! $option_value || ! $is_show_preview ? ' give-hidden' : ''; ?>">
716
											<span class="give-delete-image-thumb dashicons dashicons-no-alt"></span>
717
											<img src="<?php echo $preview_image_src; ?>" alt="">
718
										</div>
719
									</label>
720
								</div>
721
							</td>
722
						</tr>
723
						<?php
724
						break;
725
726
					// WordPress Editor.
727
					case 'wysiwyg' :
728
						// Get option value.
729
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
730
731
						// Get editor settings.
732
						$editor_settings = ! empty( $value['options'] ) ? $value['options'] : array();
733
						?>
734
					<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
735
						<th scope="row" class="titledesc">
736
							<label
737
									for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
738
						</th>
739
						<td class="give-forminp">
740
							<?php wp_editor( $option_value, $value['id'], $editor_settings ); ?>
741
							<?php echo $description; ?>
742
						</td>
743
						</tr><?php
744
						break;
745
746
					// Custom: Email preview buttons field.
747
					case 'email_preview_buttons' :
748
						?>
749
					<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
750
						<th scope="row" class="titledesc">
751
							<label
752
									for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
753
						</th>
754
						<td class="give-forminp">
755
							<?php give_email_preview_buttons_callback( $value ); ?>
756
							<?php echo $description; ?>
757
						</td>
758
						</tr><?php
759
						break;
760
761
					// Custom: API field.
762
					case 'api' :
763
						give_api_callback();
764
						echo $description;
765
						break;
766
767
					// Custom: Gateway API key.
768
					case 'api_key' :
769
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
770
						$type         = ! empty( $option_value ) ? 'password' : 'text';
771
						?>
772
					<tr valign="top" <?php echo ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '' ?>>
773
						<th scope="row" class="titledesc">
774
							<label
775
									for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo self::get_field_title( $value ); ?></label>
776
						</th>
777
						<td class="give-forminp give-forminp-<?php echo sanitize_title( $value['type'] ) ?>">
778
							<input
779
									name="<?php echo esc_attr( $value['id'] ); ?>"
780
									id="<?php echo esc_attr( $value['id'] ); ?>"
781
									type="<?php echo esc_attr( $type ); ?>"
782
									style="<?php echo esc_attr( $value['css'] ); ?>"
783
									value="<?php echo esc_attr( trim( $option_value ) ); ?>"
784
									class="give-input-field<?php echo( empty( $value['class'] ) ? '' : ' ' . esc_attr( $value['class'] ) ); ?>"
785
								<?php echo implode( ' ', $custom_attributes ); ?>
786
							/> <?php echo $description; ?>
787
						</td>
788
						</tr><?php
789
						break;
790
791
					// Note: only for internal use.
792
					case 'chosen' :
793
794
						// Get option value.
795
						$option_value     = self::get_option( $option_name, $value['id'], $value['default'] );
796
						$option_value     = is_array( $option_value ) ? array_fill_keys( $option_value, 'selected' ) : $option_value;
797
						$wrapper_class    = ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '';
798
						$type             = '';
799
						$allow_new_values = '';
800
						$name             = give_get_field_name( $value );
801
802
						// Set attributes based on multiselect datatype.
803
						if ( 'multiselect' === $value['data_type'] ) {
804
							$type             = 'multiple';
805
							$allow_new_values = 'data-allows-new-values="true"';
806
							$name             = $name . '[]';
807
							$option_value     = empty( $option_value ) ? array() : $option_value;
808
						}
809
810
						$title_prefixes_value = ( is_array( $option_value ) && count( $option_value ) > 0 ) ?
811
							array_merge( $value['options'], $option_value ) :
812
							$value['options'];
813
814
						?>
815
						<tr valign="top" <?php echo $wrapper_class; ?>>
816
							<th scope="row" class="titledesc">
817
								<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_attr( self::get_field_title( $value ) ); ?></label>
818
							</th>
819
							<td class="give-forminp give-forminp-<?php echo esc_attr( $value['type'] ); ?>">
820
								<select
821
										class="give-select-chosen give-chosen-settings"
822
										style="<?php echo esc_attr( $value['style'] ); ?>"
823
										name="<?php echo esc_attr( $name ); ?>"
824
										id="<?php echo esc_attr( $value['id'] ); ?>"
825
									<?php
826
									echo "{$type} {$allow_new_values}";
827
									echo implode( ' ', $custom_attributes );
828
									?>
829
								>
830
									<?php
831 View Code Duplication
									if ( is_array( $title_prefixes_value ) && count( $title_prefixes_value ) > 0 ) {
0 ignored issues
show
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...
832
										foreach ( $title_prefixes_value as $key => $item_value ) {
833
											echo sprintf(
834
												'<option %1$s value="%2$s">%2$s</option>',
835
												( 'selected' === $item_value ) ? 'selected="selected"' : '',
836
												esc_attr( $key )
837
											);
838
										}
839
									}
840
									?>
841
								</select>
842
								<?php echo wp_kses_post( $description ); ?>
843
							</td>
844
						</tr>
845
						<?php
846
						break;
847
848
					// Custom: Log field.
849
					case 'logs' :
850
851
						// Get current section.
852
						$current_section = $_GET['section'] = give_get_current_setting_section();
853
854
						/**
855
						 * Fires for each tab of logs view.
856
						 *
857
						 * @since 1.0
858
						 */
859
						do_action( "give_logs_view_{$current_section}" );
860
861
						echo $description;
862
						break;
863
864
					// Custom: Data field.
865
					case 'data' :
866
867
						include GIVE_PLUGIN_DIR . 'includes/admin/tools/views/html-admin-page-data.php';
868
869
						echo $description;
870
						break;
871
872
					// Custom: Give Docs Link field type.
873
					case 'give_docs_link' :
874
						$wrapper_class = ! empty( $value['wrapper_class'] ) ? 'class="' . $value['wrapper_class'] . '"' : '';
875
						?>
876
					<tr valign="top" <?php echo esc_html( $wrapper_class ); ?>>
877
						<td class="give-docs-link" colspan="2">
878
							<p class="give-docs-link">
879
								<a href="<?php echo esc_url( $value['url'] ); ?>" target="_blank">
880
									<?php
881
									echo sprintf(
882
										/* translators: %s Title */
883
										esc_html__( 'Need Help? See docs on "%s"', 'give' ),
884
										esc_html( $value['title'] )
885
									);
886
									?>
887
									<span class="dashicons dashicons-editor-help"></span>
888
								</a>
889
							</p>
890
						</td>
891
						</tr><?php
892
						break;
893
894
					// Default: run an action
895
					// You can add or handle your custom field action.
896
					default:
897
						// Get option value.
898
						$option_value = self::get_option( $option_name, $value['id'], $value['default'] );
899
						do_action( 'give_admin_field_' . $value['type'], $value, $option_value );
900
						break;
901
				}
902
			}
903
		}
904
905
		/**
906
		 * Helper function to get the formatted description for a given form field.
907
		 * Plugins can call this when implementing their own custom settings types.
908
		 *
909
		 * @since  1.8
910
		 *
911
		 * @param  array $value The form field value array
912
		 *
913
		 * @return string The HTML description of the field.
914
		 */
915
		public static function get_field_description( $value ) {
916
			$description = '';
917
918
			// Support for both 'description' and 'desc' args.
919
			$description_key = isset( $value['description'] ) ? 'description' : 'desc';
920
			$value           = ( isset( $value[ $description_key ] ) && ! empty( $value[ $description_key ] ) ) ? $value[ $description_key ] : '';
921
922
			if ( ! empty( $value ) ) {
923
				$description = '<div class="give-field-description">' . wp_kses_post( $value ) . '</div>';
924
			}
925
926
			return $description;
927
		}
928
929
930
		/**
931
		 * Helper function to get the formated title.
932
		 * Plugins can call this when implementing their own custom settings types.
933
		 *
934
		 * @since  1.8
935
		 *
936
		 * @param  array $value The form field value array
937
		 *
938
		 * @return array The description and tip as a 2 element array
939
		 */
940
		public static function get_field_title( $value ) {
941
			$title = esc_html( $value['title'] );
942
943
			// If html tag detected then allow them to print.
944
			if ( strip_tags( $title ) ) {
945
				$title = $value['title'];
946
			}
947
948
			return $title;
949
		}
950
951
		/**
952
		 * Save admin fields.
953
		 *
954
		 * Loops though the give options array and outputs each field.
955
		 *
956
		 * @since  1.8
957
		 *
958
		 * @param  array  $options     Options array to output
959
		 * @param  string $option_name Option name to save output. If empty then option will be store in there own option name i.e option id.
960
		 *
961
		 * @return bool
962
		 */
963
		public static function save_fields( $options, $option_name = '' ) {
964
			if ( empty( $_POST ) ) {
965
				return false;
966
			}
967
968
			// Options to update will be stored here and saved later.
969
			$update_options = array();
970
971
			// Loop options and get values to save.
972
			foreach ( $options as $option ) {
973
				if ( ! isset( $option['id'] ) || ! isset( $option['type'] ) ) {
974
					continue;
975
				}
976
977
				// Get posted value.
978
				if ( strstr( $option['id'], '[' ) ) {
979
					parse_str( $option['id'], $option_name_array );
980
					$field_option_name = current( array_keys( $option_name_array ) );
981
					$setting_name      = key( $option_name_array[ $field_option_name ] );
982
					$raw_value         = isset( $_POST[ $field_option_name ][ $setting_name ] ) ? wp_unslash( $_POST[ $field_option_name ][ $setting_name ] ) : null;
983
				} else {
984
					$field_option_name = $option['id'];
985
					$setting_name      = '';
986
					$raw_value         = isset( $_POST[ $option['id'] ] ) ? wp_unslash( $_POST[ $option['id'] ] ) : null;
987
				}
988
989
				// Format the value based on option type.
990
				switch ( $option['type'] ) {
991
					case 'checkbox' :
992
						$value = is_null( $raw_value ) ? '' : 'on';
993
						break;
994
					case 'wysiwyg'  :
995
					case 'textarea' :
996
						$value = wp_kses_post( trim( $raw_value ) );
997
						break;
998
					case 'multiselect' :
999
					case 'chosen' :
1000
						$value = array_filter( array_map( 'give_clean', (array) $raw_value ) );
1001
						break;
1002
					default :
1003
						$value = give_clean( $raw_value );
1004
						break;
1005
				}
1006
1007
				/**
1008
				 * Sanitize the value of an option.
1009
				 *
1010
				 * @since 1.8
1011
				 */
1012
				$value = apply_filters( 'give_admin_settings_sanitize_option', $value, $option, $raw_value );
1013
1014
				/**
1015
				 * Sanitize the value of an option by option name.
1016
				 *
1017
				 * @since 1.8
1018
				 */
1019
				$value = apply_filters( "give_admin_settings_sanitize_option_{$field_option_name}", $value, $option, $raw_value );
1020
1021
				if ( is_null( $value ) ) {
1022
					continue;
1023
				}
1024
1025
				// Check if option is an array and handle that differently to single values.
1026
				if ( $field_option_name && $setting_name ) {
1027
					if ( ! isset( $update_options[ $field_option_name ] ) ) {
1028
						$update_options[ $field_option_name ] = get_option( $field_option_name, array() );
1029
					}
1030
					if ( ! is_array( $update_options[ $field_option_name ] ) ) {
1031
						$update_options[ $field_option_name ] = array();
1032
					}
1033
					$update_options[ $field_option_name ][ $setting_name ] = $value;
1034
				} else {
1035
					$update_options[ $field_option_name ] = $value;
1036
				}
1037
			}
1038
1039
			// Save all options in our array or there own option name i.e. option id.
1040
			if ( empty( $option_name ) ) {
1041
				foreach ( $update_options as $name => $value ) {
1042
					update_option( $name, $value, false );
1043
1044
					/**
1045
					 * Trigger action.
1046
					 *
1047
					 * Note: This is dynamically fire on basis of option name.
1048
					 *
1049
					 * @since 1.8
1050
					 */
1051
					do_action( "give_save_option_{$name}", $value, $name );
1052
				}
1053
			} else {
1054
				$old_options    = ( $old_options = get_option( $option_name ) ) ? $old_options : array();
1055
				$update_options = array_merge( $old_options, $update_options );
1056
1057
				update_option( $option_name, $update_options, false );
1058
1059
				/**
1060
				 * Trigger action.
1061
				 *
1062
				 * Note: This is dynamically fire on basis of setting name.
1063
				 *
1064
				 * @since 1.8
1065
				 */
1066
				do_action( "give_save_settings_{$option_name}", $update_options, $option_name, $old_options );
1067
			}
1068
1069
			return true;
1070
		}
1071
1072
1073
		/**
1074
		 * Check if admin saving setting or not.
1075
		 *
1076
		 * @since 1.8.17
1077
		 *
1078
		 * @return bool
1079
		 */
1080
		public static function is_saving_settings() {
1081
			return self::verify_nonce();
1082
		}
1083
1084
		/**
1085
		 * Verify setting page
1086
		 *
1087
		 * @since  2.0
1088
		 * @access public
1089
		 *
1090
		 * @param string $tab
1091
		 * @param string $section
1092
		 *
1093
		 * @return bool
1094
		 */
1095
		public static function is_setting_page( $tab = '', $section = '' ) {
1096
			$is_setting_page = false;
1097
1098
			// Are we accessing admin?
1099
			if( ! is_admin() ) {
1100
				return $is_setting_page;
1101
			}
1102
1103
			// Are we accessing any give page?
1104
			if(
1105
				! isset( $_GET['post_type'], $_GET['page'] )
1106
				|| 'give_forms' !== give_clean( $_GET['post_type'] )
1107
			) {
1108
				return $is_setting_page;
1109
			}
1110
1111
			// Check fo setting tab.
1112
			if ( ! empty( $tab ) ) {
1113
				$is_setting_page = ( $tab === give_get_current_setting_tab() );
1114
			}
1115
1116
			// Check fo setting section.
1117
			if ( ! empty( $section ) ) {
1118
				$is_setting_page = ( $section === give_get_current_setting_section() );
1119
			}
1120
1121
			return $is_setting_page;
1122
		}
1123
	}
1124
1125
endif;
1126