PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.2.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.2.0
1.6.0 1.5.1 1.5.0 1.4.0 1.3.0 trunk 0.0.1 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0
suredonation / inc / api / settings-api.php

settings-api.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management 1.2.0, at inc/api/settings-api.php

687 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * General Settings REST API endpoints.
4 *
5 * @package SureDonation
6 */
7
8 namespace SureDonation\Inc\API;
9
10 use SureDonation\Inc\Helper;
11 use SureDonation\Inc\Payments\Payment_Helper;
12 use WP_Error;
13 use WP_REST_Request;
14 use WP_REST_Response;
15 use WP_REST_Server;
16
17 // Exit if accessed directly.
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Settings API class.
24 *
25 * @since 0.0.1
26 */
27 class Settings_API {
28 /**
29 * Option key for email notifications within consolidated options.
30 *
31 * @since 0.0.1
32 */
33 public const EMAIL_OPTION_KEY = 'email_notifications';
34
35 /**
36 * Option key for AI settings within consolidated options.
37 *
38 * @since 1.0.0
39 */
40 public const AI_OPTION_KEY = 'ai_settings';
41
42 /**
43 * Option key for spam protection settings within consolidated options.
44 *
45 * @since 1.1.0
46 */
47 public const SPAM_OPTION_KEY = 'spam_protection_settings';
48
49 /**
50 * Option key for donor management settings within consolidated options.
51 *
52 * @since 1.0.0
53 */
54 public const DONOR_OPTION_KEY = 'donor_settings';
55
56 /**
57 * Get settings endpoints.
58 *
59 * @return array<string, mixed>
60 * @since 0.0.1
61 */
62 public function get_endpoints() {
63 return [
64 // Get currency data for block editor (public endpoint).
65 '/settings' => [
66 'methods' => WP_REST_Server::READABLE,
67 'callback' => [ $this, 'get_currency_settings' ],
68 'permission_callback' => '__return_true',
69 ],
70
71 // Get and update general settings.
72 '/settings/general' => [
73 [
74 'methods' => WP_REST_Server::READABLE,
75 'callback' => [ $this, 'get_settings' ],
76 'permission_callback' => [ $this, 'check_permissions' ],
77 ],
78 [
79 'methods' => WP_REST_Server::EDITABLE,
80 'callback' => [ $this, 'update_settings' ],
81 'permission_callback' => [ $this, 'check_permissions' ],
82 ],
83 ],
84
85 // Get available currencies.
86 '/settings/currencies' => [
87 'methods' => WP_REST_Server::READABLE,
88 'callback' => [ $this, 'get_currencies' ],
89 'permission_callback' => [ $this, 'check_permissions' ],
90 ],
91
92 // Email notifications are managed per-form via post meta.
93 // See inc/form-editor/assets.php for the form-level email system.
94 // AI settings.
95 '/settings/ai' => [
96 [
97 'methods' => WP_REST_Server::READABLE,
98 'callback' => [ $this, 'get_ai_settings' ],
99 'permission_callback' => [ $this, 'check_permissions' ],
100 ],
101 [
102 'methods' => WP_REST_Server::EDITABLE,
103 'callback' => [ $this, 'update_ai_settings' ],
104 'permission_callback' => [ $this, 'check_permissions' ],
105 ],
106 ],
107
108 // Spam protection settings.
109 '/settings/spam-protection' => [
110 [
111 'methods' => WP_REST_Server::READABLE,
112 'callback' => [ $this, 'get_spam_protection_settings' ],
113 'permission_callback' => [ $this, 'check_permissions' ],
114 ],
115 [
116 'methods' => WP_REST_Server::EDITABLE,
117 'callback' => [ $this, 'update_spam_protection_settings' ],
118 'permission_callback' => [ $this, 'check_permissions' ],
119 ],
120 ],
121
122 // Miscellaneous settings (usage tracking, etc.).
123 '/settings/misc' => [
124 [
125 'methods' => WP_REST_Server::READABLE,
126 'callback' => [ $this, 'get_misc_settings' ],
127 'permission_callback' => [ $this, 'check_permissions' ],
128 ],
129 [
130 'methods' => WP_REST_Server::EDITABLE,
131 'callback' => [ $this, 'update_misc_settings' ],
132 'permission_callback' => [ $this, 'check_permissions' ],
133 'args' => [
134 'usage_tracking' => [
135 'type' => 'boolean',
136 'sanitize_callback' => 'rest_sanitize_boolean',
137 ],
138 ],
139 ],
140 ],
141
142 // Donor management settings.
143 '/settings/donor' => [
144 [
145 'methods' => WP_REST_Server::READABLE,
146 'callback' => [ $this, 'get_donor_settings' ],
147 'permission_callback' => [ $this, 'check_permissions' ],
148 ],
149 [
150 'methods' => WP_REST_Server::EDITABLE,
151 'callback' => [ $this, 'update_donor_settings' ],
152 'permission_callback' => [ $this, 'check_permissions' ],
153 'args' => [
154 'create_wp_user' => [
155 'type' => 'boolean',
156 'sanitize_callback' => 'rest_sanitize_boolean',
157 ],
158 ],
159 ],
160 ],
161
162 // Form validation default messages.
163 '/settings/validation' => [
164 [
165 'methods' => WP_REST_Server::READABLE,
166 'callback' => [ $this, 'get_validation_settings' ],
167 'permission_callback' => [ $this, 'check_permissions' ],
168 ],
169 [
170 'methods' => WP_REST_Server::EDITABLE,
171 'callback' => [ $this, 'update_validation_settings' ],
172 'permission_callback' => [ $this, 'check_permissions' ],
173 ],
174 ],
175
176 // Privacy settings (data retention, consent, privacy/terms fields).
177 '/settings/privacy' => [
178 [
179 'methods' => WP_REST_Server::READABLE,
180 'callback' => [ $this, 'get_privacy_settings' ],
181 'permission_callback' => [ $this, 'check_permissions' ],
182 ],
183 [
184 'methods' => WP_REST_Server::EDITABLE,
185 'callback' => [ $this, 'update_privacy_settings' ],
186 'permission_callback' => [ $this, 'check_permissions' ],
187 ],
188 ],
189
190 // Send test email.
191 '/settings/email/test' => [
192 'methods' => WP_REST_Server::CREATABLE,
193 'callback' => [ $this, 'send_test_email' ],
194 'permission_callback' => [ $this, 'check_permissions' ],
195 ],
196 ];
197 }
198
199 /**
200 * Get the Privacy settings (stored values merged over the defaults).
201 *
202 * @param WP_REST_Request $request Request object.
203 * @return WP_REST_Response
204 * @since 1.2.0
205 */
206 public function get_privacy_settings( $request ) {
207 unset( $request ); // Unused parameter.
208
209 return new WP_REST_Response(
210 [
211 'success' => true,
212 'settings' => \SureDonation\Inc\Privacy\Privacy_Settings::get_settings(),
213 ],
214 200
215 );
216 }
217
218 /**
219 * Update the Privacy settings.
220 *
221 * @param WP_REST_Request $request Request object.
222 * @return WP_REST_Response
223 * @since 1.2.0
224 */
225 public function update_privacy_settings( $request ) {
226 $params = $request->get_json_params();
227 $sanitized = \SureDonation\Inc\Privacy\Privacy_Settings::sanitize( is_array( $params ) ? $params : [] );
228
229 Helper::update_suredonation_option( \SureDonation\Inc\Privacy\Privacy_Settings::OPTION_KEY, $sanitized );
230
231 return new WP_REST_Response(
232 [
233 'success' => true,
234 'settings' => $sanitized,
235 ],
236 200
237 );
238 }
239
240 /**
241 * Get the form-validation default messages.
242 *
243 * Returns the stored admin overrides merged over the translatable defaults
244 * so every configurable message always has a value in the editor.
245 *
246 * @param WP_REST_Request $request Request object.
247 * @return WP_REST_Response
248 * @since 1.1.0
249 */
250 public function get_validation_settings( $request ) {
251 unset( $request ); // Unused parameter.
252
253 $defaults = \SureDonation\Inc\Field_Validation::default_validation_messages();
254 $stored = Helper::get_suredonation_option( \SureDonation\Inc\Field_Validation::VALIDATION_MESSAGES_OPTION_KEY, [] );
255
256 return new WP_REST_Response(
257 [
258 'success' => true,
259 'settings' => wp_parse_args( is_array( $stored ) ? $stored : [], $defaults ),
260 ],
261 200
262 );
263 }
264
265 /**
266 * Update the form-validation default messages.
267 *
268 * @param WP_REST_Request $request Request object.
269 * @return WP_REST_Response
270 * @since 1.1.0
271 */
272 public function update_validation_settings( $request ) {
273 $current = Helper::get_suredonation_option( \SureDonation\Inc\Field_Validation::VALIDATION_MESSAGES_OPTION_KEY, [] );
274
275 if ( ! is_array( $current ) ) {
276 $current = [];
277 }
278
279 /**
280 * Filter the list of allowed validation-message keys.
281 *
282 * Lets extensions register additional message keys for their own field
283 * types, mirroring the `suredonation.settings.tab.validationFields` and
284 * `suredonation.settings.tab.requiredValidationFields` JS filters.
285 *
286 * @since 1.1.0
287 * @param array<int, string> $keys Allowed message keys.
288 */
289 $allowed_keys = apply_filters(
290 'suredonation_validation_message_keys',
291 array_keys( \SureDonation\Inc\Field_Validation::default_validation_messages() )
292 );
293
294 foreach ( $allowed_keys as $key ) {
295 if ( ! is_string( $key ) ) {
296 continue;
297 }
298
299 $value = $request->get_param( $key );
300 // Guard against non-scalar input (array/object) which would make
301 // sanitize_text_field() emit a warning / type error on PHP 8.1+.
302 if ( null !== $value && is_scalar( $value ) ) {
303 $current[ $key ] = sanitize_text_field( (string) $value );
304 }
305 }
306
307 Helper::update_suredonation_option( \SureDonation\Inc\Field_Validation::VALIDATION_MESSAGES_OPTION_KEY, $current );
308
309 return new WP_REST_Response(
310 [
311 'success' => true,
312 'message' => __( 'Form validation settings saved', 'suredonation' ),
313 ],
314 200
315 );
316 }
317
318 /**
319 * Get currency settings for block editor.
320 *
321 * Returns minimal currency data needed for frontend/block previews.
322 *
323 * @param WP_REST_Request $request Request object.
324 * @return WP_REST_Response Response object.
325 * @since 0.0.1
326 */
327 public function get_currency_settings( $request ) {
328 unset( $request ); // Unused parameter.
329
330 $currency = Payment_Helper::get_currency();
331
332 return new WP_REST_Response(
333 [
334 'currency' => $currency,
335 'currencySymbol' => Payment_Helper::get_currency_symbol( $currency ),
336 'isZeroDecimal' => Payment_Helper::is_zero_decimal_currency( $currency ),
337 ],
338 200
339 );
340 }
341
342 /**
343 * Get general settings.
344 *
345 * @param WP_REST_Request $request Request object.
346 * @return WP_REST_Response Response object.
347 * @since 0.0.1
348 */
349 public function get_settings( $request ) {
350 unset( $request ); // Unused parameter.
351
352 $settings = Payment_Helper::get_all_payment_settings();
353
354 return new WP_REST_Response(
355 [
356 'success' => true,
357 'settings' => [
358 'currency' => $settings['currency'] ?? 'USD',
359 'payment_mode' => $settings['payment_mode'] ?? 'test',
360 ],
361 ],
362 200
363 );
364 }
365
366 /**
367 * Update general settings.
368 *
369 * @param WP_REST_Request $request Request object.
370 * @return WP_REST_Response|WP_Error Response object.
371 * @since 0.0.1
372 */
373 public function update_settings( $request ) {
374 $params = $request->get_json_params();
375
376 if ( empty( $params ) ) {
377 return new WP_Error(
378 'invalid_settings',
379 __( 'Invalid settings provided', 'suredonation' ),
380 [ 'status' => 400 ]
381 );
382 }
383
384 $current_settings = Payment_Helper::get_all_payment_settings();
385
386 // Update currency if provided.
387 if ( isset( $params['currency'] ) ) {
388 $currency = strtoupper( sanitize_text_field( $params['currency'] ) );
389
390 // Validate currency.
391 $valid_currencies = array_keys( Payment_Helper::get_all_currencies_data() );
392 if ( in_array( $currency, $valid_currencies, true ) ) {
393 $current_settings['currency'] = $currency;
394 }
395 }
396
397 // Update payment mode if provided.
398 if ( isset( $params['payment_mode'] ) ) {
399 $mode = sanitize_text_field( $params['payment_mode'] );
400 if ( in_array( $mode, [ 'test', 'live' ], true ) ) {
401 $current_settings['payment_mode'] = $mode;
402 }
403 }
404
405 $success = Payment_Helper::update_all_payment_settings( $current_settings );
406
407 if ( ! $success ) {
408 return new WP_Error(
409 'update_failed',
410 __( 'Failed to update settings', 'suredonation' ),
411 [ 'status' => 500 ]
412 );
413 }
414
415 return new WP_REST_Response(
416 [
417 'success' => true,
418 'message' => __( 'Settings updated successfully', 'suredonation' ),
419 ],
420 200
421 );
422 }
423
424 /**
425 * Get available currencies.
426 *
427 * @param WP_REST_Request $request Request object.
428 * @return WP_REST_Response Response object.
429 * @since 0.0.1
430 */
431 public function get_currencies( $request ) {
432 unset( $request ); // Unused parameter.
433
434 return new WP_REST_Response(
435 [
436 'success' => true,
437 'currencies' => Payment_Helper::get_currencies_list(),
438 ],
439 200
440 );
441 }
442
443 /**
444 * Get AI settings.
445 *
446 * @param WP_REST_Request $request Request object.
447 * @return WP_REST_Response Response object.
448 * @since 1.0.0
449 */
450 public function get_ai_settings( $request ) {
451 unset( $request ); // Unused parameter.
452
453 $defaults = [
454 'enable_abilities' => false,
455 'allow_updates' => false,
456 'allow_delete' => false,
457 'mcp_server' => false,
458 ];
459 $settings = Helper::get_suredonation_option( self::AI_OPTION_KEY, [] );
460
461 return new WP_REST_Response(
462 [
463 'success' => true,
464 'settings' => wp_parse_args( is_array( $settings ) ? $settings : [], $defaults ),
465 ],
466 200
467 );
468 }
469
470 /**
471 * Update AI settings.
472 *
473 * @param WP_REST_Request $request Request object.
474 * @return WP_REST_Response Response object.
475 * @since 1.0.0
476 */
477 public function update_ai_settings( $request ) {
478 $params = $request->get_json_params();
479 $current = Helper::get_suredonation_option( self::AI_OPTION_KEY, [] );
480
481 if ( ! is_array( $current ) ) {
482 $current = [];
483 }
484
485 $allowed = [ 'enable_abilities', 'allow_updates', 'allow_delete', 'mcp_server' ];
486 foreach ( $allowed as $key ) {
487 if ( isset( $params[ $key ] ) ) {
488 $current[ $key ] = (bool) $params[ $key ];
489 }
490 }
491
492 Helper::update_suredonation_option( self::AI_OPTION_KEY, $current );
493
494 return new WP_REST_Response(
495 [
496 'success' => true,
497 'message' => __( 'AI settings saved', 'suredonation' ),
498 ],
499 200
500 );
501 }
502
503 /**
504 * Get spam protection settings.
505 *
506 * @param WP_REST_Request $request Request object.
507 * @return WP_REST_Response Response object.
508 * @since 1.1.0
509 */
510 public function get_spam_protection_settings( $request ) {
511 unset( $request ); // Unused parameter.
512
513 $defaults = [
514 'honeypot' => false,
515 ];
516 $settings = Helper::get_suredonation_option( self::SPAM_OPTION_KEY, [] );
517
518 return new WP_REST_Response(
519 [
520 'success' => true,
521 'settings' => wp_parse_args( is_array( $settings ) ? $settings : [], $defaults ),
522 ],
523 200
524 );
525 }
526
527 /**
528 * Update spam protection settings.
529 *
530 * @param WP_REST_Request $request Request object.
531 * @return WP_REST_Response Response object.
532 * @since 1.1.0
533 */
534 public function update_spam_protection_settings( $request ) {
535 $current = Helper::get_suredonation_option( self::SPAM_OPTION_KEY, [] );
536
537 if ( ! is_array( $current ) ) {
538 $current = [];
539 }
540
541 // Read each setting via get_param() so the endpoint accepts JSON, body,
542 // or query params (matches the sibling /settings/* update handlers).
543 $allowed = [ 'honeypot' ];
544 foreach ( $allowed as $key ) {
545 $value = $request->get_param( $key );
546 if ( null !== $value ) {
547 $current[ $key ] = (bool) $value;
548 }
549 }
550
551 Helper::update_suredonation_option( self::SPAM_OPTION_KEY, $current );
552
553 return new WP_REST_Response(
554 [
555 'success' => true,
556 'message' => __( 'Spam protection settings saved', 'suredonation' ),
557 ],
558 200
559 );
560 }
561
562 /**
563 * Get miscellaneous settings.
564 *
565 * @param WP_REST_Request $request Request object.
566 * @return WP_REST_Response Response object.
567 * @since 1.0.0
568 */
569 public function get_misc_settings( $request ) {
570 unset( $request ); // Unused parameter.
571
572 return new WP_REST_Response(
573 [
574 'success' => true,
575 'settings' => [
576 // Site option - the BSF Analytics library reads this via
577 // get_site_option(), so the toggle must use the same
578 // scope to stay in sync on multisite.
579 'usage_tracking' => 'yes' === get_site_option( 'suredonation_usage_optin', false ),
580 ],
581 ],
582 200
583 );
584 }
585
586 /**
587 * Update miscellaneous settings.
588 *
589 * Stores the usage-tracking opt-in as the standalone 'yes'/'no'
590 * suredonation_usage_optin option read by the BSF Analytics library.
591 *
592 * @param WP_REST_Request $request Request object.
593 * @return WP_REST_Response Response object.
594 * @since 1.0.0
595 */
596 public function update_misc_settings( $request ) {
597 $usage_tracking = $request->get_param( 'usage_tracking' );
598
599 if ( null !== $usage_tracking ) {
600 if ( $usage_tracking ) {
601 update_site_option( 'suredonation_usage_optin', 'yes' );
602 } else {
603 // Mirror the library's optout() side effects (see
604 // class-bsf-analytics.php) so the cross-product notice
605 // throttle and the send-check transient stay consistent.
606 update_site_option( 'suredonation_usage_optin', 'no' );
607 update_site_option( 'bsf_usage_last_displayed_time', time() );
608 delete_site_transient( 'bsf_usage_track' );
609 }
610 }
611
612 return new WP_REST_Response(
613 [
614 'success' => true,
615 'message' => __( 'Settings saved', 'suredonation' ),
616 ],
617 200
618 );
619 }
620
621 /**
622 * Get donor management settings.
623 *
624 * @param WP_REST_Request $request Request object.
625 * @return WP_REST_Response Response object.
626 * @since 1.0.0
627 */
628 public function get_donor_settings( $request ) {
629 unset( $request ); // Unused parameter.
630
631 $donor_settings = Helper::get_suredonation_option( self::DONOR_OPTION_KEY, [] );
632 if ( ! is_array( $donor_settings ) ) {
633 $donor_settings = [];
634 }
635
636 return new WP_REST_Response(
637 [
638 'success' => true,
639 'settings' => [
640 // Off by default: guest donations never auto-create WP user accounts.
641 'create_wp_user' => ! empty( $donor_settings['create_wp_user'] ),
642 ],
643 ],
644 200
645 );
646 }
647
648 /**
649 * Update donor management settings.
650 *
651 * @param WP_REST_Request $request Request object.
652 * @return WP_REST_Response Response object.
653 * @since 1.0.0
654 */
655 public function update_donor_settings( $request ) {
656 $create_wp_user = $request->get_param( 'create_wp_user' );
657
658 if ( null !== $create_wp_user ) {
659 $donor_settings = Helper::get_suredonation_option( self::DONOR_OPTION_KEY, [] );
660 if ( ! is_array( $donor_settings ) ) {
661 $donor_settings = [];
662 }
663
664 $donor_settings['create_wp_user'] = (bool) $create_wp_user;
665 Helper::update_suredonation_option( self::DONOR_OPTION_KEY, $donor_settings );
666 }
667
668 return new WP_REST_Response(
669 [
670 'success' => true,
671 'message' => __( 'Settings saved', 'suredonation' ),
672 ],
673 200
674 );
675 }
676
677 /**
678 * Check if user has permission to manage settings.
679 *
680 * @return bool True if user has permission.
681 * @since 0.0.1
682 */
683 public function check_permissions() {
684 return current_user_can( 'manage_options' );
685 }
686 }
687