PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.0
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.0
1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 1.8.0 All 210 releases
charitable / includes / admin / settings / class-charitable-settings.php

class-charitable-settings.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.0, at includes/admin/settings/class-charitable-settings.php

836 lines 27.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Charitable Settings UI.
4 *
5 * @package Charitable/Classes/Charitable_Settings
6 * @author David Bisset
7 * @copyright Copyright (c) 2023, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.0.0
10 * @version 1.0.0
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Settings' ) ) :
19
20 /**
21 * Charitable_Settings
22 *
23 * @final
24 * @since 1.0.0
25 */
26 final class Charitable_Settings {
27
28 /**
29 * The single instance of this class.
30 *
31 * @var Charitable_Settings|null
32 */
33 private static $instance = null;
34
35 /**
36 * Dynamic groups.
37 *
38 * @since 1.5.7
39 *
40 * @var array
41 */
42 private $dynamic_groups;
43
44 /**
45 * List of static pages, used in some settings.
46 *
47 * @since 1.5.9
48 *
49 * @var array
50 */
51 private $pages;
52
53 /**
54 * Create object instance.
55 *
56 * @since 1.0.0
57 */
58 private function __construct() {
59 do_action( 'charitable_admin_settings_start', $this );
60
61 add_action( 'charitable_after_admin_settings', [ $this, 'settings_cta' ] );
62 }
63
64 /**
65 * Returns and/or create the single instance of this class.
66 *
67 * @since 1.2.0
68 *
69 * @return Charitable_Settings
70 */
71 public static function get_instance() {
72 if ( is_null( self::$instance ) ) {
73 self::$instance = new self();
74 }
75
76 return self::$instance;
77 }
78
79 /**
80 * Return the array of tabs used on the settings page.
81 *
82 * @since 1.0.0
83 *
84 * @return string[]
85 */
86 public function get_sections() {
87 /**
88 * Filter the settings tabs.
89 *
90 * @since 1.0.0
91 *
92 * @param string[] $tabs List of tabs in key=>label format.
93 */
94 return apply_filters(
95 'charitable_settings_tabs',
96 array(
97 'general' => __( 'General', 'charitable' ),
98 'gateways' => __( 'Payment Gateways', 'charitable' ),
99 'emails' => __( 'Emails', 'charitable' ),
100 'privacy' => __( 'Privacy', 'charitable' ),
101 'tools' => __( 'Tools', 'charitable' ),
102 'advanced' => __( 'Advanced', 'charitable' ),
103 )
104 );
105
106 }
107
108 /**
109 * Optionally add the extensions tab.
110 *
111 * @since 1.3.0
112 *
113 * @param string[] $tabs The existing set of tabs.
114 * @return string[]
115 */
116 public function maybe_add_extensions_tab( $tabs ) {
117 $actual_tab = isset( $_GET['tab'] ) ? $_GET['tab'] : 'general';
118
119 /* Set the tab to 'extensions' */
120 $_GET['tab'] = 'extensions';
121
122 /**
123 * Filter the settings in the extensions tab.
124 *
125 * @since 1.3.0
126 *
127 * @param array $fields Array of fields. Empty by default.
128 */
129 $settings = apply_filters( 'charitable_settings_tab_fields_extensions', array() );
130
131 /* Set the tab back to whatever it actually is */
132 $_GET['tab'] = $actual_tab;
133
134 if ( ! empty( $settings ) ) {
135 $tabs = charitable_add_settings_tab(
136 $tabs,
137 'extensions',
138 __( 'Extensions', 'charitable' ),
139 array(
140 'index' => 4,
141 )
142 );
143 }
144
145 return $tabs;
146 }
147
148 /**
149 * Add the hidden "extensions" section field.
150 *
151 * @since 1.6.7
152 *
153 * @param array $fields All the settings fields.
154 * @return array
155 */
156 public function add_hidden_extensions_setting_field( $fields ) {
157 if ( ! array_key_exists( 'extensions', $fields ) ) {
158 return $fields;
159 }
160
161 $fields['extensions']['section'] = array(
162 'title' => '',
163 'type' => 'hidden',
164 'priority' => 10000,
165 'value' => 'extensions',
166 'save' => false,
167 );
168
169 return $fields;
170 }
171
172 /**
173 * Register setting.
174 *
175 * @since 1.0.0
176 *
177 * @return void
178 */
179 public function register_settings() {
180 if ( ! charitable_is_settings_view() ) {
181 return;
182 }
183
184 register_setting( 'charitable_settings', 'charitable_settings', array( $this, 'sanitize_settings' ) );
185
186 $fields = $this->get_fields();
187
188 if ( empty( $fields ) ) {
189 return;
190 }
191
192 $sections = array_merge( $this->get_sections(), $this->get_dynamic_groups() );
193
194 /* Register each section */
195 foreach ( $sections as $section_key => $section ) {
196 $section_id = 'charitable_settings_' . $section_key;
197
198 add_settings_section(
199 $section_id,
200 __return_null(),
201 '__return_false',
202 $section_id
203 );
204
205 if ( ! isset( $fields[ $section_key ] ) || empty( $fields[ $section_key ] ) ) {
206 continue;
207 }
208
209 /* Sort by priority */
210 $section_fields = $fields[ $section_key ];
211 uasort( $section_fields, 'charitable_priority_sort' );
212
213 /* Add the individual fields within the section */
214 foreach ( $section_fields as $key => $field ) {
215 $this->register_field( $field, array( $section_key, $key ) );
216 }
217 }
218 }
219
220 /**
221 * Sanitize submitted settings before saving to the database
222 * This includes: "workaround" for Stripe keys with 1.7.0.0, additional settings options after 1.7.0.6+
223 *
224 * @since 1.0.0
225 *
226 * @param array $values The submitted values.
227 * @return string
228 */
229 public function sanitize_settings( $values ) {
230
231 $old_values = get_option( 'charitable_settings', array() );
232 $new_values = array();
233
234 if ( ! is_array( $old_values ) ) {
235 $old_values = array();
236 }
237
238 if ( ! is_array( $values ) ) {
239 $values = array();
240 }
241
242 /* Loop through all fields, merging the submitted values into the master array */
243 foreach ( $values as $section => $submitted ) {
244 $new_values = array_merge( $new_values, $this->get_section_submitted_values( $section, $submitted ) );
245 }
246
247 $settings_keys = array_keys( $new_values );
248
249 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
250 error_log( 'santiize_settings' );
251 error_log( 'values:' );
252 error_log( print_r( $values, true ) );
253 error_log( 'old_values:' );
254 error_log( print_r( $old_values, true ) );
255 error_log( 'new_values:' );
256 error_log( print_r( $new_values, true ) );
257 }
258
259 // determine if Charitable gateway "test mode" is being changed, and if so add a notice to the user.
260 if ( array_key_exists('test_mode', $new_values ) && array_key_exists('test_mode', $old_values ) && $old_values['test_mode'] !== $new_values['test_mode'] ) {
261 $old_settings_keys = array_keys( $old_values );
262 $dismissible = true;
263 if ( in_array( 'gateways_stripe', $old_settings_keys ) ) {
264 charitable_get_admin_notices()->add_notice( 'Some active payment gateways <strong>(including Stripe)</strong> might have reset their connections due to an update in the test mode. Please check your active payment gateways in ensure they are still connected.', 'warning', false, $dismissible );
265 } else {
266 charitable_get_admin_notices()->add_notice( 'Some active payment gateways might have reset their connections due to an update in the test mode. Please check your active payment gateways in ensure they are still connected.', 'warning', false, $dismissible );
267 }
268 }
269
270 if ( in_array( 'gateways_stripe', $settings_keys ) && charitable()->is_stripe_connect_addon() && false === charitable_using_stripe_connect() ) {
271 // non-existant array keys in the array for API keys might be a result of the "manual update key" feature which is based on ajax and might not load keys into form if the user doesn't click on the link in the settings to view/edit them.
272 if ( ! array_key_exists( 'live_secret_key', $values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['live_secret_key'] ) && ( false !== $old_values['gateways_stripe']['live_secret_key'] ) ) {
273 $values['gateways_stripe']['live_secret_key'] = $old_values['gateways_stripe']['live_secret_key'];
274 }
275 if ( ! array_key_exists( 'live_public_key', $values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['live_public_key'] ) && ( false !== $old_values['gateways_stripe']['live_public_key'] ) ) {
276 $values['gateways_stripe']['live_public_key'] = $old_values['gateways_stripe']['live_secret_key'];
277 }
278 if ( ! array_key_exists( 'test_secret_key', $values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['test_secret_key'] ) && ( false !== $old_values['gateways_stripe']['test_secret_key'] ) ) {
279 $values['gateways_stripe']['test_secret_key'] = $old_values['gateways_stripe']['test_secret_key'];
280 }
281 if ( ! array_key_exists( 'test_public_key', $values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['test_public_key'] ) && ( false !== $old_values['gateways_stripe']['test_public_key'] ) ) {
282 $values['gateways_stripe']['test_public_key'] = $old_values['gateways_stripe']['test_public_key'];
283 }
284 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
285 error_log( 'update:' );
286 error_log( print_r( $values, true ) );
287 }
288 }
289
290 // determine if stripe is being returned as new values - if so, then perform the API key save workaround
291 if ( in_array( 'gateways_stripe', $settings_keys ) && charitable()->is_stripe_connect_addon() && false === charitable_using_stripe_connect() ) {
292 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
293 error_log( 'there is a stripe connect addon but we are not using stripe connect' );
294 }
295 // the stripe connect addon is installed AND the AM Stripe Connect isn't being used... so it's possible the keys could be manual and the user could be updating them... therefore let's just make sure the new values match the values incoming.
296 $new_values['gateways_stripe']['live_secret_key'] = ( isset( $values['gateways_stripe']['live_secret_key'] ) && ( false !== $values['gateways_stripe']['live_secret_key'] ) ) ? $values['gateways_stripe']['live_secret_key'] : null;
297 $new_values['gateways_stripe']['live_public_key'] = ( isset( $values['gateways_stripe']['live_public_key'] ) && ( false !== $values['gateways_stripe']['live_public_key'] ) ) ? $values['gateways_stripe']['live_public_key'] : null;
298 $new_values['gateways_stripe']['test_secret_key'] = ( isset( $values['gateways_stripe']['test_secret_key'] ) && ( false !== $values['gateways_stripe']['test_secret_key'] ) ) ? $values['gateways_stripe']['test_secret_key'] : null;
299 $new_values['gateways_stripe']['test_public_key'] = ( isset( $values['gateways_stripe']['test_public_key'] ) && ( false !== $values['gateways_stripe']['test_public_key'] ) ) ? $values['gateways_stripe']['test_public_key'] : null;
300 } else if ( in_array( 'gateways_stripe', $settings_keys ) ) {
301 // otherwise we preserve the keys
302 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
303 error_log( 'charitable debug, final with debug on:' );
304 $new_values['gateways_stripe']['live_secret_key'] = ( isset( $values['gateways_stripe']['live_secret_key'] ) && ( false !== $values['gateways_stripe']['live_secret_key'] ) ) ? $values['gateways_stripe']['live_secret_key'] : null;
305 $new_values['gateways_stripe']['live_public_key'] = ( isset( $values['gateways_stripe']['live_public_key'] ) && ( false !== $values['gateways_stripe']['live_public_key'] ) ) ? $values['gateways_stripe']['live_public_key'] : null;
306 $new_values['gateways_stripe']['test_secret_key'] = ( isset( $values['gateways_stripe']['test_secret_key'] ) && ( false !== $values['gateways_stripe']['test_secret_key'] ) ) ? $values['gateways_stripe']['test_secret_key'] : null;
307 $new_values['gateways_stripe']['test_public_key'] = ( isset( $values['gateways_stripe']['test_public_key'] ) && ( false !== $values['gateways_stripe']['test_public_key'] ) ) ? $values['gateways_stripe']['test_public_key'] : null;
308 } else {
309 $new_values['gateways_stripe']['live_secret_key'] = ( isset( $old_values['gateways_stripe']['live_secret_key'] ) && ( false !== $old_values['gateways_stripe']['live_secret_key'] ) ) ? $old_values['gateways_stripe']['live_secret_key'] : null;
310 $new_values['gateways_stripe']['live_public_key'] = ( isset( $old_values['gateways_stripe']['live_public_key'] ) && ( false !== $old_values['gateways_stripe']['live_public_key'] ) ) ? $old_values['gateways_stripe']['live_public_key'] : null;
311 $new_values['gateways_stripe']['test_secret_key'] = ( isset( $old_values['gateways_stripe']['test_secret_key'] ) && ( false !== $old_values['gateways_stripe']['test_secret_key'] ) ) ? $old_values['gateways_stripe']['test_secret_key'] : null;
312 $new_values['gateways_stripe']['test_public_key'] = ( isset( $old_values['gateways_stripe']['test_public_key'] ) && ( false !== $old_values['gateways_stripe']['test_public_key'] ) ) ? $old_values['gateways_stripe']['test_public_key'] : null;
313 }
314 }
315
316 // preserve any webhook keys, regardless if stripe connect addon is active or not.
317 if ( in_array( 'gateways_stripe', $settings_keys ) ) {
318 if ( array_key_exists( 'test_webhook_id', $old_values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['test_webhook_id'] ) ) {
319 $new_values['gateways_stripe']['test_webhook_id'] = $old_values['gateways_stripe']['test_webhook_id'];
320 }
321 if ( array_key_exists( 'live_webhook_id', $old_values['gateways_stripe'] ) && isset( $old_values['gateways_stripe']['live_webhook_id'] ) ) {
322 $new_values['gateways_stripe']['live_webhook_id'] = $old_values['gateways_stripe']['live_webhook_id'];
323 }
324 }
325
326 // account for incoming legacy licenses (1.7.0.4+)
327 // all we are doing is adding the licenses into the values so that the save_license hook can retreieve them and validate, etc.
328 if ( ! empty( $values['legacy_licenses'] ) && isset( $values['advanced']['section'] ) && 'licenses' === $values['advanced']['section'] ) {
329 if ( ! isset( $new_values['licenses']['legacy'] ) ) {
330 $new_values['licenses_legacy'] = (array) $values['legacy_licenses'];
331 }
332 }
333
334 // ensure any hex color text files are valid hex fields
335 if ( isset( $new_values['donation_form_default_highlight_colour'] ) ) {
336 $color_to_test = esc_html( $new_values['donation_form_default_highlight_colour'] );
337 $color_valid = false;
338 // check for a hex color string
339 if ( preg_match( '/^#[a-f0-9]{6}$/i', $color_to_test ) ) {
340 // hex color is valid
341 $color_valid = true;
342 }
343 // Check for a hex color string without hash
344 if ( preg_match( '/^[a-f0-9]{6}$/i', $color_to_test ) ) {
345 // hex color is valid
346 $color_valid = true;
347 $new_values['donation_form_default_highlight_colour'] = '#' . $color_to_test;
348 }
349 if ( false === $color_valid ) {
350 // not valid, make sure it is blank.
351 $new_values['donation_form_default_highlight_colour'] = false;
352 }
353 // clear the transient that stores the color styles
354 delete_transient( 'charitable_custom_styles' );
355 }
356
357 $values = wp_parse_args( $new_values, $old_values );
358
359 if ( defined( 'CHARITABLE_DEBUG' ) && CHARITABLE_DEBUG ) {
360 error_log( 'santiize_settings values updated' );
361 error_log( print_r( $values, true ) );
362 }
363
364 /**
365 * Filter sanitized settings.
366 *
367 * @since 1.0.0
368 *
369 * @param array $values All values, merged.
370 * @param array $new_values Newly submitted values.
371 * @param array $old_values Old settings.
372 */
373
374 $values = apply_filters( 'charitable_save_settings', $values, $new_values, $old_values );
375
376 // save a temp transient for legacy licenses (1.7.0.8+)
377 // purpose is to provide better error reporting (transient should be deleted after settings page (advanced tab) is loaded).
378 if ( isset( $_POST['charitable_settings']['legacy_licenses'] ) ) {
379 $referer = wp_get_referer();
380 if ( false !== strpos( $referer, 'admin.php?page=charitable-settings&tab=advanced' ) ) {
381 set_transient( '_charitable_legacy_license_info', $_POST['charitable_settings']['legacy_licenses'], MINUTE_IN_SECONDS );
382 }
383 }
384
385 $this->add_update_message( __( 'Settings saved', 'charitable' ), 'success' );
386
387 return $values;
388 }
389
390 /**
391 * Checkbox settings should always be either 1 or 0.
392 *
393 * @since 1.0.0
394 *
395 * @param mixed $value Submitted value for field.
396 * @param array $field Field definition.
397 * @return int
398 */
399 public function sanitize_checkbox_value( $value, $field ) {
400 if ( isset( $field['type'] ) && 'checkbox' == $field['type'] ) {
401 $value = intval( $value && 'on' == $value );
402 }
403
404 return $value;
405 }
406
407 /**
408 * Render field. This is the default callback used for all fields, unless an alternative callback has been specified.
409 *
410 * @since 1.0.0
411 *
412 * @param array $args Field definition.
413 * @return void
414 */
415 public function render_field( $args ) {
416 $field_type = isset( $args['type'] ) ? $args['type'] : 'text';
417
418 charitable_admin_view( 'settings/' . $field_type, $args );
419 }
420
421 /**
422 * Returns an array of all pages in the id=>title format.
423 *
424 * @since 1.0.0
425 *
426 * @return string[]
427 */
428 public function get_pages() {
429 if ( ! isset( $this->pages ) ) {
430 $this->pages = charitable_get_pages_options();
431 }
432
433 return $this->pages;
434 }
435
436 /**
437 * Add an update message.
438 *
439 * @since 1.4.6
440 *
441 * @param string $message The message text.
442 * @param string $type The type of message. Options: 'error', 'success', 'warning', 'info'.
443 * @param boolean $dismissible Whether the message can be dismissed.
444 * @return void
445 */
446 public function add_update_message( $message, $type = 'error', $dismissible = true ) {
447 if ( ! in_array( $type, array( 'error', 'success', 'warning', 'info' ) ) ) {
448 $type = 'error';
449 }
450
451 charitable_get_admin_notices()->add_notice( $message, $type, false, $dismissible );
452 }
453
454 /**
455 * Recursively add settings fields, given an array.
456 *
457 * @since 1.0.0
458 *
459 * @param array $field The setting field.
460 * @param array $keys Array containing the section key and field key.
461 * @return void
462 */
463 private function register_field( $field, $keys ) {
464 $section_id = 'charitable_settings_' . $keys[0];
465
466 if ( isset( $field['render'] ) && ! $field['render'] ) {
467 return;
468 }
469
470 /* Drop the first key, which is the section identifier */
471 $field['name'] = implode( '][', $keys );
472
473 if ( ! $this->is_dynamic_group( $keys[0] ) ) {
474 array_shift( $keys );
475 }
476
477 $field['key'] = $keys;
478 $field['classes'] = $this->get_field_classes( $field );
479 $callback = isset( $field['callback'] ) ? $field['callback'] : array( $this, 'render_field' );
480 $label = $this->get_field_label( $field, end( $keys ) );
481
482 add_settings_field(
483 sprintf( 'charitable_settings_%s', implode( '_', $keys ) ),
484 $label,
485 $callback,
486 $section_id,
487 $section_id,
488 $field
489 );
490 }
491
492 /**
493 * Return the label for the given field.
494 *
495 * @since 1.0.0
496 *
497 * @param array $field The field definition.
498 * @param string $key The field key.
499 * @return string
500 */
501 private function get_field_label( $field, $key ) {
502 $label = '';
503
504 if ( isset( $field['label_for'] ) ) {
505 $label = $field['label_for'];
506 }
507
508 if ( isset( $field['title'] ) ) {
509 $label = $field['title'];
510 }
511
512 return $label;
513 }
514
515 /**
516 * Return a space separated string of classes for the given field.
517 *
518 * @since 1.0.0
519 *
520 * @param array $field Field definition.
521 * @return string
522 */
523 private function get_field_classes( $field ) {
524 $classes = array( 'charitable-settings-field' );
525
526 if ( isset( $field['class'] ) ) {
527 $classes[] = $field['class'];
528 }
529
530 /**
531 * Filter the list of classes to apply to settings fields.
532 *
533 * @since 1.0.0
534 *
535 * @param array $classes The list of classes.
536 * @param array $field The field definition.
537 */
538 $classes = apply_filters( 'charitable_settings_field_classes', $classes, $field );
539
540 return implode( ' ', $classes );
541 }
542
543 /**
544 * Return an array with all the fields & sections to be displayed.
545 *
546 * @uses charitable_settings_fields
547 * @see Charitable_Settings::register_setting()
548 * @since 1.0.0
549 *
550 * @return array
551 */
552 private function get_fields() {
553 /**
554 * Use the charitable_settings_tab_fields to include the fields for new tabs.
555 * DO NOT use it to add individual fields. That should be done with the
556 * filters within each of the methods.
557 */
558 $fields = array();
559
560 foreach ( $this->get_sections() as $section_key => $section ) {
561 /**
562 * Filter the array of fields to display in a particular tab.
563 *
564 * @since 1.0.0
565 *
566 * @param array $fields Array of fields.
567 */
568 $fields[ $section_key ] = apply_filters( 'charitable_settings_tab_fields_' . $section_key, array() );
569 }
570
571 /**
572 * Filter the array of settings fields.
573 *
574 * @since 1.0.0
575 *
576 * @param array $fields Array of fields.
577 */
578 return apply_filters( 'charitable_settings_tab_fields', $fields );
579 }
580
581 /**
582 * Get the submitted value for a particular setting.
583 *
584 * @since 1.0.0
585 *
586 * @param string $key The key of the setting being saved.
587 * @param array $field The setting field.
588 * @param array $submitted The submitted values.
589 * @param string $section The section being saved.
590 * @return mixed|null Returns null if the value was not submitted or is not applicable.
591 */
592 private function get_setting_submitted_value( $key, $field, $submitted, $section ) {
593 $value = null;
594
595 if ( isset( $field['save'] ) && ! $field['save'] ) {
596 return $value;
597 }
598
599 $field_type = isset( $field['type'] ) ? $field['type'] : '';
600
601 switch ( $field_type ) {
602
603 case 'checkbox':
604 $value = intval( array_key_exists( $key, $submitted ) && 'on' == $submitted[ $key ] );
605 break;
606
607 case 'multi-checkbox':
608 $value = isset( $submitted[ $key ] ) ? $submitted[ $key ] : array();
609 break;
610
611 case '':
612 case 'heading':
613 return $value;
614
615 default:
616 if ( ! array_key_exists( $key, $submitted ) ) {
617 return $value;
618 }
619
620 $value = $submitted[ $key ];
621
622 }//end switch
623
624 /**
625 * General way to sanitize values. If you only need to sanitize a
626 * specific setting, used the filter below instead.
627 *
628 * @since 1.0.0
629 *
630 * @param mixed $value The current setting value.
631 * @param array $field The field configuration.
632 * @param array $submitted All submitted data.
633 * @param string $key The setting key.
634 * @param string $section The section being saved.
635 */
636 $value = apply_filters( 'charitable_sanitize_value', $value, $field, $submitted, $key, $section );
637
638 /**
639 * Sanitize the setting value.
640 *
641 * The filter hook is formatted like this: charitable_sanitize_value_{$section}_{$key}.
642 *
643 * @since 1.5.0
644 *
645 * @param mixed $value The current setting value.
646 * @param array $field The field configuration.
647 * @param array $submitted All submitted data.
648 */
649 return apply_filters( 'charitable_sanitize_value_' . $section . '_' . $key, $value, $field, $submitted );
650 }
651
652 /**
653 * Return the submitted values for the given section.
654 *
655 * @since 1.0.0
656 *
657 * @param string $section The section being edited.
658 * @param array $submitted The submitted values.
659 * @return array
660 */
661 private function get_section_submitted_values( $section, $submitted ) {
662 $values = array();
663 $form_fields = $this->get_fields();
664
665 if ( ! isset( $form_fields[ $section ] ) ) {
666 return $values;
667 }
668
669 foreach ( $form_fields[ $section ] as $key => $field ) {
670 $value = $this->get_setting_submitted_value( $key, $field, $submitted, $section );
671
672 if ( is_null( $value ) ) {
673 continue;
674 }
675
676 if ( $this->is_dynamic_group( $section ) ) {
677 $values[ $section ][ $key ] = $value;
678 continue;
679 }
680
681 $values[ $key ] = $value;
682 }
683
684 return $values;
685 }
686
687 /**
688 * Return list of dynamic groups.
689 *
690 * @since 1.0.0
691 *
692 * @return string[]
693 */
694 private function get_dynamic_groups() {
695 if ( ! isset( $this->dynamic_groups ) ) {
696 /**
697 * Filter the list of dynamic groups.
698 *
699 * @since 1.0.0
700 *
701 * @param array $groups The dynamic groups.
702 */
703 $this->dynamic_groups = apply_filters( 'charitable_dynamic_groups', array() );
704 }
705
706 return $this->dynamic_groups;
707 }
708
709 /**
710 * Returns whether the given key indicates the start of a new section of the settings.
711 *
712 * @since 1.0.0
713 *
714 * @param string $composite_key The unique key for this group.
715 * @return boolean
716 */
717 private function is_dynamic_group( $composite_key ) {
718 return array_key_exists( $composite_key, $this->get_dynamic_groups() );
719 }
720
721 /* DEPRECATED FUNCTIONS */
722
723 /**
724 * Get the update messages.
725 *
726 * @deprecated 1.7.0
727 *
728 * @since 1.4.13 Deprecated.
729 */
730 public function get_update_messages() {
731 charitable_get_deprecated()->deprecated_function(
732 __METHOD__,
733 '1.4.13',
734 'Charitable_Admin_Notices::get_notices()'
735 );
736
737 return charitable_get_admin_notices()->get_notices();
738 }
739
740 /**
741 * Display upgrade notice at the bottom on the plugin settings pages.
742 *
743 * @since 1.7.0.4
744 *
745 * @param string $view Current view inside the plugin settings page.
746 */
747 public function settings_cta( $view = false ) {
748
749 if ( charitable_is_pro() ) {
750 // no need to display this cta since they have a valid license.
751 return;
752 }
753
754 if ( get_option( 'charitable_lite_settings_upgrade', false ) || apply_filters( 'charitable_lite_settings_upgrade', false ) ) {
755 return;
756 }
757 ?>
758 <div class="settings-lite-cta">
759 <button type="button" class="button-link charitable-banner-dismiss dismiss">x</button>
760 <h5><?php esc_html_e( 'Get Charitable Pro and Unlock all the Powerful Features', 'charitable' ); ?></h5>
761 <p><?php esc_html_e( 'Thanks for being a loyal Charitable Lite user. Upgrade to Charitable Pro to unlock all the awesome features and experience why Charitable is consistently rated a top WordPress donation and fundraising plugin.', 'charitable' ); ?></p>
762 <p>
763 <?php
764 printf( __( 'We know that you will truly love Charitable. Over 10,000+ non-profits who have chosen Charitable to get more donations from their website can\'t be wrong!', 'charitable' ) );
765 ?>
766 </p>
767 <h6><?php esc_html_e( 'Pro Features:', 'charitable' ); ?></h6>
768 <div class="list">
769 <ul>
770 <li><?php esc_html_e( 'Offer recurring donations to donors', 'charitable' ); ?></li>
771 <li><?php esc_html_e( 'Use fee relief to keep more donation dollars', 'charitable' ); ?></li>
772 <li><?php esc_html_e( 'Integrate with popular email marketing platforms', 'charitable' ); ?></li>
773 <li><?php esc_html_e( 'Expand your reach with peer-to-peer fundraising', 'charitable' ); ?></li>
774 <li><?php esc_html_e( 'Allow donors to crowdfund donations', 'charitable' ); ?></li>
775 </ul>
776 <ul>
777 <li><?php esc_html_e( 'Automate common tasks with Zapier and smart workflows', 'charitable' ); ?></li>
778 <li><?php esc_html_e( 'Run campaigns with ambassador and team support', 'charitable' ); ?></li>
779 <li><?php esc_html_e( 'Advanced donation management with annual receipts' ); ?></li>
780 <li><?php esc_html_e( 'Allow donors to give donations anonymously', 'charitable' ); ?></li>
781 <li><?php esc_html_e( 'Add videos and updates to all campaigns', 'charitable' ); ?></li>
782 </ul>
783 </div>
784 <p>
785 <a href="<?php echo esc_url( charitable_pro_upgrade_url( 'settings-upgrade' ) ); ?>" target="_blank" rel="noopener noreferrer">
786 <?php esc_html_e( 'Get Charitable Pro Today and Unlock all the Powerful Features »', 'charitable' ); ?>
787 </a>
788 </p>
789 <p>
790 <?php
791 echo wp_kses(
792 __( '<strong>Bonus:</strong> Charitable Lite users get up to <span class="green">$300 off regular price</span>, automatically applied at checkout.', 'charitable' ),
793 [
794 'strong' => [],
795 'span' => [
796 'class' => [],
797 ],
798 ]
799 );
800 ?>
801 </p>
802 </div>
803 <script type="text/javascript">
804 jQuery( function ( $ ) {
805 $( document ).on( 'click', '.settings-lite-cta .dismiss', function ( event ) {
806 event.preventDefault();
807 $.post( ajaxurl, {
808 action: 'charitable_lite_settings_upgrade',
809 chartiable_action: 'remove_lite_cta'
810 } );
811 $( '.settings-lite-cta' ).remove();
812 } );
813 } );
814 </script>
815 <?php
816 }
817
818 /**
819 * Dismiss upgrade notice at the bottom on the plugin settings pages.
820 *
821 * @since 1.7.0.4
822 */
823 public function settings_cta_dismiss() {
824
825 if ( ! charitable_current_user_can() ) {
826 wp_send_json_error();
827 }
828
829 update_option( 'charitable_lite_settings_upgrade', time() );
830
831 wp_send_json_success();
832 }
833 }
834
835 endif;
836