PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / trunk
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management vtrunk
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 trunk, at inc/api/settings-api.php

696 lines 18.4 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 'currency_sign_position' => Payment_Helper::get_currency_sign_position(),
361 ],
362 ],
363 200
364 );
365 }
366
367 /**
368 * Update general settings.
369 *
370 * @param WP_REST_Request $request Request object.
371 * @return WP_REST_Response|WP_Error Response object.
372 * @since 0.0.1
373 */
374 public function update_settings( $request ) {
375 $params = $request->get_json_params();
376
377 if ( empty( $params ) ) {
378 return new WP_Error(
379 'invalid_settings',
380 __( 'Invalid settings provided', 'suredonation' ),
381 [ 'status' => 400 ]
382 );
383 }
384
385 $current_settings = Payment_Helper::get_all_payment_settings();
386
387 // Update currency if provided.
388 if ( isset( $params['currency'] ) ) {
389 $currency = strtoupper( sanitize_text_field( $params['currency'] ) );
390
391 // Validate currency.
392 $valid_currencies = array_keys( Payment_Helper::get_all_currencies_data() );
393 if ( in_array( $currency, $valid_currencies, true ) ) {
394 $current_settings['currency'] = $currency;
395 }
396 }
397
398 // Update payment mode if provided.
399 if ( isset( $params['payment_mode'] ) ) {
400 $mode = sanitize_text_field( $params['payment_mode'] );
401 if ( in_array( $mode, [ 'test', 'live' ], true ) ) {
402 $current_settings['payment_mode'] = $mode;
403 }
404 }
405
406 // Update currency sign position if provided.
407 if ( isset( $params['currency_sign_position'] ) ) {
408 $position = sanitize_text_field( $params['currency_sign_position'] );
409 if ( in_array( $position, Payment_Helper::ALLOWED_SIGN_POSITIONS, true ) ) {
410 $current_settings['currency_sign_position'] = $position;
411 }
412 }
413
414 $success = Payment_Helper::update_all_payment_settings( $current_settings );
415
416 if ( ! $success ) {
417 return new WP_Error(
418 'update_failed',
419 __( 'Failed to update settings', 'suredonation' ),
420 [ 'status' => 500 ]
421 );
422 }
423
424 return new WP_REST_Response(
425 [
426 'success' => true,
427 'message' => __( 'Settings updated successfully', 'suredonation' ),
428 ],
429 200
430 );
431 }
432
433 /**
434 * Get available currencies.
435 *
436 * @param WP_REST_Request $request Request object.
437 * @return WP_REST_Response Response object.
438 * @since 0.0.1
439 */
440 public function get_currencies( $request ) {
441 unset( $request ); // Unused parameter.
442
443 return new WP_REST_Response(
444 [
445 'success' => true,
446 'currencies' => Payment_Helper::get_currencies_list(),
447 ],
448 200
449 );
450 }
451
452 /**
453 * Get AI settings.
454 *
455 * @param WP_REST_Request $request Request object.
456 * @return WP_REST_Response Response object.
457 * @since 1.0.0
458 */
459 public function get_ai_settings( $request ) {
460 unset( $request ); // Unused parameter.
461
462 $defaults = [
463 'enable_abilities' => false,
464 'allow_updates' => false,
465 'allow_delete' => false,
466 'mcp_server' => false,
467 ];
468 $settings = Helper::get_suredonation_option( self::AI_OPTION_KEY, [] );
469
470 return new WP_REST_Response(
471 [
472 'success' => true,
473 'settings' => wp_parse_args( is_array( $settings ) ? $settings : [], $defaults ),
474 ],
475 200
476 );
477 }
478
479 /**
480 * Update AI settings.
481 *
482 * @param WP_REST_Request $request Request object.
483 * @return WP_REST_Response Response object.
484 * @since 1.0.0
485 */
486 public function update_ai_settings( $request ) {
487 $params = $request->get_json_params();
488 $current = Helper::get_suredonation_option( self::AI_OPTION_KEY, [] );
489
490 if ( ! is_array( $current ) ) {
491 $current = [];
492 }
493
494 $allowed = [ 'enable_abilities', 'allow_updates', 'allow_delete', 'mcp_server' ];
495 foreach ( $allowed as $key ) {
496 if ( isset( $params[ $key ] ) ) {
497 $current[ $key ] = (bool) $params[ $key ];
498 }
499 }
500
501 Helper::update_suredonation_option( self::AI_OPTION_KEY, $current );
502
503 return new WP_REST_Response(
504 [
505 'success' => true,
506 'message' => __( 'AI settings saved', 'suredonation' ),
507 ],
508 200
509 );
510 }
511
512 /**
513 * Get spam protection settings.
514 *
515 * @param WP_REST_Request $request Request object.
516 * @return WP_REST_Response Response object.
517 * @since 1.1.0
518 */
519 public function get_spam_protection_settings( $request ) {
520 unset( $request ); // Unused parameter.
521
522 $defaults = [
523 'honeypot' => false,
524 ];
525 $settings = Helper::get_suredonation_option( self::SPAM_OPTION_KEY, [] );
526
527 return new WP_REST_Response(
528 [
529 'success' => true,
530 'settings' => wp_parse_args( is_array( $settings ) ? $settings : [], $defaults ),
531 ],
532 200
533 );
534 }
535
536 /**
537 * Update spam protection settings.
538 *
539 * @param WP_REST_Request $request Request object.
540 * @return WP_REST_Response Response object.
541 * @since 1.1.0
542 */
543 public function update_spam_protection_settings( $request ) {
544 $current = Helper::get_suredonation_option( self::SPAM_OPTION_KEY, [] );
545
546 if ( ! is_array( $current ) ) {
547 $current = [];
548 }
549
550 // Read each setting via get_param() so the endpoint accepts JSON, body,
551 // or query params (matches the sibling /settings/* update handlers).
552 $allowed = [ 'honeypot' ];
553 foreach ( $allowed as $key ) {
554 $value = $request->get_param( $key );
555 if ( null !== $value ) {
556 $current[ $key ] = (bool) $value;
557 }
558 }
559
560 Helper::update_suredonation_option( self::SPAM_OPTION_KEY, $current );
561
562 return new WP_REST_Response(
563 [
564 'success' => true,
565 'message' => __( 'Spam protection settings saved', 'suredonation' ),
566 ],
567 200
568 );
569 }
570
571 /**
572 * Get miscellaneous settings.
573 *
574 * @param WP_REST_Request $request Request object.
575 * @return WP_REST_Response Response object.
576 * @since 1.0.0
577 */
578 public function get_misc_settings( $request ) {
579 unset( $request ); // Unused parameter.
580
581 return new WP_REST_Response(
582 [
583 'success' => true,
584 'settings' => [
585 // Site option - the BSF Analytics library reads this via
586 // get_site_option(), so the toggle must use the same
587 // scope to stay in sync on multisite.
588 'usage_tracking' => 'yes' === get_site_option( 'suredonation_usage_optin', false ),
589 ],
590 ],
591 200
592 );
593 }
594
595 /**
596 * Update miscellaneous settings.
597 *
598 * Stores the usage-tracking opt-in as the standalone 'yes'/'no'
599 * suredonation_usage_optin option read by the BSF Analytics library.
600 *
601 * @param WP_REST_Request $request Request object.
602 * @return WP_REST_Response Response object.
603 * @since 1.0.0
604 */
605 public function update_misc_settings( $request ) {
606 $usage_tracking = $request->get_param( 'usage_tracking' );
607
608 if ( null !== $usage_tracking ) {
609 if ( $usage_tracking ) {
610 update_site_option( 'suredonation_usage_optin', 'yes' );
611 } else {
612 // Mirror the library's optout() side effects (see
613 // class-bsf-analytics.php) so the cross-product notice
614 // throttle and the send-check transient stay consistent.
615 update_site_option( 'suredonation_usage_optin', 'no' );
616 update_site_option( 'bsf_usage_last_displayed_time', time() );
617 delete_site_transient( 'bsf_usage_track' );
618 }
619 }
620
621 return new WP_REST_Response(
622 [
623 'success' => true,
624 'message' => __( 'Settings saved', 'suredonation' ),
625 ],
626 200
627 );
628 }
629
630 /**
631 * Get donor management settings.
632 *
633 * @param WP_REST_Request $request Request object.
634 * @return WP_REST_Response Response object.
635 * @since 1.0.0
636 */
637 public function get_donor_settings( $request ) {
638 unset( $request ); // Unused parameter.
639
640 $donor_settings = Helper::get_suredonation_option( self::DONOR_OPTION_KEY, [] );
641 if ( ! is_array( $donor_settings ) ) {
642 $donor_settings = [];
643 }
644
645 return new WP_REST_Response(
646 [
647 'success' => true,
648 'settings' => [
649 // Off by default: guest donations never auto-create WP user accounts.
650 'create_wp_user' => ! empty( $donor_settings['create_wp_user'] ),
651 ],
652 ],
653 200
654 );
655 }
656
657 /**
658 * Update donor management settings.
659 *
660 * @param WP_REST_Request $request Request object.
661 * @return WP_REST_Response Response object.
662 * @since 1.0.0
663 */
664 public function update_donor_settings( $request ) {
665 $create_wp_user = $request->get_param( 'create_wp_user' );
666
667 if ( null !== $create_wp_user ) {
668 $donor_settings = Helper::get_suredonation_option( self::DONOR_OPTION_KEY, [] );
669 if ( ! is_array( $donor_settings ) ) {
670 $donor_settings = [];
671 }
672
673 $donor_settings['create_wp_user'] = (bool) $create_wp_user;
674 Helper::update_suredonation_option( self::DONOR_OPTION_KEY, $donor_settings );
675 }
676
677 return new WP_REST_Response(
678 [
679 'success' => true,
680 'message' => __( 'Settings saved', 'suredonation' ),
681 ],
682 200
683 );
684 }
685
686 /**
687 * Check if user has permission to manage settings.
688 *
689 * @return bool True if user has permission.
690 * @since 0.0.1
691 */
692 public function check_permissions() {
693 return current_user_can( 'manage_options' );
694 }
695 }
696