post_type ) { return; } // Get the asset file for dependencies. $editor_asset_file = SUREDONATION_DIR . 'assets/build/editor/editor.asset.php'; $editor_asset = file_exists( $editor_asset_file ) ? include $editor_asset_file : [ 'dependencies' => [ 'wp-plugins', 'wp-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', ], 'version' => SUREDONATION_VER, ]; // Editor plugin JS. wp_enqueue_script( 'suredonation-form-editor', SUREDONATION_URL . 'assets/build/editor/editor.js', $editor_asset['dependencies'], $editor_asset['version'], true ); // Editor styles. wp_enqueue_style( 'suredonation-form-editor', SUREDONATION_URL . 'assets/build/editor/editor.css', [ 'wp-components' ], $editor_asset['version'] ); // The OttoKit embed script (defines window.SureTriggers) is NOT enqueued // here — it is remote executable JS and would load on every form-editor // session even when OttoKit is absent. It is lazy-injected from the // OttoKit tab only when the builder opens (see OttoKitSettings.js), using // the URL passed below. // Localized data. $global_currency = Payment_Helper::get_global_setting( 'currency', 'USD' ); $global_currency = is_string( $global_currency ) ? $global_currency : 'USD'; $editor_data = [ 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'suredonation_editor_nonce' ), 'postType' => Donation_Form::POST_TYPE, 'smartTags' => Helper::get_smart_tags()['confirmation'], 'emailSmartTags' => Helper::get_smart_tags()['email_grouped'], 'defaultEmailNotifications' => $this->get_default_email_notifications(), 'currency' => $global_currency, 'currencySymbol' => Payment_Helper::get_currency_symbol( $global_currency ), // OttoKit integration: embed config + lazy-loaded builder script. 'suretriggersNonce' => wp_create_nonce( 'suredonation_suretriggers_nonce' ), 'embedScriptUrl' => SUREDONATION_SURETRIGGERS_INTEGRATION_BASE_URL . 'js/v2/embed.js', 'integrations' => [ 'sure_triggers' => Helper::get_ottokit_integration(), ], ]; // Plugin install/activate nonces are a plugin-management capability; // only expose them to users who can actually install plugins. The AJAX // handlers enforce this server-side too — this keeps the nonces out of // the page source for sub-admins who reach the editor via post.php. if ( current_user_can( 'install_plugins' ) ) { $editor_data['pluginInstallerNonce'] = wp_create_nonce( 'updates' ); $editor_data['pluginManagerNonce'] = wp_create_nonce( 'suredonation_plugin_manager' ); } wp_localize_script( 'suredonation-form-editor', 'suredonationFormEditor', $editor_data ); // Set script translations. wp_set_script_translations( 'suredonation-form-editor', 'suredonation' ); } /** * Register form settings meta fields. * * Stores form confirmation settings as a single JSON string. * * @return void * @since 1.0.0 */ public function register_form_settings_meta() { $post_type = Donation_Form::POST_TYPE; // Default confirmation message HTML (receipt layout with smart tags). $default_message = Helper::get_default_confirmation_message(); $default_confirmation = wp_json_encode( [ 'confirmation_type' => 'same page', 'message' => $default_message, 'submission_action' => 'hide form', 'custom_url' => '', 'page_url' => '', ] ); // Form confirmation settings (JSON string). register_post_meta( $post_type, '_suredonation_form_confirmation', [ 'type' => 'string', 'description' => __( 'Form confirmation settings.', 'suredonation' ), 'single' => true, 'default' => $default_confirmation, 'show_in_rest' => [ 'schema' => [ 'type' => 'string', 'context' => [ 'edit' ], ], ], 'sanitize_callback' => [ $this, 'sanitize_confirmation_settings' ], 'auth_callback' => static function () { return current_user_can( 'manage_options' ); }, ] ); } /** * Email notification meta key. * * No migration from global `suredonation_options['email_notifications']` is needed: * the plugin is pre-release (v0.0.1) with no production installs carrying customized * global settings. New forms are seeded with defaults via the editor JS useEffect. * * @since 1.0.0 */ public const EMAIL_NOTIFICATIONS_META_KEY = '_suredonation_form_email_notifications'; /** * Get default email notifications for new forms. * * Provides the initial set of notifications (donation receipt + admin) that * are seeded when a form has no email notifications configured. * * @return array> Default notifications array. * @since 1.0.0 */ public function get_default_email_notifications() { $sig = '

