PluginProbe ʕ •ᴥ•ʔ
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.1
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.1
2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8 0.0.9 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.1.2 1.10.0 1.10.1 1.11.0 1.12.0 1.12.1 1.12.2 1.12.3 1.13.0 1.13.1 1.13.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.8.0 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.5.0 2.5.2 2.6.0
sureforms / inc / generate-form-markup.php
sureforms / inc Last commit date
abilities 1 month ago admin 3 months ago ai-form-builder 1 month ago blocks 2 months ago compatibility 2 months ago database 2 months ago email 5 months ago fields 2 months ago global-settings 1 month ago lib 1 month ago migrator 2 months ago page-builders 2 months ago payments 1 month ago single-form-settings 2 months ago traits 2 months ago activator.php 1 year ago admin-ajax.php 2 months ago background-process.php 9 months ago create-new-form.php 3 months ago duplicate-form.php 3 months ago entries.php 2 months ago events-scheduler.php 2 years ago export.php 3 months ago field-validation.php 1 month ago form-restriction.php 2 months ago form-styling.php 5 months ago form-submit.php 2 months ago forms-data.php 5 months ago frontend-assets.php 1 month ago generate-form-markup.php 2 months ago gutenberg-hooks.php 2 months ago helper.php 2 months ago learn.php 4 months ago onboarding.php 2 months ago post-types.php 2 months ago rest-api.php 1 month ago smart-tags.php 4 months ago submit-token.php 5 months ago translatable.php 1 month ago updater-callbacks.php 1 year ago updater.php 1 year ago
generate-form-markup.php
1036 lines
1 <?php
2 /**
3 * Sureforms Generate Form Class file.
4 *
5 * @package sureforms.
6 * @since 0.0.1
7 */
8
9 namespace SRFM\Inc;
10
11 use SRFM\Inc\Compatibility\Multilingual\Multilingual_Manager;
12 use SRFM\Inc\Compatibility\Multilingual\String_Translator;
13 use SRFM\Inc\Traits\Get_Instance;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 /**
20 * Load Defaults Class.
21 *
22 * @since 0.0.1
23 */
24 class Generate_Form_Markup {
25 use Get_Instance;
26
27 /**
28 * Current block attributes for the form being rendered.
29 * Used by child blocks (like inline button) to access parent form's embed styling.
30 *
31 * @var array<string,mixed>
32 * @since 2.7.0
33 */
34 private static $current_block_attrs = [];
35
36 /**
37 * Constructor
38 *
39 * @since 0.0.1
40 */
41 public function __construct() {
42 add_action( 'rest_api_init', [ $this, 'register_custom_endpoint' ] );
43 }
44
45 /**
46 * Get the current block attributes.
47 *
48 * @return array<string,mixed>
49 * @since 2.7.0
50 */
51 public static function get_current_block_attrs() {
52 return self::$current_block_attrs;
53 }
54
55 /**
56 * Add custom API Route to generate form markup.
57 *
58 * @return void
59 * @since 0.0.1
60 */
61 public function register_custom_endpoint() {
62 register_rest_route(
63 'sureforms/v1',
64 '/generate-form-markup',
65 [
66 'methods' => 'GET',
67 'callback' => [ $this, 'get_form_markup' ],
68 'permission_callback' => '__return_true',
69 ]
70 );
71 }
72
73 /**
74 * Handle Form status
75 *
76 * @param int|string $id Contains form ID.
77 * @param bool $show_title_current_page Boolean to srfm-show/srfm-hide form title.
78 * @param string $sf_classname additional class_name.
79 * @param string $post_type Contains post type.
80 * @param bool $do_blocks Boolean to enable/disable parsing dynamic blocks.
81 * @param array<mixed> $block_attrs Block attributes for per-embed styling.
82 *
83 * @return string|false
84 * @since 0.0.1
85 */
86 public static function get_form_markup( $id, $show_title_current_page = true, $sf_classname = '', $post_type = 'post', $do_blocks = false, $block_attrs = [] ) {
87 if ( isset( $_GET['id'] ) && isset( $_GET['srfm_form_markup_nonce'] ) ) {
88 $nonce = isset( $_GET['srfm_form_markup_nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['srfm_form_markup_nonce'] ) ) : '';
89 $id = wp_verify_nonce( $nonce, 'srfm_form_markup' ) && ! empty( $_GET['srfm_form_markup_nonce'] ) ? Helper::get_integer_value( sanitize_text_field( wp_unslash( $_GET['id'] ) ) ) : '';
90 } else {
91 $id = Helper::get_integer_value( $id );
92 }
93
94 // Check for any form restrictions.
95 $form_id = Helper::get_integer_value( $id );
96 if ( Form_Restriction::is_form_restricted( $form_id ) ) {
97 return Form_Restriction::display_form_restriction_message( $form_id );
98 }
99
100 // Store block_attrs for child blocks (like inline button) to access.
101 self::$current_block_attrs = $block_attrs;
102
103 do_action( 'srfm_localize_conditional_logic_data', $id );
104 $post = get_post( Helper::get_integer_value( $id ) );
105
106 $content = '';
107 $form_blocks = [];
108
109 $active_plugins = Helper::get_array_value( get_option( 'active_plugins', [] ) );
110 $is_learndash_active = in_array( 'sfwd-lms/sfwd_lms.php', $active_plugins, true );
111
112 if ( $is_learndash_active ) {
113 $do_blocks = true;
114 }
115
116 if ( $post && ! empty( $post->post_content ) ) {
117 // Filter to get the post content for the form.
118 $post_content = apply_filters( 'srfm_get_form_post_content', $post->post_content, $id );
119
120 // Pre-translate block-attribute strings (labels, placeholders, options, etc.)
121 // before rendering, so the visitor's chosen language is honoured. Returns the
122 // translated markup plus the parsed top-level blocks so we can derive the block
123 // count without re-parsing the rendered HTML. No-op when no provider is active.
124 [ $post_content, $form_blocks ] = String_Translator::get_instance()->translate_form_content_with_blocks( (int) $id, Helper::get_string_value( $post_content ), $post );
125
126 if ( ! empty( $do_blocks ) ) {
127 $content = do_blocks( $post_content );
128 } else {
129 $content = apply_filters( 'the_content', $post_content ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- wordpress hook
130 }
131 }
132
133 // Reuse the translator's parse on the multilingual path; otherwise parse once here
134 // (single-language path). Either way the content is parsed exactly once, never three times.
135 $form_blocks = ! empty( $form_blocks ) ? $form_blocks : parse_blocks( $content );
136 $block_count = count( $form_blocks );
137 $current_post_type = get_post_type();
138
139 // load all the frontend assets.
140 Frontend_Assets::enqueue_scripts_and_styles();
141
142 ob_start();
143 if ( '' !== $id && 0 !== $block_count ) {
144
145 // Create unique container ID using blockId if available (for multiple embeds of same form).
146 // Base class (without blockId) is needed for JS compatibility - frontend.js and phone.js use form-id attribute to construct selectors.
147 $base_container_class = 'srfm-form-container-' . Helper::get_string_value( $id );
148 $block_id_suffix = ! empty( $block_attrs['blockId'] ) ? '-' . Helper::get_string_value( $block_attrs['blockId'] ) : '';
149 $container_id = $base_container_class . $block_id_suffix;
150 $form_styling = get_post_meta( $id, '_srfm_forms_styling', true );
151 $form_styling = ! empty( $form_styling ) && is_array( $form_styling ) ? $form_styling : [];
152
153 // Apply per-embed styling customization when formTheme is not 'inherit'.
154 if ( Form_Styling::has_custom_styling( $block_attrs ) ) {
155 $form_styling = Form_Styling::map_block_attrs_to_styling( $form_styling, $block_attrs );
156 }
157 // Background Settings.
158 $bg_type = $form_styling['bg_type'] ?? 'color';
159 $bg_color = $form_styling['bg_color'] ?? '';
160 $bg_image = $form_styling['bg_image'] ?? '';
161 $bg_image_position = $form_styling['bg_image_position'] ?? [];
162 $bg_image_attachment = $form_styling['bg_image_attachment'] ?? 'scroll';
163 $bg_image_repeat = $form_styling['bg_image_repeat'] ?? 'no-repeat';
164 $bg_image_size = $form_styling['bg_image_size'] ?? 'cover';
165 $bg_image_size_custom = $form_styling['bg_image_size_custom'] ?? 100;
166 $bg_image_size_custom_unit = $form_styling['bg_image_size_custom_unit'] ?? '%';
167 $bg_gradient = $form_styling['bg_gradient'] ?? 'linear-gradient(90deg, #FFC9B2 0%, #C7CBFF 100%)';
168 $gradient_type = $form_styling['gradient_type'] ?? 'basic'; // Basic or advanced.
169 $is_advanced_gradient = 'advanced' === $gradient_type ? true : false;
170 $bg_gradient_type = $is_advanced_gradient && isset( $form_styling['bg_gradient_type'] ) ? $form_styling['bg_gradient_type'] : 'linear'; // linear or radial gradient.
171 $bg_gradient_color_1 = $is_advanced_gradient && isset( $form_styling['bg_gradient_color_1'] ) ? $form_styling['bg_gradient_color_1'] : '';
172 $bg_gradient_color_2 = $is_advanced_gradient && isset( $form_styling['bg_gradient_color_2'] ) ? $form_styling['bg_gradient_color_2'] : '';
173 $bg_gradient_location_1 = $is_advanced_gradient && isset( $form_styling['bg_gradient_location_1'] ) ? $form_styling['bg_gradient_location_1'] : '';
174 $bg_gradient_location_2 = $is_advanced_gradient && isset( $form_styling['bg_gradient_location_2'] ) ? $form_styling['bg_gradient_location_2'] : '';
175 $bg_gradient_angle = $is_advanced_gradient && isset( $form_styling['bg_gradient_angle'] ) ? $form_styling['bg_gradient_angle'] : '';
176 // Overlay Settings.
177 $overlay_type = $form_styling['bg_gradient_overlay_type'] ?? '';
178 $overlay_size = $form_styling['bg_overlay_size'] ?? 'cover';
179 $overlay_opacity = $form_styling['bg_overlay_opacity'] ?? 1;
180 $overlay_color = $form_styling['bg_image_overlay_color'] ?? '';
181 $overlay_image = $form_styling['bg_overlay_image'] ?? '';
182 $overlay_position = $form_styling['bg_overlay_position'] ?? [];
183 $overlay_attachment = $form_styling['bg_overlay_attachment'] ?? 'scroll';
184 $overlay_repeat = $form_styling['bg_overlay_repeat'] ?? 'no-repeat';
185 $overlay_blend_mode = $form_styling['bg_overlay_blend_mode'] ?? 'normal';
186 // Gradient Overlay.
187 $bg_overlay_gradient = $form_styling['bg_overlay_gradient'] ?? 'linear-gradient(90deg, #FFC9B2 0%, #C7CBFF 100%)';
188 $overlay_gradient_type = $form_styling['overlay_gradient_type'] ?? 'basic'; // Basic or advanced.
189 $is_overlay_advanced_gradient = 'advanced' === $overlay_gradient_type ? true : false;
190 $bg_overlay_gradient_type = $is_overlay_advanced_gradient && isset( $form_styling['bg_overlay_gradient_type'] ) ? $form_styling['bg_overlay_gradient_type'] : 'linear';
191 $bg_overlay_gradient_color_1 = $is_overlay_advanced_gradient && isset( $form_styling['bg_overlay_gradient_color_1'] ) ? $form_styling['bg_overlay_gradient_color_1'] : '';
192 $bg_overlay_gradient_color_2 = $is_overlay_advanced_gradient && isset( $form_styling['bg_overlay_gradient_color_2'] ) ? $form_styling['bg_overlay_gradient_color_2'] : '';
193 $bg_overlay_gradient_location_1 = $is_overlay_advanced_gradient && isset( $form_styling['bg_overlay_gradient_location_1'] ) ? $form_styling['bg_overlay_gradient_location_1'] : '';
194 $bg_overlay_gradient_location_2 = $is_overlay_advanced_gradient && isset( $form_styling['bg_overlay_gradient_location_2'] ) ? $form_styling['bg_overlay_gradient_location_2'] : '';
195 $bg_overlay_gradient_angle = $is_overlay_advanced_gradient && isset( $form_styling['bg_overlay_gradient_angle'] ) ? $form_styling['bg_overlay_gradient_angle'] : '';
196 // Embed Form Settings.
197 $form = [
198 // Padding.
199 'padding_top' => isset( $form_styling['form_padding_top'] ) ? floatval( $form_styling['form_padding_top'] ) : 0,
200 'padding_right' => isset( $form_styling['form_padding_right'] ) ? floatval( $form_styling['form_padding_right'] ) : 0,
201 'padding_bottom' => isset( $form_styling['form_padding_bottom'] ) ? floatval( $form_styling['form_padding_bottom'] ) : 0,
202 'padding_left' => isset( $form_styling['form_padding_left'] ) ? floatval( $form_styling['form_padding_left'] ) : 0,
203 'padding_unit' => isset( $form_styling['form_padding_unit'] ) ? Helper::get_string_value( $form_styling['form_padding_unit'] ) : 'px',
204 // Border Radius.
205 'border_radius_top' => isset( $form_styling['form_border_radius_top'] ) ? floatval( $form_styling['form_border_radius_top'] ) : 0,
206 'border_radius_right' => isset( $form_styling['form_border_radius_right'] ) ? floatval( $form_styling['form_border_radius_right'] ) : 0,
207 'border_radius_bottom' => isset( $form_styling['form_border_radius_bottom'] ) ? floatval( $form_styling['form_border_radius_bottom'] ) : 0,
208 'border_radius_left' => isset( $form_styling['form_border_radius_left'] ) ? floatval( $form_styling['form_border_radius_left'] ) : 0,
209 'border_radius_unit' => isset( $form_styling['form_border_radius_unit'] ) ? Helper::get_string_value( $form_styling['form_border_radius_unit'] ) : 'px',
210 ];
211 // Instant Form Settings.
212 $instant_form = [
213 // Padding.
214 'padding_top' => isset( $form_styling['instant_form_padding_top'] ) ? floatval( $form_styling['instant_form_padding_top'] ) : 32,
215 'padding_right' => isset( $form_styling['instant_form_padding_right'] ) ? floatval( $form_styling['instant_form_padding_right'] ) : 32,
216 'padding_bottom' => isset( $form_styling['instant_form_padding_bottom'] ) ? floatval( $form_styling['instant_form_padding_bottom'] ) : 32,
217 'padding_left' => isset( $form_styling['instant_form_padding_left'] ) ? floatval( $form_styling['instant_form_padding_left'] ) : 32,
218 'padding_unit' => isset( $form_styling['instant_form_padding_unit'] ) ? Helper::get_string_value( $form_styling['instant_form_padding_unit'] ) : 'px',
219 // Border Radius.
220 'border_radius_top' => isset( $form_styling['instant_form_border_radius_top'] ) ? floatval( $form_styling['instant_form_border_radius_top'] ) : 12,
221 'border_radius_right' => isset( $form_styling['instant_form_border_radius_right'] ) ? floatval( $form_styling['instant_form_border_radius_right'] ) : 12,
222 'border_radius_bottom' => isset( $form_styling['instant_form_border_radius_bottom'] ) ? floatval( $form_styling['instant_form_border_radius_bottom'] ) : 12,
223 'border_radius_left' => isset( $form_styling['instant_form_border_radius_left'] ) ? floatval( $form_styling['instant_form_border_radius_left'] ) : 12,
224 'border_radius_unit' => isset( $form_styling['instant_form_border_radius_unit'] ) ? Helper::get_string_value( $form_styling['instant_form_border_radius_unit'] ) : 'px',
225 ];
226
227 if ( 'custom' === $overlay_size ) {
228 $bg_overlay_custom_size = $form_styling['bg_overlay_custom_size'] ?? 100;
229 $bg_overlay_custom_size_unit = $form_styling['bg_overlay_custom_size_unit'] ?? '%';
230 $overlay_size = $bg_overlay_custom_size . $bg_overlay_custom_size_unit;
231 }
232
233 $background_classes = apply_filters( 'srfm_add_background_classes', Helper::get_background_classes( $bg_type, $overlay_type, $bg_image ), $id, $block_attrs );
234
235 $neve_theme_margin_class_name = 'srfm-neve-theme-add-margin-bottom';
236 $theme_name = wp_get_theme()->get( 'Name' );
237
238 $form_classes = [
239 'srfm-form-container',
240 $base_container_class, // Base class for JS compatibility (frontend.js, phone.js).
241 ! empty( $block_id_suffix ) ? $container_id : '', // Unique class for CSS scoping when blockId exists.
242 $sf_classname,
243 'Neve' === $theme_name ? $neve_theme_margin_class_name : '', // compatibility with Neve theme for margin between main content and footer.
244 $background_classes,
245 ];
246
247 $custom_added_classes = Helper::get_meta_value( $id, '_srfm_additional_classes' );
248 if ( ! empty( $custom_added_classes ) && is_string( $custom_added_classes ) ) {
249 $custom_added_classes = explode( ' ', $custom_added_classes );
250 foreach ( $custom_added_classes as $class ) {
251 if ( Helper::is_valid_css_class_name( $class ) ) {
252 $form_classes[] = $class;
253 }
254 }
255 }
256
257 $page_break_settings = defined( 'SRFM_PRO_VER' ) && apply_filters( 'srfm_use_page_break_layout', true ) ? get_post_meta( $id, '_srfm_page_break_settings', true ) : [];
258 $page_break_settings = ! empty( $page_break_settings ) && is_array( $page_break_settings ) ? $page_break_settings : [];
259 $is_page_break = ! empty( $page_break_settings ) ? $page_break_settings['is_page_break'] : false;
260 $page_break_progress_type = ! empty( $page_break_settings ) ? $page_break_settings['progress_indicator_type'] : 'none';
261 $form_confirmation = get_post_meta( $id, '_srfm_form_confirmation' );
262 $confirmation_type = '';
263 $submission_action = '';
264 $success_url = '';
265 if ( is_array( $form_confirmation ) && isset( $form_confirmation[0][0] ) ) {
266 $confirmation_data = $form_confirmation[0][0];
267 $page_url = $confirmation_data['page_url'] ?? '';
268 $custom_url = $confirmation_data['custom_url'] ?? '';
269 $confirmation_type = $confirmation_data['confirmation_type'] ?? '';
270 $submission_action = $confirmation_data['submission_action'] ?? '';
271 $success_url = '';
272 if ( 'different page' === $confirmation_type ) {
273 $success_url = $page_url;
274 } elseif ( 'custom url' === $confirmation_type ) {
275 $success_url = $custom_url;
276 }
277 }
278
279 // Submit button.
280 $button_text = Helper::get_meta_value( $id, '_srfm_submit_button_text' );
281 $button_text = String_Translator::get_instance()->translate_submit_button( (int) $id, Helper::get_string_value( $button_text ) );
282 $submit_button_alignment = ! empty( $form_styling['submit_button_alignment'] ) ? $form_styling['submit_button_alignment'] : 'left';
283
284 if ( is_rtl() && ( 'left' === $submit_button_alignment || 'right' === $submit_button_alignment ) ) {
285 $submit_button_alignment = 'right' === $submit_button_alignment ? 'left' : 'right';
286 }
287
288 $btn_from_theme = Helper::get_meta_value( $id, '_srfm_inherit_theme_button' );
289 $is_inline_button = apply_filters( 'srfm_is_inline_button', Helper::get_meta_value( $id, '_srfm_is_inline_button' ) );
290 $security_type = Helper::get_meta_value( $id, '_srfm_captcha_security_type' );
291 $form_custom_css_meta = Helper::get_meta_value( $id, '_srfm_form_custom_css' );
292 $custom_css = ! empty( $form_custom_css_meta ) && is_string( $form_custom_css_meta ) ? $form_custom_css_meta : '';
293
294 $full = 'justify' === $submit_button_alignment ? true : false;
295 $recaptcha_version = 'g-recaptcha' === $security_type ? Helper::get_meta_value( $id, '_srfm_form_recaptcha' ) : '';
296 $srfm_cf_appearance_mode = '';
297 $srfm_cf_turnstile_site_key = '';
298 $srfm_hcaptcha_site_key = '';
299
300 $google_captcha_site_key = '';
301
302 if ( 'none' !== $security_type ) {
303 $global_setting_options = get_option( 'srfm_security_settings_options' );
304 } else {
305 $global_setting_options = [];
306 }
307
308 if ( is_array( $global_setting_options ) && 'cf-turnstile' === $security_type ) {
309 $srfm_cf_turnstile_site_key = $global_setting_options['srfm_cf_turnstile_site_key'] ?? '';
310 $srfm_cf_appearance_mode = $global_setting_options['srfm_cf_appearance_mode'] ?? 'auto';
311 }
312
313 if ( is_array( $global_setting_options ) && 'hcaptcha' === $security_type ) {
314 $srfm_hcaptcha_site_key = $global_setting_options['srfm_hcaptcha_site_key'] ?? '';
315 }
316
317 if ( is_array( $global_setting_options ) && 'g-recaptcha' === $security_type ) {
318 switch ( $recaptcha_version ) {
319 case 'v2-checkbox':
320 $google_captcha_site_key = $global_setting_options['srfm_v2_checkbox_site_key'] ?? '';
321 break;
322 case 'v2-invisible':
323 $google_captcha_site_key = $global_setting_options['srfm_v2_invisible_site_key'] ?? '';
324 break;
325 case 'v3-reCAPTCHA':
326 $google_captcha_site_key = $global_setting_options['srfm_v3_site_key'] ?? '';
327 break;
328 default:
329 break;
330 }
331 }
332
333 // Ensure $google_captcha_site_key is not empty, and if not, trim any leading or trailing whitespace.
334 $google_captcha_site_key = is_string( $google_captcha_site_key ) && ! empty( $google_captcha_site_key ) ? trim( $google_captcha_site_key ) : '';
335
336 $primary_color = $form_styling['primary_color'] ?? '';
337 $help_color_var = $form_styling['text_color'] ?? '';
338 $label_text_color = $form_styling['text_color_on_primary'] ?? '';
339 $field_spacing = $form_styling['field_spacing'] ?? 'small';
340
341 // New colors.
342
343 $primary_color_var = $primary_color ? $primary_color : '#046bd2';
344 $label_text_color_var = $label_text_color ? $label_text_color : '#111827';
345
346 $selected_size = Helper::get_css_vars( $field_spacing );
347
348 $should_show_submit_button = apply_filters(
349 'srfm_show_submit_button',
350 0 !== $block_count && ! $is_inline_button || $is_page_break,
351 $id
352 );
353
354 if ( ! $should_show_submit_button ) {
355 $form_classes[] = 'srfm-submit-button-hidden';
356 }
357
358 ?>
359 <div class="<?php echo esc_attr( implode( ' ', array_filter( $form_classes ) ) ); ?>">
360 <style>
361 /* Need to check and remove the input variables related to the Style Tab. */
362 <?php echo esc_html( ".{$container_id}" ); ?> {
363 /* New test variables */
364 --srfm-color-scheme-primary: <?php echo esc_html( $primary_color_var ); ?>;
365 --srfm-color-scheme-text-on-primary: <?php echo esc_html( $label_text_color_var ); ?>;
366 --srfm-color-scheme-text: <?php echo esc_html( $help_color_var ); ?>;
367 --srfm-quill-editor-color: <?php echo esc_html( $primary_color_var ); ?>;
368
369 --srfm-color-input-label: <?php echo esc_html( $help_color_var ); ?>;
370 --srfm-color-input-description: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.65 );
371 --srfm-color-input-placeholder: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.5 );
372 --srfm-color-input-text: <?php echo esc_html( $help_color_var ); ?>;
373 --srfm-color-input-prefix: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.65 );
374 --srfm-color-input-background: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.02 );
375 --srfm-color-input-background-hover: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.05 );
376 --srfm-color-input-background-disabled: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.07 );
377 --srfm-color-input-border: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.25 );
378 --srfm-color-input-border-disabled: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.15 );
379 --srfm-color-multi-choice-svg: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.7 );
380 --srfm-color-input-border-hover: hsl( from <?php echo esc_html( $primary_color_var ); ?> h s l / 0.65 );
381 --srfm-color-input-border-focus-glow: hsl( from <?php echo esc_html( $primary_color_var ); ?> h s l / 0.15 );
382 --srfm-color-input-selected: hsl( from <?php echo esc_html( $primary_color_var ); ?> h s l / 0.1 );
383 --srfm-btn-color-hover: hsl( from <?php echo esc_html( $primary_color_var ); ?> h s l / 0.9 );
384 --srfm-btn-color-disabled: hsl( from <?php echo esc_html( $primary_color_var ); ?> h s l / 0.25 );
385
386 /* Dropdown Variables */
387 --srfm-dropdown-input-background-hover: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.05 );
388 --srfm-dropdown-option-background-hover: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.10 );
389 --srfm-dropdown-option-background-selected: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.05 );
390 --srfm-dropdown-option-selected-icon: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.65 );
391 --srfm-dropdown-option-text-color: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.80 );
392 --srfm-dropdown-option-selected-text: <?php echo esc_html( $help_color_var ); ?>;
393 --srfm-dropdown-badge-background: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.05 );
394 --srfm-dropdown-badge-background-hover: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.10 );
395 --srfm-dropdown-menu-border-color: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.10 );
396 --srfm-dropdown-placeholder-color: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.50 );
397 --srfm-dropdown-icon-color: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.65 );
398 --srfm-dropdown-icon-disabled: hsl( from <?php echo esc_html( $help_color_var ); ?> h s l / 0.25 );
399
400 /* Background Control Variables */
401 <?php
402 // Form Styles.
403 $styling_vars = [
404 // Instant Form Padding.
405 '--srfm-instant-form-padding-top' => sanitize_text_field( "{$instant_form['padding_top']}{$instant_form['padding_unit']}" ),
406 '--srfm-instant-form-padding-right' => sanitize_text_field( "{$instant_form['padding_right']}{$instant_form['padding_unit']}" ),
407 '--srfm-instant-form-padding-bottom' => sanitize_text_field( "{$instant_form['padding_bottom']}{$instant_form['padding_unit']}" ),
408 '--srfm-instant-form-padding-left' => sanitize_text_field( "{$instant_form['padding_left']}{$instant_form['padding_unit']}" ),
409 // Instant Form Border Radius.
410 '--srfm-instant-form-border-radius-top' => sanitize_text_field( "{$instant_form['border_radius_top']}{$instant_form['border_radius_unit']}" ),
411 '--srfm-instant-form-border-radius-right' => sanitize_text_field( "{$instant_form['border_radius_right']}{$instant_form['border_radius_unit']}" ),
412 '--srfm-instant-form-border-radius-bottom' => sanitize_text_field( "{$instant_form['border_radius_bottom']}{$instant_form['border_radius_unit']}" ),
413 '--srfm-instant-form-border-radius-left' => sanitize_text_field( "{$instant_form['border_radius_left']}{$instant_form['border_radius_unit']}" ),
414 // Embed Form Padding.
415 '--srfm-form-padding-top' => sanitize_text_field( "{$form['padding_top']}{$form['padding_unit']}" ),
416 '--srfm-form-padding-right' => sanitize_text_field( "{$form['padding_right']}{$form['padding_unit']}" ),
417 '--srfm-form-padding-bottom' => sanitize_text_field( "{$form['padding_bottom']}{$form['padding_unit']}" ),
418 '--srfm-form-padding-left' => sanitize_text_field( "{$form['padding_left']}{$form['padding_unit']}" ),
419 // Embed Form Border Radius.
420 '--srfm-form-border-radius-top' => sanitize_text_field( "{$form['border_radius_top']}{$form['border_radius_unit']}" ),
421 '--srfm-form-border-radius-right' => sanitize_text_field( "{$form['border_radius_right']}{$form['border_radius_unit']}" ),
422 '--srfm-form-border-radius-bottom' => sanitize_text_field( "{$form['border_radius_bottom']}{$form['border_radius_unit']}" ),
423 '--srfm-form-border-radius-left' => sanitize_text_field( "{$form['border_radius_left']}{$form['border_radius_unit']}" ),
424 ];
425 // Background Styles.
426 if ( 'image' === $bg_type && ! empty( $bg_image ) ) {
427 $bg_size_merged = 'custom' === $bg_image_size ? "{$bg_image_size_custom}{$bg_image_size_custom_unit}" : $bg_image_size;
428 $styling_vars += [
429 '--srfm-bg-image' => 'url(' . esc_url_raw( $bg_image ) . ')',
430 '--srfm-bg-position' => sanitize_text_field(
431 ( ( ! empty( $bg_image_position['x'] ) ? $bg_image_position['x'] : 0.5 ) * 100 ) . '% ' .
432 ( ( ! empty( $bg_image_position['y'] ) ? $bg_image_position['y'] : 0.5 ) * 100 ) . '% '
433 ),
434 '--srfm-bg-attachment' => sanitize_text_field( $bg_image_attachment ),
435 '--srfm-bg-repeat' => sanitize_text_field( $bg_image_repeat ),
436 '--srfm-bg-size' => sanitize_text_field( $bg_size_merged ),
437 ];
438 } elseif ( 'color' === $bg_type && ! empty( $bg_color ) ) {
439 $styling_vars['--srfm-bg-color'] = sanitize_text_field( $bg_color );
440 } elseif ( 'gradient' === $bg_type && ! empty( $bg_gradient ) ) {
441 if ( $is_advanced_gradient ) {
442 $bg_gradient = Helper::get_gradient_css( $bg_gradient_type, $bg_gradient_color_1, $bg_gradient_color_2, $bg_gradient_location_1, $bg_gradient_location_2, $bg_gradient_angle );
443 }
444 $styling_vars['--srfm-bg-gradient'] = sanitize_text_field( $bg_gradient );
445 }
446 // Overlay Variables.
447 if ( 'image' === $bg_type && 'image' === $overlay_type && ! empty( $overlay_image ) ) {
448 $styling_vars += [
449 '--srfm-bg-overlay-image' => 'url(' . esc_url_raw( $overlay_image ) . ')',
450 '--srfm-bg-overlay-position' => sanitize_text_field(
451 ( ( ! empty( $overlay_position['x'] ) ? $overlay_position['x'] : 0.5 ) * 100 ) . '% ' .
452 ( ( ! empty( $overlay_position['y'] ) ? $overlay_position['y'] : 0.5 ) * 100 ) . '%'
453 ),
454 '--srfm-bg-overlay-attachment' => sanitize_text_field( $overlay_attachment ),
455 '--srfm-bg-overlay-repeat' => sanitize_text_field( $overlay_repeat ),
456 '--srfm-bg-overlay-size' => sanitize_text_field( $overlay_size ),
457 '--srfm-bg-overlay-blend-mode' => sanitize_text_field( $overlay_blend_mode ),
458 ];
459 } elseif ( 'image' === $bg_type && 'color' === $overlay_type && ! empty( $overlay_color ) ) {
460 $styling_vars += [
461 '--srfm-bg-overlay-color' => sanitize_text_field( $overlay_color ),
462 ];
463 } elseif ( 'image' === $bg_type && 'gradient' === $overlay_type && ! empty( $bg_overlay_gradient ) ) {
464 if ( $is_overlay_advanced_gradient ) {
465 $bg_overlay_gradient = Helper::get_gradient_css( $bg_overlay_gradient_type, $bg_overlay_gradient_color_1, $bg_overlay_gradient_color_2, $bg_overlay_gradient_location_1, $bg_overlay_gradient_location_2, $bg_overlay_gradient_angle );
466 }
467 $styling_vars += [
468 '--srfm-bg-overlay-gradient' => sanitize_text_field( $bg_overlay_gradient ),
469 ];
470 }
471 $styling_vars['--srfm-bg-overlay-opacity'] = floatval( $overlay_opacity );
472 // Output the CSS variables.
473 foreach ( $styling_vars as $key => $value ) {
474 echo esc_html( Helper::get_string_value( $key ) ) . ': ' . esc_html( Helper::get_string_value( $value ) ) . ';';
475 }
476 ?>
477 <?php
478 // Echo the CSS variables for the form according to the field spacing selected.
479 foreach ( $selected_size as $variable => $value ) {
480 echo esc_html( Helper::get_string_value( $variable ) ) . ': ' . esc_html( Helper::get_string_value( $value ) ) . ';';
481 }
482 do_action(
483 'srfm_form_css_variables',
484 [
485 'id' => $id,
486 'primary_color' => $primary_color_var,
487 'help_color' => $help_color_var,
488 'form_styling' => $form_styling,
489 'block_attrs' => $block_attrs,
490 ]
491 );
492 // echo custom css on page/post.
493 if ( 'sureforms_form' !== $current_post_type ) {
494 echo wp_kses_post( $custom_css );
495 }
496 ?>
497 }
498 </style>
499 <?php
500 if ( 'sureforms_form' !== $current_post_type && true === $show_title_current_page ) {
501 $title = ! empty( get_the_title( (int) $id ) ) ? get_the_title( (int) $id ) : '';
502 ?>
503 <h2 class="srfm-form-title"><?php echo esc_html( $title ); ?></h2>
504 <?php
505 }
506
507 // Password protected form check.
508 if ( $post && post_password_required( $post ) ) {
509 // Define allowed HTML tags for password form output.
510 $allowed_password_form_tags = [
511 'form' => [
512 'action' => true,
513 'method' => true,
514 'class' => true,
515 'id' => true,
516 ],
517 'label' => [
518 'for' => true,
519 'class' => true,
520 ],
521 'input' => [
522 'type' => true,
523 'name' => true,
524 'id' => true,
525 'class' => true,
526 'value' => true,
527 'size' => true,
528 'placeholder' => true,
529 'required' => true,
530 ],
531 'p' => [
532 'class' => true,
533 'style' => true,
534 ],
535 'button' => [
536 'type' => true,
537 'name' => true,
538 'class' => true,
539 'id' => true,
540 'style' => true,
541 ],
542 'div' => [
543 'class' => true,
544 'id' => true,
545 'style' => true,
546 ],
547 'span' => [
548 'class' => true,
549 'aria-hidden' => true,
550 ],
551 'svg' => [
552 'xmlns' => true,
553 'width' => true,
554 'height' => true,
555 'viewBox' => true,
556 'fill' => true,
557 ],
558 'path' => [
559 'd' => true,
560 'stroke' => true,
561 'stroke-opacity' => true,
562 'stroke-width' => true,
563 'stroke-linecap' => true,
564 'stroke-linejoin' => true,
565 ],
566 ];
567 echo wp_kses( get_the_password_form( $post ), $allowed_password_form_tags );
568 ?>
569 </div>
570 <?php
571 self::$current_block_attrs = [];
572 return ob_get_clean();
573 }
574 $submit_token = Submit_Token::generate( (int) $id );
575
576 ?>
577 <form method="post" enctype="multipart/form-data" id="srfm-form-<?php echo esc_attr( Helper::get_string_value( $id ) ); ?>" class="srfm-form <?php echo esc_attr( 'sureforms_form' === $post_type ? 'srfm-single-form ' : '' ); ?>"
578 form-id="<?php echo esc_attr( Helper::get_string_value( $id ) ); ?>" after-submission="<?php echo esc_attr( $submission_action ); ?>" message-type="<?php echo esc_attr( $confirmation_type ? $confirmation_type : 'same page' ); ?>" success-url="<?php echo esc_attr( $success_url ? $success_url : '' ); ?>" ajaxurl="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>" data-submit-token="<?php echo esc_attr( $submit_token ); ?>"
579 >
580 <?php
581 // Submission security is handled via the HMAC token in data-submit-token.
582 $global_setting_options = get_option( 'srfm_security_settings_options' );
583 $honeypot_spam = is_array( $global_setting_options ) && isset( $global_setting_options['srfm_honeypot'] ) ? $global_setting_options['srfm_honeypot'] : '';
584
585 if ( $is_page_break && 'none' !== $page_break_progress_type ) {
586 do_action( 'srfm_page_break_header', $id );
587 }
588 ?>
589
590 <input type="hidden" value="<?php echo esc_attr( Helper::get_string_value( $id ) ); ?>" name="form-id">
591 <?php
592 /*
593 * Submission language. Captured client-side because the REST submit endpoint
594 * loses WPML's URL-based language context. The value is baked into the markup
595 * at render time, so accurate entry-language tagging requires the page cache to
596 * be language-aware (the default for WPML's language-per-URL modes). At submit
597 * time the server re-validates this value against the active language list and
598 * falls back to its own current_language() when it can't be confirmed
599 * (see Form_Submit::is_known_language()), so a stale/forged value is never
600 * trusted blindly.
601 */
602 ?>
603 <input type="hidden" value="<?php echo esc_attr( Multilingual_Manager::get_instance()->provider()->current_language() ); ?>" name="srfm-form-language">
604 <input type="hidden" value="" name="srfm-sender-email-field" id="srfm-sender-email">
605 <input type="hidden" value="<?php echo esc_attr( Helper::get_string_value( $is_page_break ) ); ?>" id="srfm-page-break">
606 <?php if ( $honeypot_spam ) { ?>
607 <input type="hidden" value="" name="srfm-honeypot-field">
608 <?php
609 }
610 self::common_error_message( 'head' );
611 if ( $is_page_break ) {
612 do_action( 'srfm_page_break_pagination', $post, $id );
613 } elseif ( ! apply_filters( 'srfm_use_custom_field_content', false ) ) {
614 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Content is filtered and sanitized by WordPress core blocks and filters.
615 echo $content;
616 }
617
618 do_action( 'srfm_after_field_content', $post, $id );
619
620 $captcha_container_hidden_class = ! empty( $google_captcha_site_key ) && ( 'v3-reCAPTCHA' === $recaptcha_version || 'v2-invisible' === $recaptcha_version ) ? 'srfm-display-none' : '';
621
622 ?>
623 <?php if ( $should_show_submit_button && ! empty( $security_type ) && 'none' !== $security_type ) { ?>
624 <div class="srfm-captcha-container <?php echo esc_attr( $captcha_container_hidden_class ); ?>">
625
626 <?php
627
628 if ( 'g-recaptcha' === $security_type ) {
629 self::get_google_captcha_script( $recaptcha_version, $google_captcha_site_key );
630 }
631
632 if ( 'cf-turnstile' === $security_type ) {
633 self::get_cf_turnstile_script( $srfm_cf_appearance_mode, $srfm_cf_turnstile_site_key );
634 }
635
636 if ( 'hcaptcha' === $security_type ) {
637 self::get_h_captcha_script( $srfm_hcaptcha_site_key );
638 }
639 ?>
640 <div class="srfm-validation-error" id="captcha-error" style="display: none;"><?php echo esc_html__( 'Please verify that you are not a robot.', 'sureforms' ); ?></div>
641 </div>
642 <?php } ?>
643
644 <?php
645 if ( $is_page_break ) {
646 do_action( 'srfm_page_break_btn', $id );
647 }
648 $srfm_button_classes = apply_filters( 'srfm_add_button_classes', [ '1' === $btn_from_theme ? 'wp-block-button__link' : 'srfm-btn-frontend srfm-button srfm-submit-button', 'v3-reCAPTCHA' === $recaptcha_version ? ' g-recaptcha' : '' ], $id, $block_attrs );
649 ?>
650
651 <div class="srfm-submit-container <?php echo esc_attr( $is_page_break ? 'srfm-hide' : '' ); ?>" style="<?php echo ! $should_show_submit_button ? 'visibility:hidden;position:absolute;' : ''; ?>">
652 <div style="width: <?php echo esc_attr( $full ? '100%' : '' ); ?>; text-align: <?php echo esc_attr( $submit_button_alignment ); ?>" class="wp-block-button">
653 <?php do_action( 'srfm_before_submit_button', $id ); ?>
654 <?php if ( $should_show_submit_button ) { ?>
655 <button style="<?php echo esc_attr( $full ? 'width: 100%;' : '' ); ?>" id="srfm-submit-btn" class="<?php echo esc_attr( implode( ' ', array_filter( $srfm_button_classes ) ) ); ?>"
656 <?php if ( 'v3-reCAPTCHA' === $recaptcha_version ) { ?>
657 data-callback="recaptchaCallback"
658 data-error-callback="onGCaptchaV3Error"
659 recaptcha-type="<?php echo esc_attr( $recaptcha_version ); ?>"
660 data-sitekey="<?php echo esc_attr( $google_captcha_site_key ); ?>"
661 <?php } ?>
662 >
663 <div class="srfm-submit-wrap">
664 <?php echo esc_html( $button_text ); ?>
665 <div class="srfm-loader"></div>
666 </div>
667 </button>
668 <?php } ?>
669 <?php do_action( 'srfm_after_submit_button', $id ); ?>
670 </div>
671 </div>
672 <?php
673
674 echo wp_kses_post(
675 apply_filters(
676 'srfm_after_submit_button_content',
677 '',
678 [
679 'id' => $id,
680 'should_show_submit_button' => $should_show_submit_button,
681 'button_text' => $button_text,
682 'submit_button_alignment' => $submit_button_alignment,
683 'full' => $full,
684 'btn_from_theme' => $btn_from_theme,
685 'is_page_break' => $is_page_break,
686 'recaptcha_version' => $recaptcha_version,
687 'google_captcha_site_key' => $google_captcha_site_key,
688 'srfm_button_classes' => $srfm_button_classes,
689 ]
690 )
691 );
692 }
693 self::common_error_message( 'footer' );
694 ?>
695 </form>
696 <div class="srfm-single-form srfm-success-box in-page">
697 <div aria-live="polite" aria-atomic="true" role="alert" id="srfm-success-message-page-<?php echo esc_attr( Helper::get_string_value( $id ) ); ?>" class="srfm-success-box-description"></div>
698 </div>
699 <?php
700 // Add preview script for real-time styling updates from block editor.
701 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a preview context, nonce not required.
702 if ( isset( $_GET['form_preview'] ) && 'true' === $_GET['form_preview'] && isset( $container_id ) ) {
703 self::enqueue_preview_styling_script( $container_id );
704 }
705 ?>
706 </div>
707 <?php
708 self::$current_block_attrs = [];
709 return ob_get_clean();
710 }
711
712 /**
713 * Generate HCaptcha script markup
714 *
715 * @param string $srfm_hcaptcha_site_key site key.
716 * @since 1.7.0
717 * @return void
718 */
719 public static function get_h_captcha_script( $srfm_hcaptcha_site_key ) {
720 if ( ! empty( $srfm_hcaptcha_site_key ) ) {
721 // hCaptcha script.
722 wp_enqueue_script( 'hcaptcha', 'https://js.hcaptcha.com/1/api.js', [], null, [ 'strategy' => 'defer' ] ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
723 ?>
724 <div id="srfm-hcaptcha-sitekey" data-callback="onSuccess" data-error-callback="onHCaptchaError" class="h-captcha" data-sitekey="<?php echo esc_attr( $srfm_hcaptcha_site_key ); ?>"></div>
725 <?php
726 } else {
727 Helper::render_missing_sitekey_error( 'HCaptcha' );
728 }
729 }
730
731 /**
732 * Generate Google Recaptcha script markup
733 *
734 * @param string $recaptcha_version reCAPTCHA version.
735 * @param string $google_captcha_site_key site key.
736 * @since 1.7.0
737 * @return void
738 */
739 public static function get_google_captcha_script( $recaptcha_version, $google_captcha_site_key ) {
740
741 if ( empty( $google_captcha_site_key ) ) {
742 Helper::render_missing_sitekey_error( 'Google reCAPTCHA' );
743 return;
744 }
745
746 if ( 'v2-checkbox' === $recaptcha_version ) {
747 ?>
748 <?php
749 wp_enqueue_script( 'google-recaptcha', 'https://www.google.com/recaptcha/api.js', [], SRFM_VER, true );
750 ?>
751 <div class='g-recaptcha' data-callback="onSuccess" data-error-callback="onGCaptchaV2CheckBoxError" recaptcha-type="<?php echo esc_attr( $recaptcha_version ); ?>" data-sitekey="<?php echo esc_attr( strval( $google_captcha_site_key ) ); ?>" ></div>
752 <?php } ?>
753
754 <?php if ( 'v2-invisible' === $recaptcha_version ) { ?>
755 <?php
756 wp_enqueue_script( 'google-recaptcha-invisible', 'https://www.google.com/recaptcha/api.js?onload=recaptchaCallback&render=explicit', [ SRFM_SLUG . '-form-submit' ], SRFM_VER, true );
757 ?>
758 <div class='g-recaptcha' recaptcha-type="<?php echo esc_attr( $recaptcha_version ); ?>" data-sitekey="<?php echo esc_attr( $google_captcha_site_key ); ?>" data-size="invisible"></div>
759 <?php } ?>
760
761 <?php if ( 'v3-reCAPTCHA' === $recaptcha_version ) { ?>
762 <?php
763 // phpcs:disable WordPress.WP.EnqueuedResourceParameters.MissingVersion, PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent -- Google reCAPTCHA must be loaded from Google's servers for token verification; the version is controlled by Google, and passing null avoids stale caching.
764 wp_enqueue_script(
765 'srfm-google-recaptchaV3',
766 'https://www.google.com/recaptcha/api.js?render=' . $google_captcha_site_key,
767 [],
768 null,
769 true
770 );
771 // phpcs:enable WordPress.WP.EnqueuedResourceParameters.MissingVersion, PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent
772 ?>
773 <?php
774 }
775 }
776
777 /**
778 * Generate Cloudflare Turnstile script markup
779 *
780 * @param string $srfm_cf_appearance_mode appearance mode.
781 * @param string $srfm_cf_turnstile_site_key site key.
782 * @since 1.7.0
783 * @return void
784 */
785 public static function get_cf_turnstile_script( $srfm_cf_appearance_mode, $srfm_cf_turnstile_site_key ) {
786 if ( ! empty( $srfm_cf_turnstile_site_key ) ) {
787 // Cloudflare Turnstile script.
788 // phpcs:disable WordPress.WP.EnqueuedResourceParameters.MissingVersion, PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent -- Cloudflare Turnstile must be loaded from Cloudflare's servers for token verification; the version is controlled by Cloudflare.
789 wp_enqueue_script(
790 SRFM_SLUG . '-cf-turnstile',
791 'https://challenges.cloudflare.com/turnstile/v0/api.js',
792 [],
793 null,
794 [
795 false,
796 'defer' => true,
797 ]
798 );
799 // phpcs:enable WordPress.WP.EnqueuedResourceParameters.MissingVersion, PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent
800 ?>
801 <!-- The callback methods below are available on frontend.js. onTurnstileError displays and error in place of recaptcha dialog. -->
802 <div id="srfm-cf-sitekey" class="cf-turnstile" data-callback="onSuccess" data-error-callback="onTurnstileError" data-theme="<?php echo esc_attr( $srfm_cf_appearance_mode ); ?>" data-sitekey="<?php echo esc_attr( $srfm_cf_turnstile_site_key ); ?>"></div>
803 <?php
804 } else {
805 Helper::render_missing_sitekey_error( 'Turnstile' );
806 }
807 }
808
809 /**
810 * Generate common error message markup
811 *
812 * @param string $position position of the error message.
813 * @since 1.5.0
814 * @return void
815 */
816 public static function common_error_message( $position = 'footer' ) {
817 $icon = Helper::fetch_svg( 'info_circle', '', 'aria-hidden="true"' );
818 $classes = "srfm-common-error-message srfm-error-message srfm-{$position}-error";
819 ?>
820 <p id="srfm-error-message" class="<?php echo esc_attr( $classes ); ?>" hidden><?php echo wp_kses( $icon, Helper::$allowed_tags_svg ); ?><span class="srfm-error-content"><?php echo esc_html( String_Translator::get_instance()->translate_validation_message( 'srfm_submit_error', __( 'There was an error trying to submit your form. Please try again.', 'sureforms' ) ) ); ?></span></p>
821 <?php
822 }
823
824 /**
825 * Enqueue the preview styling script for real-time updates from block editor.
826 *
827 * @param string $container_id The form container ID selector.
828 * @since 2.7.0
829 * @return void
830 */
831 public static function enqueue_preview_styling_script( $container_id ) {
832 $script_asset_path = SRFM_DIR . 'assets/build/previewStyling.asset.php';
833 $script_asset = file_exists( $script_asset_path ) ? require $script_asset_path : [
834 'dependencies' => [],
835 'version' => SRFM_VER,
836 ];
837
838 wp_enqueue_script(
839 SRFM_SLUG . '-preview-styling',
840 SRFM_URL . 'assets/build/previewStyling.js',
841 $script_asset['dependencies'],
842 $script_asset['version'],
843 true
844 );
845
846 wp_localize_script(
847 SRFM_SLUG . '-preview-styling',
848 'srfmPreviewStyling',
849 [
850 'containerId' => $container_id,
851 'fieldSpacingVars' => Helper::get_css_vars(),
852 ]
853 );
854
855 /**
856 * Action to allow Pro to enqueue additional preview styling scripts.
857 *
858 * @since 2.7.0
859 */
860 do_action( 'srfm_enqueue_preview_styling_scripts' );
861 }
862
863 /**
864 * Generate form confirmation markup
865 *
866 * @param array<mixed> $form_data contains form data.
867 * @param array<mixed> $submission_data contains submission data.
868 * @since 0.0.3
869 * @return string|false
870 */
871 public static function get_confirmation_markup( $form_data = [], $submission_data = [] ) {
872
873 $confirmation_message = '';
874
875 if ( empty( $form_data ) ) {
876 return $confirmation_message;
877 }
878
879 $form_id = isset( $form_data['form-id'] ) ? Helper::get_integer_value( $form_data['form-id'] ) : 0;
880 $form_confirmation = get_post_meta( $form_id, '_srfm_form_confirmation' );
881
882 /**
883 * Filter the form confirmation data.
884 * Allows conditional confirmations to override the default confirmation settings.
885 *
886 * @param mixed $form_confirmation The form confirmation data from post meta.
887 * @param int $form_id The form ID.
888 * @param array $submission_data The submission data.
889 * @since 2.4.0
890 */
891 $form_confirmation = apply_filters( 'srfm_form_confirmation_data', $form_confirmation, $form_id, $submission_data );
892
893 if ( ! is_array( $form_confirmation ) ) {
894 return $confirmation_message;
895 }
896
897 $confirmation_data = is_array( $form_confirmation[0] ) && isset( $form_confirmation[0][0] ) ? $form_confirmation[0][0] : null;
898
899 if ( is_array( $form_confirmation ) && isset( $confirmation_data['message'] ) && is_string( $confirmation_data['message'] ) ) {
900 $confirmation_message = $confirmation_data['message'];
901 $confirmation_message = String_Translator::get_instance()->translate_confirmation_message( (int) $form_id, 0, $confirmation_message );
902 }
903 if ( empty( $submission_data ) ) {
904 return $confirmation_message;
905 }
906 $smart_tags = new Smart_Tags();
907 $confirmation_message = $smart_tags->process_smart_tags( $confirmation_message, $submission_data, $form_data );
908
909 /**
910 * Filter whether confirmation message links should open in a new tab.
911 *
912 * @since 2.5.2
913 *
914 * @param bool $open_in_new_tab Whether links open in a new tab. Default true.
915 */
916 $open_in_new_tab = (bool) apply_filters( 'srfm_confirmation_links_open_in_new_tab', true );
917
918 $markup = Helper::strip_js_attributes(
919 apply_filters( 'srfm_after_submit_confirmation_message', $confirmation_message, $form_data, $submission_data ),
920 ! $open_in_new_tab
921 );
922
923 if ( false !== strpos( $markup, 'src="image/svg+xml;base64' ) ) {
924 // Handle Form Confirmation SVGs separately. We have planned to improve it in the future replacing it with image URL.
925 $normalized_string = preg_replace( '/src="image\/svg\+xml;base64/', 'src="data:image/svg+xml;base64', $markup );
926
927 if ( is_string( $normalized_string ) ) {
928 $markup = $normalized_string;
929 }
930 }
931
932 return $markup;
933 }
934
935 /**
936 * Get redirect url for form incase of different page or custom url is selected.
937 *
938 * @param array<mixed> $form_data contains form data.
939 * @param array<mixed> $submission_data contains submission data.
940 * @since 1.0.2
941 * @return string|false
942 */
943 public static function get_redirect_url( $form_data = [], $submission_data = [] ) {
944 $redirect_url = '';
945
946 if ( empty( $form_data ) ) {
947 return $redirect_url;
948 }
949
950 $form_id = isset( $form_data['form-id'] ) ? Helper::get_integer_value( $form_data['form-id'] ) : 0;
951 $form_confirmation = get_post_meta( $form_id, '_srfm_form_confirmation' );
952
953 /**
954 * Filter the form confirmation data.
955 * Allows conditional confirmations to override the default confirmation settings.
956 *
957 * @param mixed $form_confirmation The form confirmation data from post meta.
958 * @param int $form_id The form ID.
959 * @param array $submission_data The submission data.
960 * @since 2.4.0
961 */
962 $form_confirmation = apply_filters( 'srfm_form_confirmation_data', $form_confirmation, $form_id, $submission_data );
963
964 if ( ! is_array( $form_confirmation ) ) {
965 return $redirect_url;
966 }
967
968 $confirmation_data = is_array( $form_confirmation[0] ) && isset( $form_confirmation[0][0] ) ? $form_confirmation[0][0] : null;
969
970 $page_url = $confirmation_data['page_url'] ?? '';
971 $custom_url = $confirmation_data['custom_url'] ?? '';
972 $confirmation_type = $confirmation_data['confirmation_type'] ?? '';
973
974 if ( 'different page' === $confirmation_type ) {
975 $redirect_url = esc_url_raw( $page_url );
976 } elseif ( 'custom url' === $confirmation_type ) {
977 $redirect_url = esc_url_raw( $custom_url );
978 }
979
980 if ( empty( $redirect_url ) ) {
981 return $redirect_url;
982 }
983
984 if ( empty( $confirmation_data['enable_query_params'] ) || true !== $confirmation_data['enable_query_params'] ) {
985 return $redirect_url;
986 }
987
988 if ( empty( $confirmation_data['query_params'] ) && ! is_array( $confirmation_data['query_params'] ) ) {
989 return $redirect_url;
990 }
991
992 $query_params = [];
993 foreach ( $confirmation_data['query_params'] as $params ) {
994 if ( is_array( $params ) && ! empty( array_keys( $params ) ) && ! empty( array_values( $params ) ) ) {
995 $query_params[ sanitize_text_field( array_keys( $params )[0] ) ] = sanitize_text_field( array_values( $params )[0] );
996 }
997 }
998
999 $redirect_url = add_query_arg( $query_params, $redirect_url );
1000
1001 if ( ! empty( $submission_data ) ) {
1002 $smart_tags = new Smart_Tags();
1003 // Adding upload_format_type = 'raw' to retrieve urls as comma separated values.
1004 $form_data['upload_format_type'] = 'raw';
1005 // Skip auto-linking URLs in smart tag values — redirect query params need raw values, not HTML.
1006 $form_data['smart_tag_context'] = 'redirect';
1007
1008 /*
1009 * Resolve smart tags in the URL, normalize the multi-value delimiters
1010 * left behind by the substitution, then decode any HTML entities.
1011 *
1012 * Multi-select dropdown values are packed as "Red | Blue" by the frontend
1013 * (srfmUtility.prepareValue in assets/js/unminified/frontend.js), and
1014 * checkbox multi-choice values are rendered as "Red<br>Blue" by
1015 * Smart_Tags::parse_form_input. Neither delimiter is URL-friendly as-is:
1016 * " | " leaks whitespace into the query string and "<br>" gets mangled
1017 * by esc_url_raw below. Normalize both to a plain "|" so the final
1018 * redirect URL carries a clean, URL-safe list that the receiver can
1019 * split on "|".
1020 *
1021 * The str_replace runs before html_entity_decode so that any literal
1022 * "<br>" character sequence inside an option label — which
1023 * Smart_Tags::parse_form_input escapes to "&lt;br&gt;" before joining
1024 * — survives intact. Only the actual delimiter (the unescaped "<br>"
1025 * emitted by the implode) is converted to a pipe; html_entity_decode
1026 * then restores the option's original text.
1027 */
1028 $resolved_redirect_url = Helper::get_string_value( $smart_tags->process_smart_tags( $redirect_url, $submission_data, $form_data ) );
1029 $multi_value_delimiters = [ '<br>', ' | ' ];
1030 $redirect_url = html_entity_decode( str_replace( $multi_value_delimiters, '|', $resolved_redirect_url ) );
1031 }
1032
1033 return esc_url_raw( apply_filters( 'srfm_after_submit_redirect_url', $redirect_url ) );
1034 }
1035 }
1036