PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.1.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.1.0
1.6.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
← All changes | inc/form-editor/assets.php +327 -53 0.0.1 → 1.1.0 View file →
@@ -9,8 +9,10 @@
9 9 */
10 10
11 11 namespace SureDonation\Inc\FormEditor;
12 12
13 +use SureDonation\Inc\Helper;
14 +use SureDonation\Inc\Payments\Payment_Helper;
13 15 use SureDonation\Inc\Traits\Get_Instance;
14 16 use SureDonation\Inc\Post_Types\Donation_Form;
15 17
16 18 // Exit if accessed directly.
@@ -33,8 +35,9 @@
33 35 */
34 36 public function __construct() {
35 37 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] );
36 38 add_action( 'init', [ $this, 'register_form_settings_meta' ] );
39 + add_action( 'init', [ $this, 'register_email_notifications_meta' ] );
37 40 }
38 41
39 42 /**
40 43 * Enqueue editor assets for the donation form editor.
@@ -83,15 +86,23 @@
83 86 $editor_asset['version']
84 87 );
85 88
86 89 // Localized data.
90 + $global_currency = Payment_Helper::get_global_setting( 'currency', 'USD' );
91 + $global_currency = is_string( $global_currency ) ? $global_currency : 'USD';
92 +
87 93 wp_localize_script(
88 94 'suredonation-form-editor',
89 95 'suredonationFormEditor',
90 96 [
91 - 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
92 - 'nonce' => wp_create_nonce( 'suredonation_editor_nonce' ),
93 - 'postType' => Donation_Form::POST_TYPE,
97 + 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
98 + 'nonce' => wp_create_nonce( 'suredonation_editor_nonce' ),
99 + 'postType' => Donation_Form::POST_TYPE,
100 + 'smartTags' => Helper::get_smart_tags()['confirmation'],
101 + 'emailSmartTags' => Helper::get_smart_tags()['email_grouped'],
102 + 'defaultEmailNotifications' => $this->get_default_email_notifications(),
103 + 'currency' => $global_currency,
104 + 'currencySymbol' => Payment_Helper::get_currency_symbol( $global_currency ),
94 105 ]
95 106 );
96 107
97 108 // Set script translations.
@@ -100,85 +111,348 @@
100 111
101 112 /**
102 113 * Register form settings meta fields.
103 114 *
104 - * These meta fields store form-level settings like submit button text,
105 - * success message, and confirmation type.
115 + * Stores form confirmation settings as a single JSON string.
106 116 *
107 117 * @return void
108 - * @since 0.0.1
118 + * @since 1.0.0
109 119 */
110 120 public function register_form_settings_meta() {
111 121 $post_type = Donation_Form::POST_TYPE;
112 122
113 - // Submit button text.
114 - register_post_meta(
115 - $post_type,
116 - '_suredonation_form_submitButtonText',
123 + // Default confirmation message HTML (receipt layout with smart tags).
124 + $default_message = Helper::get_default_confirmation_message();
125 +
126 + $default_confirmation = wp_json_encode(
117 127 [
118 - 'type' => 'string',
119 - 'description' => __( 'Submit button text.', 'suredonation' ),
120 - 'single' => true,
121 - 'default' => 'Donate',
122 - 'show_in_rest' => true,
123 - 'sanitize_callback' => 'sanitize_text_field',
124 - 'auth_callback' => function () {
125 - return current_user_can( 'edit_posts' );
126 - },
128 + 'confirmation_type' => 'same page',
129 + 'message' => $default_message,
130 + 'submission_action' => 'hide form',
131 + 'custom_url' => '',
132 + 'page_url' => '',
127 133 ]
128 134 );
129 135
130 - // Success message.
136 + // Form confirmation settings (JSON string).
131 137 register_post_meta(
132 138 $post_type,
133 - '_suredonation_form_successMessage',
139 + '_suredonation_form_confirmation',
134 140 [
135 141 'type' => 'string',
136 - 'description' => __( 'Success message shown after donation.', 'suredonation' ),
142 + 'description' => __( 'Form confirmation settings.', 'suredonation' ),
137 143 'single' => true,
138 - 'default' => 'Thank you for your donation!',
139 - 'show_in_rest' => true,
140 - 'sanitize_callback' => 'sanitize_textarea_field',
141 - 'auth_callback' => function () {
142 - return current_user_can( 'edit_posts' );
144 + 'default' => $default_confirmation,
145 + 'show_in_rest' => [
146 + 'schema' => [
147 + 'type' => 'string',
148 + 'context' => [ 'edit' ],
149 + ],
150 + ],
151 + 'sanitize_callback' => [ $this, 'sanitize_confirmation_settings' ],
152 + 'auth_callback' => static function () {
153 + return current_user_can( 'manage_options' );
143 154 },
144 155 ]
145 156 );
157 + }
146 158
147 - // Confirmation type.
148 - register_post_meta(
149 - $post_type,
150 - '_suredonation_form_confirmationType',
159 + /**
160 + * Email notification meta key.
161 + *
162 + * No migration from global `suredonation_options['email_notifications']` is needed:
163 + * the plugin is pre-release (v0.0.1) with no production installs carrying customized
164 + * global settings. New forms are seeded with defaults via the editor JS useEffect.
165 + *
166 + * @since 1.0.0
167 + */
168 + public const EMAIL_NOTIFICATIONS_META_KEY = '_suredonation_form_email_notifications';
169 +
170 + /**
171 + * Get default email notifications for new forms.
172 + *
173 + * Provides the initial set of notifications (donation receipt + admin) that
174 + * are seeded when a form has no email notifications configured.
175 + *
176 + * @return array<int, array<string, mixed>> Default notifications array.
177 + * @since 1.0.0
178 + */
179 + public function get_default_email_notifications() {
180 + $sig = '<p>' . esc_html__( 'We truly appreciate your support', 'suredonation' ) . '</p>'
181 + . '<p>— {site_title}</p>';
182 +
183 + // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Readability.
184 + $defaults = [
185 + // --- Donor Emails ---
151 186 [
152 - 'type' => 'string',
153 - 'description' => __( 'What happens after successful donation.', 'suredonation' ),
154 - 'single' => true,
155 - 'default' => 'message',
156 - 'show_in_rest' => true,
157 - 'sanitize_callback' => function ( $value ) {
158 - $allowed = [ 'message', 'redirect' ];
159 - return in_array( $value, $allowed, true ) ? $value : 'message';
160 - },
161 - 'auth_callback' => function () {
162 - return current_user_can( 'edit_posts' );
163 - },
164 - ]
165 - );
187 + 'id' => 1,
188 + 'status' => true,
189 + 'name' => __( 'Donation Receipt', 'suredonation' ),
190 + 'email_to' => '{donor_email}',
191 + 'subject' => __( 'Thank you for your donation to {campaign_name}', 'suredonation' ),
192 + 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
193 + . '<p>' . esc_html__( 'Thank you for supporting {campaign_name}. Your contribution means a lot.', 'suredonation' ) . '</p>'
194 + . '<p><strong>' . esc_html__( 'Donation Details:', 'suredonation' ) . '</strong></p>'
195 + . '<ul>'
196 + . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
197 + . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
198 + . '<li>' . esc_html__( 'Transaction ID:', 'suredonation' ) . ' {transaction_id}</li>'
199 + . '</ul>'
200 + . $sig,
201 + 'from_name' => '{site_title}',
202 + 'from_email' => '{admin_email}',
203 + 'reply_to' => '',
204 + 'trigger' => 'donation_completed',
205 + ],
206 + [
207 + 'id' => 2,
208 + 'status' => true,
209 + 'name' => __( 'Donation Processing', 'suredonation' ),
210 + 'email_to' => '{donor_email}',
211 + 'subject' => __( 'Your donation is being processed', 'suredonation' ),
212 + 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
213 + . '<p>' . esc_html__( 'Your donation to {campaign_name} is currently being processed.', 'suredonation' ) . '</p>'
214 + . '<ul>'
215 + . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
216 + . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
217 + . '</ul>'
218 + . '<p>' . esc_html__( "We'll notify you once it's confirmed.", 'suredonation' ) . '</p>'
219 + . '<p>— {site_title}</p>',
220 + 'from_name' => '{site_title}',
221 + 'from_email' => '{admin_email}',
222 + 'reply_to' => '',
223 + 'trigger' => 'donation_processing',
224 + ],
225 + [
226 + 'id' => 3,
227 + 'status' => true,
228 + 'name' => __( 'Donation Failed', 'suredonation' ),
229 + 'email_to' => '{donor_email}',
230 + 'subject' => __( "We couldn't process your donation", 'suredonation' ),
231 + 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
232 + . '<p>' . esc_html__( 'Unfortunately, your donation to {campaign_name} could not be completed.', 'suredonation' ) . '</p>'
233 + . '<p>' . esc_html__( 'If you need help, feel free to contact us.', 'suredonation' ) . '</p>'
234 + . '<p>— {site_title}</p>',
235 + 'from_name' => '{site_title}',
236 + 'from_email' => '{admin_email}',
237 + 'reply_to' => '',
238 + 'trigger' => 'donation_failed',
239 + ],
240 + [
241 + 'id' => 4,
242 + 'status' => true,
243 + 'name' => __( 'Refund Processed', 'suredonation' ),
244 + 'email_to' => '{donor_email}',
245 + 'subject' => __( 'Your donation has been refunded', 'suredonation' ),
246 + 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
247 + . '<p>' . esc_html__( 'Your donation has been refunded.', 'suredonation' ) . '</p>'
248 + . '<ul>'
249 + . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
250 + . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {refund_amount}</li>'
251 + . '</ul>'
252 + . '<p>' . esc_html__( 'If you have any questions, feel free to reach out.', 'suredonation' ) . '</p>'
253 + . '<p>— {site_title}</p>',
254 + 'from_name' => '{site_title}',
255 + 'from_email' => '{admin_email}',
256 + 'reply_to' => '',
257 + 'trigger' => 'refund_processed',
258 + ],
166 259
167 - // Redirect URL.
260 + // --- Admin Emails ---
261 + [
262 + 'id' => 9,
263 + 'status' => true,
264 + 'name' => __( 'New Donation (Admin)', 'suredonation' ),
265 + 'email_to' => '{admin_email}',
266 + 'subject' => __( 'New donation received', 'suredonation' ),
267 + 'email_body' => '<p>' . esc_html__( 'A new donation has been received.', 'suredonation' ) . '</p>'
268 + . '<ul>'
269 + . '<li>' . esc_html__( 'Donor:', 'suredonation' ) . ' {donor_name}</li>'
270 + . '<li>' . esc_html__( 'Email:', 'suredonation' ) . ' {donor_email}</li>'
271 + . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
272 + . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
273 + . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
274 + . '</ul>'
275 + . '<p>' . esc_html__( 'View details:', 'suredonation' ) . '<br />{admin_url}</p>',
276 + 'from_name' => '{site_title}',
277 + 'from_email' => '{admin_email}',
278 + 'reply_to' => '',
279 + 'trigger' => 'donation_completed',
280 + ],
281 + [
282 + 'id' => 10,
283 + 'status' => true,
284 + 'name' => __( 'Donation Failed (Admin)', 'suredonation' ),
285 + 'email_to' => '{admin_email}',
286 + 'subject' => __( 'Donation failed', 'suredonation' ),
287 + 'email_body' => '<p>' . esc_html__( 'A donation attempt has failed.', 'suredonation' ) . '</p>'
288 + . '<ul>'
289 + . '<li>' . esc_html__( 'Donor:', 'suredonation' ) . ' {donor_name}</li>'
290 + . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
291 + . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
292 + . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
293 + . '</ul>'
294 + . '<p>' . esc_html__( 'Check details:', 'suredonation' ) . '<br />{admin_url}</p>',
295 + 'from_name' => '{site_title}',
296 + 'from_email' => '{admin_email}',
297 + 'reply_to' => '',
298 + 'trigger' => 'donation_failed',
299 + ],
300 + [
301 + 'id' => 11,
302 + 'status' => true,
303 + 'name' => __( 'Refund Processed (Admin)', 'suredonation' ),
304 + 'email_to' => '{admin_email}',
305 + 'subject' => __( 'Refund issued', 'suredonation' ),
306 + 'email_body' => '<p>' . esc_html__( 'A refund has been processed.', 'suredonation' ) . '</p>'
307 + . '<ul>'
308 + . '<li>' . esc_html__( 'Donor:', 'suredonation' ) . ' {donor_name}</li>'
309 + . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
310 + . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {refund_amount}</li>'
311 + . '</ul>'
312 + . '<p>' . esc_html__( 'View details:', 'suredonation' ) . '<br />{admin_url}</p>',
313 + 'from_name' => '{site_title}',
314 + 'from_email' => '{admin_email}',
315 + 'reply_to' => '',
316 + 'trigger' => 'refund_processed',
317 + ],
318 + ];
319 + // phpcs:enable Generic.Strings.UnnecessaryStringConcat.Found
320 +
321 + /**
322 + * Filter default email notifications.
323 + * Pro uses this to add subscription email notification templates.
324 + *
325 + * @param array<int, array<string, mixed>> $defaults Default notification configs.
326 + * @since 1.0.0
327 + */
328 + return apply_filters( 'suredonation_default_email_notifications', $defaults );
329 + }
330 +
331 + /**
332 + * Register email notification meta for donation forms.
333 + *
334 + * Stores per-form email notification settings as a JSON string.
335 + *
336 + * @return void
337 + * @since 1.0.0
338 + */
339 + public function register_email_notifications_meta() {
168 340 register_post_meta(
169 - $post_type,
170 - '_suredonation_form_redirectUrl',
341 + Donation_Form::POST_TYPE,
342 + self::EMAIL_NOTIFICATIONS_META_KEY,
171 343 [
172 344 'type' => 'string',
173 - 'description' => __( 'URL to redirect after donation.', 'suredonation' ),
345 + 'description' => __( 'Form email notification settings.', 'suredonation' ),
174 346 'single' => true,
175 347 'default' => '',
176 - 'show_in_rest' => true,
177 - 'sanitize_callback' => 'esc_url_raw',
178 - 'auth_callback' => function () {
179 - return current_user_can( 'edit_posts' );
348 + 'show_in_rest' => [
349 + 'schema' => [
350 + 'type' => 'string',
351 + 'context' => [ 'edit' ],
352 + ],
353 + ],
354 + 'sanitize_callback' => [ $this, 'sanitize_email_notifications' ],
355 + 'auth_callback' => static function () {
356 + return current_user_can( 'manage_options' );
180 357 },
181 358 ]
182 359 );
360 + }
361 +
362 + /**
363 + * Sanitize email notification settings.
364 + *
365 + * @param string $value JSON string of email notification settings.
366 + * @return string Sanitized JSON string.
367 + * @since 1.0.0
368 + */
369 + public function sanitize_email_notifications( $value ) {
370 + if ( empty( $value ) || ! is_string( $value ) ) {
371 + return '';
372 + }
373 +
374 + $data = json_decode( $value, true );
375 +
376 + if ( ! is_array( $data ) ) {
377 + return '';
378 + }
379 +
380 + $sanitized = [];
381 + foreach ( $data as $notification ) {
382 + if ( ! is_array( $notification ) ) {
383 + continue;
384 + }
385 +
386 + $sanitized[] = [
387 + 'id' => isset( $notification['id'] ) ? absint( $notification['id'] ) : 0,
388 + 'status' => isset( $notification['status'] ) ? (bool) $notification['status'] : true,
389 + 'name' => isset( $notification['name'] ) ? sanitize_text_field( $notification['name'] ) : '',
390 + 'email_to' => isset( $notification['email_to'] ) ? sanitize_text_field( $notification['email_to'] ) : '',
391 + 'subject' => isset( $notification['subject'] ) ? sanitize_text_field( $notification['subject'] ) : '',
392 + 'email_body' => isset( $notification['email_body'] ) ? wp_kses_post( $notification['email_body'] ) : '',
393 + 'from_name' => isset( $notification['from_name'] ) ? sanitize_text_field( $notification['from_name'] ) : '',
394 + 'from_email' => isset( $notification['from_email'] ) ? sanitize_text_field( $notification['from_email'] ) : '',
395 + 'reply_to' => isset( $notification['reply_to'] ) ? sanitize_text_field( $notification['reply_to'] ) : '',
396 + 'trigger' => isset( $notification['trigger'] ) && in_array(
397 + $notification['trigger'],
398 + apply_filters(
399 + 'suredonation_email_notification_triggers',
400 + [ 'all', 'donation_completed', 'donation_processing', 'donation_failed', 'refund_processed' ]
401 + ),
402 + true
403 + ) ? $notification['trigger'] : 'all',
404 + ];
405 + }
406 +
407 + $encoded = wp_json_encode( $sanitized );
408 + return is_string( $encoded ) ? $encoded : '';
409 + }
410 +
411 + /**
412 + * Sanitize form confirmation settings.
413 + *
414 + * @param string $value JSON string of confirmation settings.
415 + * @return string Sanitized JSON string.
416 + * @since 1.0.0
417 + */
418 + public function sanitize_confirmation_settings( $value ) {
419 + $fallback_data = [
420 + 'confirmation_type' => 'same page',
421 + 'message' => '',
422 + 'submission_action' => 'hide form',
423 + 'custom_url' => '',
424 + 'page_url' => '',
425 + ];
426 + $fallback = (string) wp_json_encode( $fallback_data );
427 +
428 + if ( empty( $value ) || ! is_string( $value ) ) {
429 + return $fallback;
430 + }
431 +
432 + $data = json_decode( $value, true );
433 +
434 + if ( ! is_array( $data ) ) {
435 + return $fallback;
436 + }
437 +
438 + $allowed_types = [ 'same page', 'different page', 'custom url' ];
439 + $allowed_actions = [ 'hide form', 'reset form' ];
440 +
441 + $message = isset( $data['message'] ) ? wp_kses_post( $data['message'] ) : '';
442 +
443 + $sanitized = [
444 + 'confirmation_type' => isset( $data['confirmation_type'] ) && in_array( $data['confirmation_type'], $allowed_types, true )
445 + ? $data['confirmation_type']
446 + : 'same page',
447 + 'message' => $message,
448 + 'submission_action' => isset( $data['submission_action'] ) && in_array( $data['submission_action'], $allowed_actions, true )
449 + ? $data['submission_action']
450 + : 'hide form',
451 + 'custom_url' => isset( $data['custom_url'] ) ? esc_url_raw( $data['custom_url'] ) : '',
452 + 'page_url' => isset( $data['page_url'] ) ? esc_url_raw( $data['page_url'] ) : '',
453 + ];
454 +
455 + $encoded = wp_json_encode( $sanitized );
456 + return is_string( $encoded ) ? $encoded : $fallback;
183 457 }
184 458 }