' . esc_html__( 'We truly appreciate your support', 'suredonation' ) . '

' . '

— {site_title}

'; // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Readability. $defaults = [ // --- Donor Emails --- [ 'id' => 1, 'status' => true, 'name' => __( 'Donation Receipt', 'suredonation' ), 'email_to' => '{donor_email}', 'subject' => __( 'Thank you for your donation to {campaign_name}', 'suredonation' ), 'email_body' => '

' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '

' . '

' . esc_html__( 'Thank you for supporting {campaign_name}. Your contribution means a lot.', 'suredonation' ) . '

' . '

' . esc_html__( 'Donation Details:', 'suredonation' ) . '

' . '' . $sig, 'from_name' => '{site_title}', 'from_email' => '{admin_email}', 'reply_to' => '', 'trigger' => 'donation_completed', ], [ 'id' => 2, 'status' => true, 'name' => __( 'Donation Processing', 'suredonation' ), 'email_to' => '{donor_email}', 'subject' => __( 'Your donation is being processed', 'suredonation' ), 'email_body' => '

' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '

' . '

' . esc_html__( 'Your donation to {campaign_name} is currently being processed.', 'suredonation' ) . '

' . '' . '

' . esc_html__( "We'll notify you once it's confirmed.", 'suredonation' ) . '

' . '

— {site_title}

', 'from_name' => '{site_title}', 'from_email' => '{admin_email}', 'reply_to' => '', 'trigger' => 'donation_processing', ], [ 'id' => 3, 'status' => true, 'name' => __( 'Donation Failed', 'suredonation' ), 'email_to' => '{donor_email}', 'subject' => __( "We couldn't process your donation", 'suredonation' ), 'email_body' => '

' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '

' . '

' . esc_html__( 'Unfortunately, your donation to {campaign_name} could not be completed.', 'suredonation' ) . '

' . '

' . esc_html__( 'If you need help, feel free to contact us.', 'suredonation' ) . '

' . '

— {site_title}

', 'from_name' => '{site_title}', 'from_email' => '{admin_email}', 'reply_to' => '', 'trigger' => 'donation_failed', ], [ 'id' => 4, 'status' => true, 'name' => __( 'Refund Processed', 'suredonation' ), 'email_to' => '{donor_email}', 'subject' => __( 'Your donation has been refunded', 'suredonation' ), 'email_body' => '

' . esc_html__( 'Hi {donor_name},', 'suredonation' ) . '

' . '

' . esc_html__( 'Your donation has been refunded.', 'suredonation' ) . '

' . '' . '

' . esc_html__( 'If you have any questions, feel free to reach out.', 'suredonation' ) . '

' . '

— {site_title}

', 'from_name' => '{site_title}', 'from_email' => '{admin_email}', 'reply_to' => '', 'trigger' => 'refund_processed', ], // --- Admin Emails --- [ 'id' => 9, 'status' => true, 'name' => __( 'New Donation (Admin)', 'suredonation' ), 'email_to' => '{admin_email}', 'subject' => __( 'New donation received', 'suredonation' ), 'email_body' => '

' . esc_html__( 'A new donation has been received.', 'suredonation' ) . '

' . '' . '

' . esc_html__( 'View details:', 'suredonation' ) . '
{admin_url}

', 'from_name' => '{site_title}', 'from_email' => '{admin_email}', 'reply_to' => '', 'trigger' => 'donation_completed', ], [ 'id' => 10, 'status' => true, 'name' => __( 'Donation Failed (Admin)', 'suredonation' ), 'email_to' => '{admin_email}', 'subject' => __( 'Donation failed', 'suredonation' ), 'email_body' => '

' . esc_html__( 'A donation attempt has failed.', 'suredonation' ) . '

' . '' . '

' . esc_html__( 'Check details:', 'suredonation' ) . '
{admin_url}

', 'from_name' => '{site_title}', 'from_email' => '{admin_email}', 'reply_to' => '', 'trigger' => 'donation_failed', ], [ 'id' => 11, 'status' => true, 'name' => __( 'Refund Processed (Admin)', 'suredonation' ), 'email_to' => '{admin_email}', 'subject' => __( 'Refund issued', 'suredonation' ), 'email_body' => '

' . esc_html__( 'A refund has been processed.', 'suredonation' ) . '

' . '' . '

' . esc_html__( 'View details:', 'suredonation' ) . '
{admin_url}

