PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.3.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.3.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
suredonation / inc / form-editor / assets.php

assets.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management 1.3.0, at inc/form-editor/assets.php

482 lines 17.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Form Editor Assets.
4 *
5 * Handles asset registration and enqueuing for the donation form editor.
6 *
7 * @package SureDonation
8 * @since 0.0.1
9 */
10
11 namespace SureDonation\Inc\FormEditor;
12
13 use SureDonation\Inc\Helper;
14 use SureDonation\Inc\Payments\Payment_Helper;
15 use SureDonation\Inc\Traits\Get_Instance;
16 use SureDonation\Inc\Post_Types\Donation_Form;
17
18 // Exit if accessed directly.
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 /**
24 * Assets Class.
25 *
26 * @since 0.0.1
27 */
28 class Assets {
29 use Get_Instance;
30
31 /**
32 * Constructor.
33 *
34 * @since 0.0.1
35 */
36 public function __construct() {
37 add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_editor_assets' ] );
38 add_action( 'init', [ $this, 'register_form_settings_meta' ] );
39 add_action( 'init', [ $this, 'register_email_notifications_meta' ] );
40 }
41
42 /**
43 * Enqueue editor assets for the donation form editor.
44 *
45 * @return void
46 * @since 0.0.1
47 */
48 public function enqueue_editor_assets() {
49 $screen = get_current_screen();
50
51 // Only load on donation form editor.
52 if ( ! $screen || Donation_Form::POST_TYPE !== $screen->post_type ) {
53 return;
54 }
55
56 // Get the asset file for dependencies.
57 $editor_asset_file = SUREDONATION_DIR . 'assets/build/editor/editor.asset.php';
58 $editor_asset = file_exists( $editor_asset_file )
59 ? include $editor_asset_file
60 : [
61 'dependencies' => [
62 'wp-plugins',
63 'wp-editor',
64 'wp-components',
65 'wp-data',
66 'wp-element',
67 'wp-i18n',
68 ],
69 'version' => SUREDONATION_VER,
70 ];
71
72 // Editor plugin JS.
73 wp_enqueue_script(
74 'suredonation-form-editor',
75 SUREDONATION_URL . 'assets/build/editor/editor.js',
76 $editor_asset['dependencies'],
77 $editor_asset['version'],
78 true
79 );
80
81 // Editor styles.
82 wp_enqueue_style(
83 'suredonation-form-editor',
84 SUREDONATION_URL . 'assets/build/editor/editor.css',
85 [ 'wp-components' ],
86 $editor_asset['version']
87 );
88
89 // The OttoKit embed script (defines window.SureTriggers) is NOT enqueued
90 // here — it is remote executable JS and would load on every form-editor
91 // session even when OttoKit is absent. It is lazy-injected from the
92 // OttoKit tab only when the builder opens (see OttoKitSettings.js), using
93 // the URL passed below.
94
95 // Localized data.
96 $global_currency = Payment_Helper::get_global_setting( 'currency', 'USD' );
97 $global_currency = is_string( $global_currency ) ? $global_currency : 'USD';
98
99 $editor_data = [
100 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
101 'nonce' => wp_create_nonce( 'suredonation_editor_nonce' ),
102 'postType' => Donation_Form::POST_TYPE,
103 'smartTags' => Helper::get_smart_tags()['confirmation'],
104 'emailSmartTags' => Helper::get_smart_tags()['email_grouped'],
105 'defaultEmailNotifications' => $this->get_default_email_notifications(),
106 'currency' => $global_currency,
107 'currencySymbol' => Payment_Helper::get_currency_symbol( $global_currency ),
108 // OttoKit integration: embed config + lazy-loaded builder script.
109 'suretriggersNonce' => wp_create_nonce( 'suredonation_suretriggers_nonce' ),
110 'embedScriptUrl' => SUREDONATION_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js',
111 'integrations' => [
112 'sure_triggers' => Helper::get_ottokit_integration(),
113 ],
114 ];
115
116 // Plugin install/activate nonces are a plugin-management capability;
117 // only expose them to users who can actually install plugins. The AJAX
118 // handlers enforce this server-side too — this keeps the nonces out of
119 // the page source for sub-admins who reach the editor via post.php.
120 if ( current_user_can( 'install_plugins' ) ) {
121 $editor_data['pluginInstallerNonce'] = wp_create_nonce( 'updates' );
122 $editor_data['pluginManagerNonce'] = wp_create_nonce( 'suredonation_plugin_manager' );
123 }
124
125 wp_localize_script(
126 'suredonation-form-editor',
127 'suredonationFormEditor',
128 $editor_data
129 );
130
131 // Set script translations.
132 wp_set_script_translations( 'suredonation-form-editor', 'suredonation' );
133 }
134
135 /**
136 * Register form settings meta fields.
137 *
138 * Stores form confirmation settings as a single JSON string.
139 *
140 * @return void
141 * @since 1.0.0
142 */
143 public function register_form_settings_meta() {
144 $post_type = Donation_Form::POST_TYPE;
145
146 // Default confirmation message HTML (receipt layout with smart tags).
147 $default_message = Helper::get_default_confirmation_message();
148
149 $default_confirmation = wp_json_encode(
150 [
151 'confirmation_type' => 'same page',
152 'message' => $default_message,
153 'submission_action' => 'hide form',
154 'custom_url' => '',
155 'page_url' => '',
156 ]
157 );
158
159 // Form confirmation settings (JSON string).
160 register_post_meta(
161 $post_type,
162 '_suredonation_form_confirmation',
163 [
164 'type' => 'string',
165 'description' => __( 'Form confirmation settings.', 'suredonation' ),
166 'single' => true,
167 'default' => $default_confirmation,
168 'show_in_rest' => [
169 'schema' => [
170 'type' => 'string',
171 'context' => [ 'edit' ],
172 ],
173 ],
174 'sanitize_callback' => [ $this, 'sanitize_confirmation_settings' ],
175 'auth_callback' => static function () {
176 return current_user_can( 'manage_options' );
177 },
178 ]
179 );
180 }
181
182 /**
183 * Email notification meta key.
184 *
185 * No migration from global `suredonation_options['email_notifications']` is needed:
186 * the plugin is pre-release (v0.0.1) with no production installs carrying customized
187 * global settings. New forms are seeded with defaults via the editor JS useEffect.
188 *
189 * @since 1.0.0
190 */
191 public const EMAIL_NOTIFICATIONS_META_KEY = '_suredonation_form_email_notifications';
192
193 /**
194 * Get default email notifications for new forms.
195 *
196 * Provides the initial set of notifications (donation receipt + admin) that
197 * are seeded when a form has no email notifications configured.
198 *
199 * @return array<int, array<string, mixed>> Default notifications array.
200 * @since 1.0.0
201 */
202 public function get_default_email_notifications() {
203 $sig = '<p>' . esc_html__( 'We truly appreciate your support', 'suredonation' ) . '</p>'
204 . '<p>— {site_title}</p>';
205
206 // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Readability.
207 $defaults = [
208 // --- Donor Emails ---
209 [
210 'id' => 1,
211 'status' => true,
212 'name' => __( 'Donation Receipt', 'suredonation' ),
213 'email_to' => '{donor_email}',
214 'subject' => __( 'Thank you for your donation to {campaign_name}', 'suredonation' ),
215 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
216 . '<p>' . esc_html__( 'Thank you for supporting {campaign_name}. Your contribution means a lot.', 'suredonation' ) . '</p>'
217 . '<p><strong>' . esc_html__( 'Donation Details:', 'suredonation' ) . '</strong></p>'
218 . '<ul>'
219 . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
220 . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
221 . '<li>' . esc_html__( 'Transaction ID:', 'suredonation' ) . ' {transaction_id}</li>'
222 . '</ul>'
223 . $sig,
224 'from_name' => '{site_title}',
225 'from_email' => '{admin_email}',
226 'reply_to' => '',
227 'trigger' => 'donation_completed',
228 ],
229 [
230 'id' => 2,
231 'status' => true,
232 'name' => __( 'Donation Processing', 'suredonation' ),
233 'email_to' => '{donor_email}',
234 'subject' => __( 'Your donation is being processed', 'suredonation' ),
235 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
236 . '<p>' . esc_html__( 'Your donation to {campaign_name} is currently being processed.', 'suredonation' ) . '</p>'
237 . '<ul>'
238 . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
239 . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
240 . '</ul>'
241 . '<p>' . esc_html__( "We'll notify you once it's confirmed.", 'suredonation' ) . '</p>'
242 . '<p>— {site_title}</p>',
243 'from_name' => '{site_title}',
244 'from_email' => '{admin_email}',
245 'reply_to' => '',
246 'trigger' => 'donation_processing',
247 ],
248 [
249 'id' => 3,
250 'status' => true,
251 'name' => __( 'Donation Failed', 'suredonation' ),
252 'email_to' => '{donor_email}',
253 'subject' => __( "We couldn't process your donation", 'suredonation' ),
254 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
255 . '<p>' . esc_html__( 'Unfortunately, your donation to {campaign_name} could not be completed.', 'suredonation' ) . '</p>'
256 . '<p>' . esc_html__( 'If you need help, feel free to contact us.', 'suredonation' ) . '</p>'
257 . '<p>— {site_title}</p>',
258 'from_name' => '{site_title}',
259 'from_email' => '{admin_email}',
260 'reply_to' => '',
261 'trigger' => 'donation_failed',
262 ],
263 [
264 'id' => 4,
265 'status' => true,
266 'name' => __( 'Refund Processed', 'suredonation' ),
267 'email_to' => '{donor_email}',
268 'subject' => __( 'Your donation has been refunded', 'suredonation' ),
269 'email_body' => '<p>' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '</p>'
270 . '<p>' . esc_html__( 'Your donation has been refunded.', 'suredonation' ) . '</p>'
271 . '<ul>'
272 . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
273 . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {refund_amount}</li>'
274 . '</ul>'
275 . '<p>' . esc_html__( 'If you have any questions, feel free to reach out.', 'suredonation' ) . '</p>'
276 . '<p>— {site_title}</p>',
277 'from_name' => '{site_title}',
278 'from_email' => '{admin_email}',
279 'reply_to' => '',
280 'trigger' => 'refund_processed',
281 ],
282
283 // --- Admin Emails ---
284 [
285 'id' => 9,
286 'status' => true,
287 'name' => __( 'New Donation (Admin)', 'suredonation' ),
288 'email_to' => '{admin_email}',
289 'subject' => __( 'New donation received', 'suredonation' ),
290 'email_body' => '<p>' . esc_html__( 'A new donation has been received.', 'suredonation' ) . '</p>'
291 . '<ul>'
292 . '<li>' . esc_html__( 'Donor:', 'suredonation' ) . ' {donor_name}</li>'
293 . '<li>' . esc_html__( 'Email:', 'suredonation' ) . ' {donor_email}</li>'
294 . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
295 . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
296 . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
297 . '</ul>'
298 . '<p>' . esc_html__( 'View details:', 'suredonation' ) . '<br />{admin_url}</p>',
299 'from_name' => '{site_title}',
300 'from_email' => '{admin_email}',
301 'reply_to' => '',
302 'trigger' => 'donation_completed',
303 ],
304 [
305 'id' => 10,
306 'status' => true,
307 'name' => __( 'Donation Failed (Admin)', 'suredonation' ),
308 'email_to' => '{admin_email}',
309 'subject' => __( 'Donation failed', 'suredonation' ),
310 'email_body' => '<p>' . esc_html__( 'A donation attempt has failed.', 'suredonation' ) . '</p>'
311 . '<ul>'
312 . '<li>' . esc_html__( 'Donor:', 'suredonation' ) . ' {donor_name}</li>'
313 . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
314 . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {amount}</li>'
315 . '<li>' . esc_html__( 'Date:', 'suredonation' ) . ' {donation_date}</li>'
316 . '</ul>'
317 . '<p>' . esc_html__( 'Check details:', 'suredonation' ) . '<br />{admin_url}</p>',
318 'from_name' => '{site_title}',
319 'from_email' => '{admin_email}',
320 'reply_to' => '',
321 'trigger' => 'donation_failed',
322 ],
323 [
324 'id' => 11,
325 'status' => true,
326 'name' => __( 'Refund Processed (Admin)', 'suredonation' ),
327 'email_to' => '{admin_email}',
328 'subject' => __( 'Refund issued', 'suredonation' ),
329 'email_body' => '<p>' . esc_html__( 'A refund has been processed.', 'suredonation' ) . '</p>'
330 . '<ul>'
331 . '<li>' . esc_html__( 'Donor:', 'suredonation' ) . ' {donor_name}</li>'
332 . '<li>' . esc_html__( 'Campaign:', 'suredonation' ) . ' {campaign_name}</li>'
333 . '<li>' . esc_html__( 'Amount:', 'suredonation' ) . ' {refund_amount}</li>'
334 . '</ul>'
335 . '<p>' . esc_html__( 'View details:', 'suredonation' ) . '<br />{admin_url}</p>',
336 'from_name' => '{site_title}',
337 'from_email' => '{admin_email}',
338 'reply_to' => '',
339 'trigger' => 'refund_processed',
340 ],
341 ];
342 // phpcs:enable Generic.Strings.UnnecessaryStringConcat.Found
343
344 /**
345 * Filter default email notifications.
346 * Pro uses this to add subscription email notification templates.
347 *
348 * @param array<int, array<string, mixed>> $defaults Default notification configs.
349 * @since 1.0.0
350 */
351 return apply_filters( 'suredonation_default_email_notifications', $defaults );
352 }
353
354 /**
355 * Register email notification meta for donation forms.
356 *
357 * Stores per-form email notification settings as a JSON string.
358 *
359 * @return void
360 * @since 1.0.0
361 */
362 public function register_email_notifications_meta() {
363 register_post_meta(
364 Donation_Form::POST_TYPE,
365 self::EMAIL_NOTIFICATIONS_META_KEY,
366 [
367 'type' => 'string',
368 'description' => __( 'Form email notification settings.', 'suredonation' ),
369 'single' => true,
370 'default' => '',
371 'show_in_rest' => [
372 'schema' => [
373 'type' => 'string',
374 'context' => [ 'edit' ],
375 ],
376 ],
377 'sanitize_callback' => [ $this, 'sanitize_email_notifications' ],
378 'auth_callback' => static function () {
379 return current_user_can( 'manage_options' );
380 },
381 ]
382 );
383 }
384
385 /**
386 * Sanitize email notification settings.
387 *
388 * @param string $value JSON string of email notification settings.
389 * @return string Sanitized JSON string.
390 * @since 1.0.0
391 */
392 public function sanitize_email_notifications( $value ) {
393 if ( empty( $value ) || ! is_string( $value ) ) {
394 return '';
395 }
396
397 $data = json_decode( $value, true );
398
399 if ( ! is_array( $data ) ) {
400 return '';
401 }
402
403 $sanitized = [];
404 foreach ( $data as $notification ) {
405 if ( ! is_array( $notification ) ) {
406 continue;
407 }
408
409 $sanitized[] = [
410 'id' => isset( $notification['id'] ) ? absint( $notification['id'] ) : 0,
411 'status' => isset( $notification['status'] ) ? (bool) $notification['status'] : true,
412 'name' => isset( $notification['name'] ) ? sanitize_text_field( $notification['name'] ) : '',
413 'email_to' => isset( $notification['email_to'] ) ? sanitize_text_field( $notification['email_to'] ) : '',
414 'subject' => isset( $notification['subject'] ) ? sanitize_text_field( $notification['subject'] ) : '',
415 'email_body' => isset( $notification['email_body'] ) ? wp_kses_post( $notification['email_body'] ) : '',
416 'from_name' => isset( $notification['from_name'] ) ? sanitize_text_field( $notification['from_name'] ) : '',
417 'from_email' => isset( $notification['from_email'] ) ? sanitize_text_field( $notification['from_email'] ) : '',
418 'reply_to' => isset( $notification['reply_to'] ) ? sanitize_text_field( $notification['reply_to'] ) : '',
419 'trigger' => isset( $notification['trigger'] ) && in_array(
420 $notification['trigger'],
421 apply_filters(
422 'suredonation_email_notification_triggers',
423 [ 'all', 'donation_completed', 'donation_processing', 'donation_failed', 'refund_processed' ]
424 ),
425 true
426 ) ? $notification['trigger'] : 'all',
427 ];
428 }
429
430 $encoded = wp_json_encode( $sanitized );
431 return is_string( $encoded ) ? $encoded : '';
432 }
433
434 /**
435 * Sanitize form confirmation settings.
436 *
437 * @param string $value JSON string of confirmation settings.
438 * @return string Sanitized JSON string.
439 * @since 1.0.0
440 */
441 public function sanitize_confirmation_settings( $value ) {
442 $fallback_data = [
443 'confirmation_type' => 'same page',
444 'message' => '',
445 'submission_action' => 'hide form',
446 'custom_url' => '',
447 'page_url' => '',
448 ];
449 $fallback = (string) wp_json_encode( $fallback_data );
450
451 if ( empty( $value ) || ! is_string( $value ) ) {
452 return $fallback;
453 }
454
455 $data = json_decode( $value, true );
456
457 if ( ! is_array( $data ) ) {
458 return $fallback;
459 }
460
461 $allowed_types = [ 'same page', 'different page', 'custom url' ];
462 $allowed_actions = [ 'hide form', 'reset form' ];
463
464 $message = isset( $data['message'] ) ? wp_kses_post( $data['message'] ) : '';
465
466 $sanitized = [
467 'confirmation_type' => isset( $data['confirmation_type'] ) && in_array( $data['confirmation_type'], $allowed_types, true )
468 ? $data['confirmation_type']
469 : 'same page',
470 'message' => $message,
471 'submission_action' => isset( $data['submission_action'] ) && in_array( $data['submission_action'], $allowed_actions, true )
472 ? $data['submission_action']
473 : 'hide form',
474 'custom_url' => isset( $data['custom_url'] ) ? esc_url_raw( $data['custom_url'] ) : '',
475 'page_url' => isset( $data['page_url'] ) ? esc_url_raw( $data['page_url'] ) : '',
476 ];
477
478 $encoded = wp_json_encode( $sanitized );
479 return is_string( $encoded ) ? $encoded : $fallback;
480 }
481 }
482