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

588 lines 18.1 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\Emails\Email_Template;
11 use SureDonation\Inc\Helper;
12 use SureDonation\Inc\Payments\Payment_Helper;
13 use WP_Error;
14 use WP_REST_Request;
15 use WP_REST_Response;
16 use WP_REST_Server;
17
18 // Exit if accessed directly.
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 /**
24 * Settings API class.
25 *
26 * @since 0.0.1
27 */
28 class Settings_API {
29 /**
30 * Option key for email notifications within consolidated options.
31 *
32 * @since 0.0.1
33 */
34 public const EMAIL_OPTION_KEY = 'email_notifications';
35
36 /**
37 * Get settings endpoints.
38 *
39 * @return array<string, mixed>
40 * @since 0.0.1
41 */
42 public function get_endpoints() {
43 return [
44 // Get currency data for block editor (public endpoint).
45 '/settings' => [
46 'methods' => WP_REST_Server::READABLE,
47 'callback' => [ $this, 'get_currency_settings' ],
48 'permission_callback' => '__return_true',
49 ],
50
51 // Get and update general settings.
52 '/settings/general' => [
53 [
54 'methods' => WP_REST_Server::READABLE,
55 'callback' => [ $this, 'get_settings' ],
56 'permission_callback' => [ $this, 'check_permissions' ],
57 ],
58 [
59 'methods' => WP_REST_Server::EDITABLE,
60 'callback' => [ $this, 'update_settings' ],
61 'permission_callback' => [ $this, 'check_permissions' ],
62 ],
63 ],
64
65 // Get available currencies.
66 '/settings/currencies' => [
67 'methods' => WP_REST_Server::READABLE,
68 'callback' => [ $this, 'get_currencies' ],
69 'permission_callback' => [ $this, 'check_permissions' ],
70 ],
71
72 // Email settings.
73 '/settings/email' => [
74 [
75 'methods' => WP_REST_Server::READABLE,
76 'callback' => [ $this, 'get_email_settings' ],
77 'permission_callback' => [ $this, 'check_permissions' ],
78 ],
79 [
80 'methods' => WP_REST_Server::EDITABLE,
81 'callback' => [ $this, 'update_email_settings' ],
82 'permission_callback' => [ $this, 'check_permissions' ],
83 ],
84 ],
85
86 // Send test email.
87 '/settings/email/test' => [
88 'methods' => WP_REST_Server::CREATABLE,
89 'callback' => [ $this, 'send_test_email' ],
90 'permission_callback' => [ $this, 'check_permissions' ],
91 ],
92 ];
93 }
94
95 /**
96 * Get currency settings for block editor.
97 *
98 * Returns minimal currency data needed for frontend/block previews.
99 *
100 * @param WP_REST_Request $request Request object.
101 * @return WP_REST_Response Response object.
102 * @since 0.0.1
103 */
104 public function get_currency_settings( $request ) {
105 unset( $request ); // Unused parameter.
106
107 $currency = Payment_Helper::get_currency();
108
109 return new WP_REST_Response(
110 [
111 'currency' => $currency,
112 'currencySymbol' => Payment_Helper::get_currency_symbol( $currency ),
113 'isZeroDecimal' => Payment_Helper::is_zero_decimal_currency( $currency ),
114 ],
115 200
116 );
117 }
118
119 /**
120 * Get general settings.
121 *
122 * @param WP_REST_Request $request Request object.
123 * @return WP_REST_Response Response object.
124 * @since 0.0.1
125 */
126 public function get_settings( $request ) {
127 unset( $request ); // Unused parameter.
128
129 $settings = Payment_Helper::get_all_payment_settings();
130
131 return new WP_REST_Response(
132 [
133 'success' => true,
134 'settings' => [
135 'currency' => $settings['currency'] ?? 'USD',
136 'payment_mode' => $settings['payment_mode'] ?? 'test',
137 ],
138 ],
139 200
140 );
141 }
142
143 /**
144 * Update general settings.
145 *
146 * @param WP_REST_Request $request Request object.
147 * @return WP_REST_Response|WP_Error Response object.
148 * @since 0.0.1
149 */
150 public function update_settings( $request ) {
151 $params = $request->get_json_params();
152
153 if ( empty( $params ) ) {
154 return new WP_Error(
155 'invalid_settings',
156 __( 'Invalid settings provided', 'suredonation' ),
157 [ 'status' => 400 ]
158 );
159 }
160
161 $current_settings = Payment_Helper::get_all_payment_settings();
162
163 // Update currency if provided.
164 if ( isset( $params['currency'] ) ) {
165 $currency = strtoupper( sanitize_text_field( $params['currency'] ) );
166
167 // Validate currency.
168 $valid_currencies = array_keys( Payment_Helper::get_all_currencies_data() );
169 if ( in_array( $currency, $valid_currencies, true ) ) {
170 $current_settings['currency'] = $currency;
171 }
172 }
173
174 // Update payment mode if provided.
175 if ( isset( $params['payment_mode'] ) ) {
176 $mode = sanitize_text_field( $params['payment_mode'] );
177 if ( in_array( $mode, [ 'test', 'live' ], true ) ) {
178 $current_settings['payment_mode'] = $mode;
179 }
180 }
181
182 $success = Payment_Helper::update_all_payment_settings( $current_settings );
183
184 if ( ! $success ) {
185 return new WP_Error(
186 'update_failed',
187 __( 'Failed to update settings', 'suredonation' ),
188 [ 'status' => 500 ]
189 );
190 }
191
192 return new WP_REST_Response(
193 [
194 'success' => true,
195 'message' => __( 'Settings updated successfully', 'suredonation' ),
196 ],
197 200
198 );
199 }
200
201 /**
202 * Get available currencies.
203 *
204 * @param WP_REST_Request $request Request object.
205 * @return WP_REST_Response Response object.
206 * @since 0.0.1
207 */
208 public function get_currencies( $request ) {
209 unset( $request ); // Unused parameter.
210
211 $currencies_data = Payment_Helper::get_all_currencies_data();
212
213 // Format for frontend: "CODE - Name".
214 $currencies = [];
215 foreach ( $currencies_data as $code => $data ) {
216 $currencies[ $code ] = $code . ' - ' . $data['name'];
217 }
218
219 return new WP_REST_Response(
220 [
221 'success' => true,
222 'currencies' => $currencies,
223 ],
224 200
225 );
226 }
227
228 /**
229 * Get email settings.
230 *
231 * @param WP_REST_Request $request Request object.
232 * @return WP_REST_Response Response object.
233 * @since 0.0.1
234 */
235 public function get_email_settings( $request ) {
236 unset( $request ); // Unused parameter.
237
238 $saved_notifications = Helper::get_array_value( Helper::get_suredonation_option( self::EMAIL_OPTION_KEY, [] ) );
239 $default_notifications = $this->get_default_notifications();
240
241 // Merge saved settings with defaults.
242 $notifications = [];
243 foreach ( $default_notifications as $key => $default ) {
244 $saved_value = isset( $saved_notifications[ $key ] ) && is_array( $saved_notifications[ $key ] ) ? $saved_notifications[ $key ] : [];
245 $notifications[ $key ] = wp_parse_args(
246 $saved_value,
247 $default
248 );
249 }
250
251 return new WP_REST_Response(
252 [
253 'success' => true,
254 'notifications' => $notifications,
255 ],
256 200
257 );
258 }
259
260 /**
261 * Update email settings.
262 *
263 * @param WP_REST_Request $request Request object.
264 * @return WP_REST_Response|WP_Error Response object.
265 * @since 0.0.1
266 */
267 public function update_email_settings( $request ) {
268 $params = $request->get_json_params();
269
270 if ( empty( $params ) || ! isset( $params['notifications'] ) ) {
271 return new WP_Error(
272 'invalid_settings',
273 __( 'Invalid settings provided', 'suredonation' ),
274 [ 'status' => 400 ]
275 );
276 }
277
278 $current_notifications = Helper::get_array_value( Helper::get_suredonation_option( self::EMAIL_OPTION_KEY, [] ) );
279 $valid_keys = array_keys( $this->get_default_notifications() );
280
281 foreach ( $params['notifications'] as $key => $notification ) {
282 // Only allow known notification types.
283 if ( ! in_array( $key, $valid_keys, true ) ) {
284 continue;
285 }
286
287 $current_notifications[ $key ] = [
288 'enabled' => isset( $notification['enabled'] ) ? (bool) $notification['enabled'] : false,
289 'subject' => isset( $notification['subject'] ) ? sanitize_text_field( $notification['subject'] ) : '',
290 'from_name' => isset( $notification['from_name'] ) ? sanitize_text_field( $notification['from_name'] ) : '',
291 'from_email' => isset( $notification['from_email'] ) ? sanitize_email( $notification['from_email'] ) : '',
292 'reply_to' => isset( $notification['reply_to'] ) ? sanitize_email( $notification['reply_to'] ) : '',
293 'email_body' => isset( $notification['email_body'] ) ? wp_kses_post( $notification['email_body'] ) : '',
294 ];
295 }
296
297 Helper::update_suredonation_option( self::EMAIL_OPTION_KEY, $current_notifications );
298
299 return new WP_REST_Response(
300 [
301 'success' => true,
302 'message' => __( 'Email settings saved', 'suredonation' ),
303 ],
304 200
305 );
306 }
307
308 /**
309 * Send a test email.
310 *
311 * @param WP_REST_Request $request Request object.
312 * @return WP_REST_Response|WP_Error Response object.
313 * @since 0.0.1
314 */
315 public function send_test_email( $request ) {
316 $params = $request->get_json_params();
317
318 if ( empty( $params['notification_id'] ) ) {
319 return new WP_Error(
320 'missing_notification_id',
321 __( 'Notification ID is required', 'suredonation' ),
322 [ 'status' => 400 ]
323 );
324 }
325
326 $notification_id = sanitize_text_field( $params['notification_id'] );
327 $admin_email = get_option( 'admin_email' );
328 $test_email = ! empty( $params['test_email'] ) ? sanitize_email( $params['test_email'] ) : ( is_string( $admin_email ) ? $admin_email : '' );
329
330 if ( ! is_email( $test_email ) ) {
331 return new WP_Error(
332 'invalid_email',
333 __( 'Invalid email address', 'suredonation' ),
334 [ 'status' => 400 ]
335 );
336 }
337
338 // Get notification settings.
339 $saved_notifications = Helper::get_array_value( Helper::get_suredonation_option( self::EMAIL_OPTION_KEY, [] ) );
340 $default_notifications = $this->get_default_notifications();
341
342 if ( ! isset( $default_notifications[ $notification_id ] ) ) {
343 return new WP_Error(
344 'invalid_notification',
345 __( 'Invalid notification type', 'suredonation' ),
346 [ 'status' => 400 ]
347 );
348 }
349
350 $saved_notification_value = isset( $saved_notifications[ $notification_id ] ) && is_array( $saved_notifications[ $notification_id ] ) ? $saved_notifications[ $notification_id ] : [];
351 $notification = wp_parse_args(
352 $saved_notification_value,
353 $default_notifications[ $notification_id ]
354 );
355
356 // Use current form data if provided (for preview before save).
357 if ( ! empty( $params['notification_data'] ) && is_array( $params['notification_data'] ) ) {
358 $raw = $params['notification_data'];
359 $sanitized_data = [];
360 if ( isset( $raw['subject'] ) ) {
361 $sanitized_data['subject'] = sanitize_text_field( $raw['subject'] );
362 }
363 if ( isset( $raw['from_name'] ) ) {
364 $sanitized_data['from_name'] = sanitize_text_field( $raw['from_name'] );
365 }
366 if ( isset( $raw['from_email'] ) ) {
367 $sanitized_data['from_email'] = sanitize_email( $raw['from_email'] );
368 }
369 if ( isset( $raw['reply_to'] ) ) {
370 $sanitized_data['reply_to'] = sanitize_email( $raw['reply_to'] );
371 }
372 if ( isset( $raw['email_body'] ) ) {
373 $sanitized_data['email_body'] = wp_kses_post( $raw['email_body'] );
374 }
375 if ( isset( $raw['enabled'] ) ) {
376 $sanitized_data['enabled'] = (bool) $raw['enabled'];
377 }
378 $notification = wp_parse_args( $sanitized_data, $notification );
379 }
380
381 // Create sample donation data for smart tags.
382 $sample_data = $this->get_sample_donation_data();
383
384 // Process smart tags.
385 $subject = $this->process_test_smart_tags( $notification['subject'] ?? '', $sample_data );
386 $email_body = $this->process_test_smart_tags( $notification['email_body'] ?? '', $sample_data );
387
388 // Get from name and email.
389 $from_name = ! empty( $notification['from_name'] ) ? $notification['from_name'] : get_bloginfo( 'name' );
390 $from_email = ! empty( $notification['from_email'] ) ? $notification['from_email'] : get_option( 'admin_email' );
391 $reply_to = ! empty( $notification['reply_to'] ) ? $notification['reply_to'] : $from_email;
392
393 // Process smart tags in from name.
394 $from_name = $this->process_test_smart_tags( $from_name, $sample_data );
395
396 // Set email headers.
397 $headers = [
398 'Content-Type: text/html; charset=UTF-8',
399 sprintf( 'From: %s <%s>', $from_name, $from_email ),
400 sprintf( 'Reply-To: %s', $reply_to ),
401 ];
402
403 // Format email body with HTML wrapper.
404 $email_body = $this->format_test_email_body( $email_body );
405
406 // Send email.
407 $sent = wp_mail( $test_email, $subject, $email_body, $headers );
408
409 if ( ! $sent ) {
410 return new WP_Error(
411 'email_failed',
412 __( 'Failed to send test email. Please check your email configuration.', 'suredonation' ),
413 [ 'status' => 500 ]
414 );
415 }
416
417 return new WP_REST_Response(
418 [
419 'success' => true,
420 'message' => sprintf(
421 /* translators: %s: email address */
422 __( 'Test email sent to %s', 'suredonation' ),
423 $test_email
424 ),
425 ],
426 200
427 );
428 }
429
430 /**
431 * Check if user has permission to manage settings.
432 *
433 * @return bool True if user has permission.
434 * @since 0.0.1
435 */
436 public function check_permissions() {
437 return current_user_can( 'manage_options' );
438 }
439
440 /**
441 * Get default notification configurations.
442 *
443 * @return array<string, array<string, mixed>> Default notifications.
444 * @since 0.0.1
445 */
446 private function get_default_notifications() {
447 return [
448 'donation_receipt' => [
449 'id' => 'donation_receipt',
450 'name' => __( 'Donation Receipt', 'suredonation' ),
451 'description' => __( 'Sent to donor after a successful donation.', 'suredonation' ),
452 'recipient' => 'donor',
453 'enabled' => true,
454 'subject' => __( 'Thank you for your donation!', 'suredonation' ),
455 'from_name' => '',
456 'from_email' => '',
457 'reply_to' => '',
458 'email_body' => $this->get_donation_receipt_body(),
459 ],
460 'admin_new_donation' => [
461 'id' => 'admin_new_donation',
462 'name' => __( 'New Donation (Admin)', 'suredonation' ),
463 'description' => __( 'Sent to admin when a new donation is received.', 'suredonation' ),
464 'recipient' => 'admin',
465 'enabled' => true,
466 'subject' => __( 'New donation received!', 'suredonation' ),
467 'from_name' => '',
468 'from_email' => '',
469 'reply_to' => '',
470 'email_body' => $this->get_admin_new_donation_body(),
471 ],
472 ];
473 }
474
475 /**
476 * Get donation receipt email body.
477 *
478 * @return string Email body in HTML format.
479 * @since 0.0.1
480 */
481 private function get_donation_receipt_body() {
482 ob_start();
483 ?>
484 <p><strong><span style="font-size: 18px;"><?php esc_html_e( 'Thank You for Your Donation!', 'suredonation' ); ?></span></strong></p>
485 <p><?php esc_html_e( 'Dear', 'suredonation' ); ?> {donor_name},</p>
486 <p><?php esc_html_e( 'Thank you for your generous donation of', 'suredonation' ); ?> <strong>{amount}</strong> <?php esc_html_e( 'to', 'suredonation' ); ?> <strong>{campaign_name}</strong>.</p>
487 <p><?php esc_html_e( 'Your support means the world to us and helps us continue our mission.', 'suredonation' ); ?></p>
488 <p><strong><?php esc_html_e( 'Donation Details:', 'suredonation' ); ?></strong></p>
489 <ul>
490 <li><?php esc_html_e( 'Amount:', 'suredonation' ); ?> {amount}</li>
491 <li><?php esc_html_e( 'Campaign:', 'suredonation' ); ?> {campaign_name}</li>
492 <li><?php esc_html_e( 'Date:', 'suredonation' ); ?> {donation_date}</li>
493 <li><?php esc_html_e( 'Transaction ID:', 'suredonation' ); ?> {transaction_id}</li>
494 </ul>
495 <p><?php esc_html_e( 'Best regards,', 'suredonation' ); ?><br />{site_title}</p>
496 <?php
497 $output = ob_get_clean();
498 return trim( false !== $output ? $output : '' );
499 }
500
501 /**
502 * Get admin new donation email body.
503 *
504 * @return string Email body in HTML format.
505 * @since 0.0.1
506 */
507 private function get_admin_new_donation_body() {
508 ob_start();
509 ?>
510 <p><strong><span style="font-size: 18px;"><?php esc_html_e( 'New Donation Received!', 'suredonation' ); ?></span></strong></p>
511 <p><?php esc_html_e( 'A new donation has been received for your campaign.', 'suredonation' ); ?></p>
512 <p><strong><?php esc_html_e( 'Donation Details:', 'suredonation' ); ?></strong></p>
513 <ul>
514 <li><?php esc_html_e( 'Donor:', 'suredonation' ); ?> {donor_name} ({donor_email})</li>
515 <li><?php esc_html_e( 'Amount:', 'suredonation' ); ?> {amount}</li>
516 <li><?php esc_html_e( 'Campaign:', 'suredonation' ); ?> {campaign_name}</li>
517 <li><?php esc_html_e( 'Date:', 'suredonation' ); ?> {donation_date}</li>
518 <li><?php esc_html_e( 'Transaction ID:', 'suredonation' ); ?> {transaction_id}</li>
519 </ul>
520 <?php
521 $output = ob_get_clean();
522 return trim( false !== $output ? $output : '' );
523 }
524
525 /**
526 * Get sample donation data for test emails.
527 *
528 * @return array<string, int|string> Sample data.
529 * @since 0.0.1
530 */
531 private function get_sample_donation_data() {
532 $currency = Payment_Helper::get_currency();
533 $currency_symbol = Payment_Helper::get_currency_symbol( $currency );
534 $date_format = get_option( 'date_format' );
535 $admin_email = get_option( 'admin_email' );
536
537 return [
538 'donor_name' => __( 'John Doe', 'suredonation' ),
539 'donor_email' => 'john.doe@example.com',
540 'amount' => $currency_symbol . '50.00',
541 'campaign_name' => __( 'Sample Campaign', 'suredonation' ),
542 'donation_date' => current_time( is_string( $date_format ) ? $date_format : 'Y-m-d' ),
543 'transaction_id' => 'pi_test_' . wp_generate_password( 16, false ),
544 'site_title' => get_bloginfo( 'name' ),
545 'admin_email' => is_string( $admin_email ) ? $admin_email : '',
546 'site_url' => home_url(),
547 'admin_url' => admin_url( 'admin.php?page=suredonation' ),
548 ];
549 }
550
551 /**
552 * Process smart tags for test emails.
553 *
554 * @param string $content Content with smart tags.
555 * @param array<string, int|string> $sample_data Sample data for replacement.
556 * @return string Processed content.
557 * @since 0.0.1
558 */
559 private function process_test_smart_tags( $content, $sample_data ) {
560 $tags = [
561 '{donor_name}' => $sample_data['donor_name'],
562 '{donor_email}' => $sample_data['donor_email'],
563 '{amount}' => $sample_data['amount'],
564 '{campaign_name}' => $sample_data['campaign_name'],
565 '{donation_date}' => $sample_data['donation_date'],
566 '{transaction_id}' => $sample_data['transaction_id'],
567 '{site_title}' => $sample_data['site_title'],
568 '{admin_email}' => $sample_data['admin_email'],
569 '{site_url}' => $sample_data['site_url'],
570 '{admin_url}' => $sample_data['admin_url'],
571 ];
572
573 return str_replace( array_keys( $tags ), array_values( $tags ), $content );
574 }
575
576 /**
577 * Format test email body with HTML wrapper.
578 *
579 * @param string $body Email body content.
580 * @return string Formatted HTML email.
581 * @since 0.0.1
582 */
583 private function format_test_email_body( $body ) {
584 $email_template = Email_Template::get_instance();
585 return $email_template->render( $body );
586 }
587 }
588