', 'from_name' => '{site_title}', 'from_email' => '{admin_email}', 'reply_to' => '', 'trigger' => 'refund_processed', ], ]; // phpcs:enable Generic.Strings.UnnecessaryStringConcat.Found /** * Filter default email notifications. * Pro uses this to add subscription email notification templates. * * @param array> $defaults Default notification configs. * @since 1.0.0 */ return apply_filters( 'suredonation_default_email_notifications', $defaults ); } /** * Register email notification meta for donation forms. * * Stores per-form email notification settings as a JSON string. * * @return void * @since 1.0.0 */ public function register_email_notifications_meta() { register_post_meta( Donation_Form::POST_TYPE, self::EMAIL_NOTIFICATIONS_META_KEY, [ 'type' => 'string', 'description' => __( 'Form email notification settings.', 'suredonation' ), 'single' => true, 'default' => '', 'show_in_rest' => [ 'schema' => [ 'type' => 'string', 'context' => [ 'edit' ], ], ], 'sanitize_callback' => [ $this, 'sanitize_email_notifications' ], 'auth_callback' => static function () { return current_user_can( 'manage_options' ); }, ] ); } /** * Sanitize email notification settings. * * @param string $value JSON string of email notification settings. * @return string Sanitized JSON string. * @since 1.0.0 */ public function sanitize_email_notifications( $value ) { if ( empty( $value ) || ! is_string( $value ) ) { return ''; } $data = json_decode( $value, true ); if ( ! is_array( $data ) ) { return ''; } $sanitized = []; foreach ( $data as $notification ) { if ( ! is_array( $notification ) ) { continue; } $sanitized[] = [ 'id' => isset( $notification['id'] ) ? absint( $notification['id'] ) : 0, 'status' => isset( $notification['status'] ) ? (bool) $notification['status'] : true, 'name' => isset( $notification['name'] ) ? sanitize_text_field( $notification['name'] ) : '', 'email_to' => isset( $notification['email_to'] ) ? sanitize_text_field( $notification['email_to'] ) : '', 'subject' => isset( $notification['subject'] ) ? sanitize_text_field( $notification['subject'] ) : '', 'email_body' => isset( $notification['email_body'] ) ? wp_kses_post( $notification['email_body'] ) : '', 'from_name' => isset( $notification['from_name'] ) ? sanitize_text_field( $notification['from_name'] ) : '', 'from_email' => isset( $notification['from_email'] ) ? sanitize_text_field( $notification['from_email'] ) : '', 'reply_to' => isset( $notification['reply_to'] ) ? sanitize_text_field( $notification['reply_to'] ) : '', 'trigger' => isset( $notification['trigger'] ) && in_array( $notification['trigger'], apply_filters( 'suredonation_email_notification_triggers', [ 'all', 'donation_completed', 'donation_processing', 'donation_failed', 'refund_processed' ] ), true ) ? $notification['trigger'] : 'all', ]; } $encoded = wp_json_encode( $sanitized ); return is_string( $encoded ) ? $encoded : ''; } /** * Sanitize form confirmation settings. * * @param string $value JSON string of confirmation settings. * @return string Sanitized JSON string. * @since 1.0.0 */ public function sanitize_confirmation_settings( $value ) { $fallback_data = [ 'confirmation_type' => 'same page', 'message' => '', 'submission_action' => 'hide form', 'custom_url' => '', 'page_url' => '', ]; $fallback = (string) wp_json_encode( $fallback_data ); if ( empty( $value ) || ! is_string( $value ) ) { return $fallback; } $data = json_decode( $value, true ); if ( ! is_array( $data ) ) { return $fallback; } $allowed_types = [ 'same page', 'different page', 'custom url' ]; $allowed_actions = [ 'hide form', 'reset form' ]; $message = isset( $data['message'] ) ? wp_kses_post( $data['message'] ) : ''; $sanitized = [ 'confirmation_type' => isset( $data['confirmation_type'] ) && in_array( $data['confirmation_type'], $allowed_types, true ) ? $data['confirmation_type'] : 'same page', 'message' => $message, 'submission_action' => isset( $data['submission_action'] ) && in_array( $data['submission_action'], $allowed_actions, true ) ? $data['submission_action'] : 'hide form', 'custom_url' => isset( $data['custom_url'] ) ? esc_url_raw( $data['custom_url'] ) : '', 'page_url' => isset( $data['page_url'] ) ? esc_url_raw( $data['page_url'] ) : '', ]; $encoded = wp_json_encode( $sanitized ); return is_string( $encoded ) ? $encoded : $fallback; } }