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

632 lines 16.5 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 // Send test email.
177 '/settings/email/test' => [
178 'methods' => WP_REST_Server::CREATABLE,
179 'callback' => [ $this, 'send_test_email' ],
180 'permission_callback' => [ $this, 'check_permissions' ],
181 ],
182 ];
183 }
184
185 /**
186 * Get the form-validation default messages.
187 *
188 * Returns the stored admin overrides merged over the translatable defaults
189 * so every configurable message always has a value in the editor.
190 *
191 * @param WP_REST_Request $request Request object.
192 * @return WP_REST_Response
193 * @since 1.1.0
194 */
195 public function get_validation_settings( $request ) {
196 unset( $request ); // Unused parameter.
197
198 $defaults = \SureDonation\Inc\Field_Validation::default_validation_messages();
199 $stored = Helper::get_suredonation_option( \SureDonation\Inc\Field_Validation::VALIDATION_MESSAGES_OPTION_KEY, [] );
200
201 return new WP_REST_Response(
202 [
203 'success' => true,
204 'settings' => wp_parse_args( is_array( $stored ) ? $stored : [], $defaults ),
205 ],
206 200
207 );
208 }
209
210 /**
211 * Update the form-validation default messages.
212 *
213 * @param WP_REST_Request $request Request object.
214 * @return WP_REST_Response
215 * @since 1.1.0
216 */
217 public function update_validation_settings( $request ) {
218 $current = Helper::get_suredonation_option( \SureDonation\Inc\Field_Validation::VALIDATION_MESSAGES_OPTION_KEY, [] );
219
220 if ( ! is_array( $current ) ) {
221 $current = [];
222 }
223
224 /**
225 * Filter the list of allowed validation-message keys.
226 *
227 * Lets extensions register additional message keys for their own field
228 * types, mirroring the `suredonation.settings.tab.validationFields` and
229 * `suredonation.settings.tab.requiredValidationFields` JS filters.
230 *
231 * @since 1.1.0
232 * @param array<int, string> $keys Allowed message keys.
233 */
234 $allowed_keys = apply_filters(
235 'suredonation_validation_message_keys',
236 array_keys( \SureDonation\Inc\Field_Validation::default_validation_messages() )
237 );
238
239 foreach ( $allowed_keys as $key ) {
240 if ( ! is_string( $key ) ) {
241 continue;
242 }
243
244 $value = $request->get_param( $key );
245 // Guard against non-scalar input (array/object) which would make
246 // sanitize_text_field() emit a warning / type error on PHP 8.1+.
247 if ( null !== $value && is_scalar( $value ) ) {
248 $current[ $key ] = sanitize_text_field( (string) $value );
249 }
250 }
251
252 Helper::update_suredonation_option( \SureDonation\Inc\Field_Validation::VALIDATION_MESSAGES_OPTION_KEY, $current );
253
254 return new WP_REST_Response(
255 [
256 'success' => true,
257 'message' => __( 'Form validation settings saved', 'suredonation' ),
258 ],
259 200
260 );
261 }
262
263 /**
264 * Get currency settings for block editor.
265 *
266 * Returns minimal currency data needed for frontend/block previews.
267 *
268 * @param WP_REST_Request $request Request object.
269 * @return WP_REST_Response Response object.
270 * @since 0.0.1
271 */
272 public function get_currency_settings( $request ) {
273 unset( $request ); // Unused parameter.
274
275 $currency = Payment_Helper::get_currency();
276
277 return new WP_REST_Response(
278 [
279 'currency' => $currency,
280 'currencySymbol' => Payment_Helper::get_currency_symbol( $currency ),
281 'isZeroDecimal' => Payment_Helper::is_zero_decimal_currency( $currency ),
282 ],
283 200
284 );
285 }
286
287 /**
288 * Get general settings.
289 *
290 * @param WP_REST_Request $request Request object.
291 * @return WP_REST_Response Response object.
292 * @since 0.0.1
293 */
294 public function get_settings( $request ) {
295 unset( $request ); // Unused parameter.
296
297 $settings = Payment_Helper::get_all_payment_settings();
298
299 return new WP_REST_Response(
300 [
301 'success' => true,
302 'settings' => [
303 'currency' => $settings['currency'] ?? 'USD',
304 'payment_mode' => $settings['payment_mode'] ?? 'test',
305 ],
306 ],
307 200
308 );
309 }
310
311 /**
312 * Update general settings.
313 *
314 * @param WP_REST_Request $request Request object.
315 * @return WP_REST_Response|WP_Error Response object.
316 * @since 0.0.1
317 */
318 public function update_settings( $request ) {
319 $params = $request->get_json_params();
320
321 if ( empty( $params ) ) {
322 return new WP_Error(
323 'invalid_settings',
324 __( 'Invalid settings provided', 'suredonation' ),
325 [ 'status' => 400 ]
326 );
327 }
328
329 $current_settings = Payment_Helper::get_all_payment_settings();
330
331 // Update currency if provided.
332 if ( isset( $params['currency'] ) ) {
333 $currency = strtoupper( sanitize_text_field( $params['currency'] ) );
334
335 // Validate currency.
336 $valid_currencies = array_keys( Payment_Helper::get_all_currencies_data() );
337 if ( in_array( $currency, $valid_currencies, true ) ) {
338 $current_settings['currency'] = $currency;
339 }
340 }
341
342 // Update payment mode if provided.
343 if ( isset( $params['payment_mode'] ) ) {
344 $mode = sanitize_text_field( $params['payment_mode'] );
345 if ( in_array( $mode, [ 'test', 'live' ], true ) ) {
346 $current_settings['payment_mode'] = $mode;
347 }
348 }
349
350 $success = Payment_Helper::update_all_payment_settings( $current_settings );
351
352 if ( ! $success ) {
353 return new WP_Error(
354 'update_failed',
355 __( 'Failed to update settings', 'suredonation' ),
356 [ 'status' => 500 ]
357 );
358 }
359
360 return new WP_REST_Response(
361 [
362 'success' => true,
363 'message' => __( 'Settings updated successfully', 'suredonation' ),
364 ],
365 200
366 );
367 }
368
369 /**
370 * Get available currencies.
371 *
372 * @param WP_REST_Request $request Request object.
373 * @return WP_REST_Response Response object.
374 * @since 0.0.1
375 */
376 public function get_currencies( $request ) {
377 unset( $request ); // Unused parameter.
378
379 return new WP_REST_Response(
380 [
381 'success' => true,
382 'currencies' => Payment_Helper::get_currencies_list(),
383 ],
384 200
385 );
386 }
387
388 /**
389 * Get AI settings.
390 *
391 * @param WP_REST_Request $request Request object.
392 * @return WP_REST_Response Response object.
393 * @since 1.0.0
394 */
395 public function get_ai_settings( $request ) {
396 unset( $request ); // Unused parameter.
397
398 $defaults = [
399 'enable_abilities' => false,
400 'allow_updates' => false,
401 'allow_delete' => false,
402 'mcp_server' => false,
403 ];
404 $settings = Helper::get_suredonation_option( self::AI_OPTION_KEY, [] );
405
406 return new WP_REST_Response(
407 [
408 'success' => true,
409 'settings' => wp_parse_args( is_array( $settings ) ? $settings : [], $defaults ),
410 ],
411 200
412 );
413 }
414
415 /**
416 * Update AI settings.
417 *
418 * @param WP_REST_Request $request Request object.
419 * @return WP_REST_Response Response object.
420 * @since 1.0.0
421 */
422 public function update_ai_settings( $request ) {
423 $params = $request->get_json_params();
424 $current = Helper::get_suredonation_option( self::AI_OPTION_KEY, [] );
425
426 if ( ! is_array( $current ) ) {
427 $current = [];
428 }
429
430 $allowed = [ 'enable_abilities', 'allow_updates', 'allow_delete', 'mcp_server' ];
431 foreach ( $allowed as $key ) {
432 if ( isset( $params[ $key ] ) ) {
433 $current[ $key ] = (bool) $params[ $key ];
434 }
435 }
436
437 Helper::update_suredonation_option( self::AI_OPTION_KEY, $current );
438
439 return new WP_REST_Response(
440 [
441 'success' => true,
442 'message' => __( 'AI settings saved', 'suredonation' ),
443 ],
444 200
445 );
446 }
447
448 /**
449 * Get spam protection settings.
450 *
451 * @param WP_REST_Request $request Request object.
452 * @return WP_REST_Response Response object.
453 * @since 1.1.0
454 */
455 public function get_spam_protection_settings( $request ) {
456 unset( $request ); // Unused parameter.
457
458 $defaults = [
459 'honeypot' => false,
460 ];
461 $settings = Helper::get_suredonation_option( self::SPAM_OPTION_KEY, [] );
462
463 return new WP_REST_Response(
464 [
465 'success' => true,
466 'settings' => wp_parse_args( is_array( $settings ) ? $settings : [], $defaults ),
467 ],
468 200
469 );
470 }
471
472 /**
473 * Update spam protection settings.
474 *
475 * @param WP_REST_Request $request Request object.
476 * @return WP_REST_Response Response object.
477 * @since 1.1.0
478 */
479 public function update_spam_protection_settings( $request ) {
480 $current = Helper::get_suredonation_option( self::SPAM_OPTION_KEY, [] );
481
482 if ( ! is_array( $current ) ) {
483 $current = [];
484 }
485
486 // Read each setting via get_param() so the endpoint accepts JSON, body,
487 // or query params (matches the sibling /settings/* update handlers).
488 $allowed = [ 'honeypot' ];
489 foreach ( $allowed as $key ) {
490 $value = $request->get_param( $key );
491 if ( null !== $value ) {
492 $current[ $key ] = (bool) $value;
493 }
494 }
495
496 Helper::update_suredonation_option( self::SPAM_OPTION_KEY, $current );
497
498 return new WP_REST_Response(
499 [
500 'success' => true,
501 'message' => __( 'Spam protection settings saved', 'suredonation' ),
502 ],
503 200
504 );
505 }
506
507 /**
508 * Get miscellaneous settings.
509 *
510 * @param WP_REST_Request $request Request object.
511 * @return WP_REST_Response Response object.
512 * @since 1.0.0
513 */
514 public function get_misc_settings( $request ) {
515 unset( $request ); // Unused parameter.
516
517 return new WP_REST_Response(
518 [
519 'success' => true,
520 'settings' => [
521 // Site option - the BSF Analytics library reads this via
522 // get_site_option(), so the toggle must use the same
523 // scope to stay in sync on multisite.
524 'usage_tracking' => 'yes' === get_site_option( 'suredonation_usage_optin', false ),
525 ],
526 ],
527 200
528 );
529 }
530
531 /**
532 * Update miscellaneous settings.
533 *
534 * Stores the usage-tracking opt-in as the standalone 'yes'/'no'
535 * suredonation_usage_optin option read by the BSF Analytics library.
536 *
537 * @param WP_REST_Request $request Request object.
538 * @return WP_REST_Response Response object.
539 * @since 1.0.0
540 */
541 public function update_misc_settings( $request ) {
542 $usage_tracking = $request->get_param( 'usage_tracking' );
543
544 if ( null !== $usage_tracking ) {
545 if ( $usage_tracking ) {
546 update_site_option( 'suredonation_usage_optin', 'yes' );
547 } else {
548 // Mirror the library's optout() side effects (see
549 // class-bsf-analytics.php) so the cross-product notice
550 // throttle and the send-check transient stay consistent.
551 update_site_option( 'suredonation_usage_optin', 'no' );
552 update_site_option( 'bsf_usage_last_displayed_time', time() );
553 delete_site_transient( 'bsf_usage_track' );
554 }
555 }
556
557 return new WP_REST_Response(
558 [
559 'success' => true,
560 'message' => __( 'Settings saved', 'suredonation' ),
561 ],
562 200
563 );
564 }
565
566 /**
567 * Get donor management settings.
568 *
569 * @param WP_REST_Request $request Request object.
570 * @return WP_REST_Response Response object.
571 * @since 1.0.0
572 */
573 public function get_donor_settings( $request ) {
574 unset( $request ); // Unused parameter.
575
576 $donor_settings = Helper::get_suredonation_option( self::DONOR_OPTION_KEY, [] );
577 if ( ! is_array( $donor_settings ) ) {
578 $donor_settings = [];
579 }
580
581 return new WP_REST_Response(
582 [
583 'success' => true,
584 'settings' => [
585 // Off by default: guest donations never auto-create WP user accounts.
586 'create_wp_user' => ! empty( $donor_settings['create_wp_user'] ),
587 ],
588 ],
589 200
590 );
591 }
592
593 /**
594 * Update donor management settings.
595 *
596 * @param WP_REST_Request $request Request object.
597 * @return WP_REST_Response Response object.
598 * @since 1.0.0
599 */
600 public function update_donor_settings( $request ) {
601 $create_wp_user = $request->get_param( 'create_wp_user' );
602
603 if ( null !== $create_wp_user ) {
604 $donor_settings = Helper::get_suredonation_option( self::DONOR_OPTION_KEY, [] );
605 if ( ! is_array( $donor_settings ) ) {
606 $donor_settings = [];
607 }
608
609 $donor_settings['create_wp_user'] = (bool) $create_wp_user;
610 Helper::update_suredonation_option( self::DONOR_OPTION_KEY, $donor_settings );
611 }
612
613 return new WP_REST_Response(
614 [
615 'success' => true,
616 'message' => __( 'Settings saved', 'suredonation' ),
617 ],
618 200
619 );
620 }
621
622 /**
623 * Check if user has permission to manage settings.
624 *
625 * @return bool True if user has permission.
626 * @since 0.0.1
627 */
628 public function check_permissions() {
629 return current_user_can( 'manage_options' );
630 }
631 }
632