PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 3.6.0
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v3.6.0
3.6.0 3.5.3 3.5.2 3.5.1 3.5.0 3.4.8 3.4.7 3.4.6 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5.1 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.10 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.6.1 1.6.7 1.7.0 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.2 1.7.2.1 1.7.2.2 1.7.3 1.7.4 1.7.5 1.7.5.1 1.7.5.2 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.8.0 1.8.0.1 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.0.1 1.9.1 1.9.2 1.9.3 1.9.4 1.9.4.1 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.0.1 2.0.1 2.0.2 2.0.3 2.0.3.1 2.0.4 2.0.4.1 2.0.5 2.0.6 2.0.7 2.0.8 2.0.8.1 2.0.9 3.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.3.1 3.0.4 3.0.4.1 3.0.4.2 3.0.5 3.0.5.1 3.0.5.2 3.0.6 3.0.6.1 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.0.9.1 3.0.9.2 3.0.9.3 3.0.9.4 3.0.9.5 3.1.0 3.1.1 3.1.2 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.4.0 3.4.1 3.4.2 3.4.2.1 3.4.3 3.4.4 3.4.5 trunk 1.0 1.0.1 1.0.2 1.0.3
everest-forms / includes / shortcodes / class-evf-shortcode-form.php
everest-forms / includes / shortcodes Last commit date
class-evf-shortcode-form.php 2 days ago
class-evf-shortcode-form.php
1505 lines
1 <?php
2
3 /**
4 * Form Shortcode
5 *
6 * Used on the show frontend form.
7 *
8 * @package EverestForms\Shortcodes\Form
9 * @version 1.0.0
10 * @since 1.3.2
11 */
12
13 defined( 'ABSPATH' ) || exit;
14
15 /**
16 * Form Shortcode class.
17 */
18 class EVF_Shortcode_Form {
19
20
21 /**
22 * Contains information for multi-part forms.
23 *
24 * Forms that do not contain parts return false, otherwise returns an array
25 * that contains the number of total parts and part counter used when
26 * displaying part rows.
27 *
28 * @since 1.3.2
29 *
30 * @var array
31 */
32 public static $parts = array();
33
34 /**
35 * Hooks in tab.
36 */
37 public static function hooks() {
38 add_filter( 'amp_skip_post', array( 'EVF_Shortcode_Form', 'amp_skip_post' ) );
39 add_action( 'everest_forms_frontend_output_success', 'evf_print_notices', 10, 2 );
40 add_action( 'everest_forms_frontend_output', array( 'EVF_Shortcode_Form', 'header' ), 5, 4 );
41 add_action( 'everest_forms_frontend_output', array( 'EVF_Shortcode_Form', 'fields' ), 10, 3 );
42 add_action( 'everest_forms_display_field_before', array( 'EVF_Shortcode_Form', 'wrapper_start' ), 5, 2 );
43 add_action( 'everest_forms_display_field_before', array( 'EVF_Shortcode_Form', 'label' ), 15, 2 );
44 add_action( 'everest_forms_display_field_before', array( 'EVF_Shortcode_Form', 'description' ), 20, 2 );
45 add_action( 'everest_forms_display_field_after', array( 'EVF_Shortcode_Form', 'messages' ), 3, 2 );
46 add_action( 'everest_forms_display_field_after', array( 'EVF_Shortcode_Form', 'description' ), 5, 2 );
47 add_action( 'everest_forms_display_field_after', array( 'EVF_Shortcode_Form', 'wrapper_end' ), 15, 2 );
48 add_action( 'everest_forms_frontend_output', array( 'EVF_Shortcode_Form', 'honeypot' ), 15, 3 );
49 add_action( 'everest_forms_frontend_output', array( 'EVF_Shortcode_Form', 'clean_talk' ), 15, 3 );
50 if ( ! apply_filters( 'everest_forms_recaptcha_disabled', false ) ) {
51 add_action( 'everest_forms_frontend_output', array( 'EVF_Shortcode_Form', 'recaptcha' ), 20, 3 );
52 }
53 add_action( 'everest_forms_frontend_output', array( 'EVF_Shortcode_Form', 'footer' ), 25, 3 );
54 add_action( 'everest_forms_frontend_output', array( 'EVF_Shortcode_Form', 'inline_script_to_update_nonce' ), 26, 3 );
55
56 // reCaptcha Language.
57 add_filter( 'everest_forms_frontend_recaptcha_url', array( __CLASS__, 'evf_recaptcha_language' ), 10, 1 );
58
59 // Enable for submission waiting time.
60 add_filter( 'everest_forms_display_fields_before', array( 'EVF_Shortcode_Form', 'evf_form_submission_waiting_time' ) );
61 }
62
63 /**
64 * Get the amp-state ID for a given form.
65 *
66 * @param int $form_id Form ID.
67 * @return string State ID.
68 */
69 protected static function get_form_amp_state_id( $form_id ) {
70 return sprintf( 'evf_form_state_%d', $form_id );
71 }
72
73 /**
74 * Disable AMP if query param is detected.
75 *
76 * This allows the full form to be accessible for Pro users or sites
77 * that do not have SSL.
78 *
79 * @since 1.5.3
80 *
81 * @param bool $skip Skip AMP mode, display full post.
82 *
83 * @return bool
84 */
85 public static function amp_skip_post( $skip ) {
86
87 return isset( $_GET['nonamp'] ) ? true : $skip; // phpcs:ignore WordPress.Security.NonceVerification
88 }
89
90
91 /**
92 * Form footer area.
93 *
94 * @param array $form_data Form data and settings.
95 * @param bool $title Whether to display form title.
96 * @param bool $description Whether to display form description.
97 */
98 public static function footer( $form_data, $title, $description ) {
99 $form_id = absint( $form_data['id'] );
100 $settings = isset( $form_data['settings'] ) ? $form_data['settings'] : array();
101 $submit = apply_filters( 'everest_forms_field_submit', isset( $settings['submit_button_text'] ) ? $settings['submit_button_text'] : __( 'Submit', 'everest-forms' ), $form_data );
102 $submit_btn = evf_string_translation( $form_data['id'], 'submit_button', $submit );
103 $process = '';
104 $classes = isset( $form_data['settings']['submit_button_class'] ) ? evf_sanitize_classes( $form_data['settings']['submit_button_class'] ) : '';
105 $parts = ! empty( self::$parts[ $form_id ] ) ? self::$parts[ $form_id ] : array();
106 $visible = ! empty( $parts ) ? 'style="display:none"' : '';
107 $attrs = array( 'aria-live' => 'assertive' );
108 $data_attrs = array();
109 $evf_amp_classes = array();
110
111 // Visibility class.
112 $visibility_class = apply_filters( 'everest_forms_field_submit_visibility_class', array(), $parts, $form_data );
113
114 // Check for submit button processing-text.
115 if ( ! isset( $settings['submit_button_processing_text'] ) ) {
116 $process = 'data-process-text="' . esc_attr__( 'Processing&hellip;', 'everest-forms' ) . '"';
117 } elseif ( ! empty( $settings['submit_button_processing_text'] ) ) {
118 if ( evf_is_amp() ) {
119 $attrs['[text]'] = sprintf(
120 '%s.submitting ? %s : %s',
121 self::get_form_amp_state_id( $form_id ),
122 wp_json_encode( $settings['submit_button_processing_text'], JSON_UNESCAPED_UNICODE ),
123 wp_json_encode( $submit, JSON_UNESCAPED_UNICODE )
124 );
125 } else {
126 $process = 'data-process-text="' . esc_attr( evf_string_translation( $form_data['id'], 'processing_text', $settings['submit_button_processing_text'] ) ) . '"';
127 }
128 }
129
130 // Submit button area.
131 $conditional_id = 'evf-submit-' . $form_id;
132 if ( isset( $form_data['settings']['submit']['connection_1']['conditional_logic_status'] ) && '1' === $form_data['settings']['submit']['connection_1']['conditional_logic_status'] ) {
133 $con_rules = array(
134 'conditional_option' => isset( $form_data['settings']['submit']['connection_1']['conditional_option'] ) ? $form_data['settings']['submit']['connection_1']['conditional_option'] : '',
135 'conditionals' => isset( $form_data['settings']['submit']['connection_1']['conditionals'] ) ? $form_data['settings']['submit']['connection_1']['conditionals'] : '',
136 );
137 } else {
138 $con_rules = '';
139 }
140
141 $conditional_rules = wp_json_encode( $con_rules );
142
143 echo '<div class="evf-submit-container ' . esc_attr( implode( ' ', $visibility_class ) ) . '" >';
144
145 echo '<input type="hidden" name="everest_forms[id]" value="' . absint( $form_id ) . '">';
146
147 echo '<input type="hidden" name="everest_forms[author]" value="' . absint( get_the_author_meta( 'ID' ) ) . '">';
148
149 if ( is_singular() ) {
150 echo '<input type="hidden" name="everest_forms[post_id]" value="' . absint( get_the_ID() ) . '">';
151 }
152
153 do_action( 'everest_forms_display_submit_before', $form_data );
154
155 printf(
156 "<button type='submit' name='everest_forms[submit]' class='everest-forms-submit-button button evf-submit %s' id='evf-submit-%d' value='evf-submit' %s conditional_rules='%s' conditional_id='%s' %s %s>%s</button>",
157 esc_attr( $classes ),
158 esc_attr( $form_id ),
159 ! isset( $settings['submit_button_processing_text'] ) ? 'data-process-text="' . esc_attr__( 'Processing&hellip;', 'everest-forms' ) . '"' : ( ! empty( $settings['submit_button_processing_text'] ) ? 'data-process-text="' . esc_attr( evf_string_translation( $form_data['id'], 'processing_text', $settings['submit_button_processing_text'] ) ) . '"' : '' ),
160 esc_attr( $conditional_rules ),
161 esc_attr( $conditional_id ),
162 ( ! empty( self::$parts[ $form_id ] ) ? 'style="display:none"' : '' ),
163 evf_html_attributes(
164 sprintf( 'evf-submit-%d', absint( $form_id ) ),
165 $evf_amp_classes,
166 $data_attrs,
167 $attrs
168 ),
169 esc_html( $submit_btn )
170 );
171
172 do_action( 'everest_forms_display_submit_after', $form_data );
173
174 echo '</div>';
175
176 if ( evf_is_amp() ) {
177 printf( '<div submit-success><template type="amp-mustache"><div class=" everest-forms-notice everest-forms-notice--success {{#redirecting}}evf-redirection-message{{/redirecting}}">{{{message}}}</div></template></div>' );
178 return;
179 }
180 }
181
182 /**
183 * Message.
184 *
185 * @param array $field Field.
186 * @param array $form_data Form data.
187 */
188 public static function messages( $field, $form_data ) {
189 $error = $field['properties']['error'];
190
191 if ( empty( $error['value'] ) || is_array( $error['value'] ) ) {
192 return;
193 }
194
195 printf(
196 '<label %s>%s</label>',
197 evf_html_attributes( $error['id'], $error['class'], $error['data'], $error['attr'] ),
198 esc_html( $error['value'] )
199 );
200 }
201
202 /**
203 * Description.
204 *
205 * @param array $field Field.
206 * @param array $form_data Form data.
207 */
208 public static function description( $field, $form_data ) {
209 $action = current_action();
210
211 $description = $field['properties']['description'];
212
213 // If the description is empty don't proceed.
214 if ( empty( $description['value'] ) ) {
215 return;
216 }
217
218 // Determine positioning.
219 if ( 'everest_forms_display_field_before' === $action && 'before' !== $description['position'] ) {
220 return;
221 }
222 if ( 'everest_forms_display_field_after' === $action && 'after' !== $description['position'] ) {
223 return;
224 }
225
226 if ( 'before' === $description['position'] ) {
227 $description['class'][] = 'evf-field-description-before';
228 }
229
230 printf(
231 '<div %s>%s</div>',
232 evf_html_attributes( $description['id'], $description['class'], $description['data'], $description['attr'] ),
233 wp_kses_post( evf_string_translation( $form_data['id'], $field['id'], $description['value'], '-description' ) )
234 );
235 }
236
237 /**
238 * Label.
239 *
240 * @param array $field Field.
241 * @param array $form_data Form data.
242 */
243 public static function label( $field, $form_data ) {
244
245 $label = $field['properties']['label'];
246 // If the label is empty or disabled don't proceed.
247 if ( empty( $label['value'] ) || $label['disabled'] ) {
248 return;
249 }
250
251 $required = $label['required'] ? apply_filters( 'everest_forms_field_required_label', '<abbr class="required" title="' . esc_attr__( 'Required', 'everest-forms' ) . '">' . apply_filters( 'everest_form_get_required_type', '*', $field, $form_data ) . '</abbr>' ) : '';
252 $custom_tags = apply_filters( 'everest_forms_field_custom_tags', false, $field, $form_data );
253
254 printf(
255 '<label %s><span class="evf-label">%s</span> %s</label>',
256 evf_html_attributes( $label['id'], $label['class'], $label['data'], $label['attr'] ),
257 wp_kses(
258 evf_string_translation(
259 $form_data['id'],
260 $field['id'],
261 wp_kses(
262 $label['value'],
263 array(
264 'a' => array(
265 'href' => array(),
266 'class' => array(),
267 ),
268 'span' => array(
269 'class' => array(),
270 ),
271 'em' => array(),
272 'small' => array(),
273 'strong' => array(),
274 )
275 )
276 ),
277 array(
278 'a' => array(
279 'href' => array(),
280 'class' => array(),
281 ),
282 'span' => array(
283 'class' => array(),
284 ),
285 'em' => array(),
286 'small' => array(),
287 'strong' => array(),
288 )
289 ),
290 wp_kses_post( $required ),
291 wp_kses_post( $custom_tags )
292 );
293 }
294
295 /**
296 * Wrapper end.
297 *
298 * @param array $field Field.
299 * @param array $form_data Form data.
300 */
301 public static function wrapper_end( $field, $form_data ) {
302 echo '</div>';
303 }
304
305 /**
306 * Wrapper start.
307 *
308 * @param array $field Field.
309 * @param array $form_data Form data.
310 */
311 public static function wrapper_start( $field, $form_data ) {
312 $container = $field['properties']['container'];
313 $container['data']['field-id'] = esc_attr( $field['id'] );
314 printf(
315 '<div %s>',
316 evf_html_attributes( $container['id'], $container['class'], $container['data'], $container['attr'] )
317 );
318 }
319
320 /**
321 * Form header for displaying form title and description if enabled.
322 *
323 * @param array $form_data Form data and settings.
324 * @param bool $title Whether to display form title.
325 * @param bool $description Whether to display form description.
326 * @param array $errors List of all errors during form submission.
327 */
328 public static function header( $form_data, $title, $description, $errors ) {
329 $settings = isset( $form_data['settings'] ) ? $form_data['settings'] : array();
330
331 // Check if title and/or description is enabled.
332 if ( true === $title || true === $description ) {
333 echo '<div class="evf-title-container">';
334
335 if ( true === $title && ! empty( $settings['form_title'] ) ) {
336 echo '<div class="everest-forms--title">' . esc_html( evf_string_translation( $form_data['id'], 'form_title', $settings['form_title'] ) ) . '</div>';
337 }
338
339 if ( true === $description && ! empty( $settings['form_description'] ) ) {
340 echo '<div class="everest-forms--description">' . esc_textarea( evf_string_translation( $form_data['id'], 'form_description', $settings['form_description'] ) ) . '</div>';
341 }
342
343 echo '</div>';
344 }
345
346 // Output header errors if they exist.
347 if ( ! empty( $errors['header'] ) ) {
348 evf_add_notice( $errors['header'], 'error' );
349 }
350 }
351
352 /**
353 * Form field area.
354 *
355 * @param array $form_data Form data and settings.
356 * @param bool $title Whether to display form title.
357 * @param bool $description Whether to display form description.
358 */
359 public static function fields( $form_data, $title, $description ) {
360 $structure = isset( $form_data['structure'] ) ? $form_data['structure'] : array();
361
362 // Bail if empty form fields.
363 if ( empty( $form_data['form_fields'] ) ) {
364 return;
365 }
366
367 // Form fields area.
368 echo '<div class="evf-field-container">';
369
370 wp_nonce_field( 'everest-forms_process_submit', '_wpnonce' . $form_data['id'] );
371
372 /**
373 * Hook: everest_forms_display_fields_before.
374 *
375 * @hooked EverestForms_MultiPart::display_fields_before() Multi-Part markup open.
376 */
377 do_action( 'everest_forms_display_fields_before', $form_data );
378
379 foreach ( $structure as $row_key => $row ) {
380 /**
381 * Hook: everest_forms_display_repeater_fields.
382 *
383 * @hooked EVF_Repeater_Fields->display_repeater_fields() Display Repeater Fields.
384 */
385 $is_repeater = apply_filters( 'everest_forms_display_repeater_fields', false, $row, $form_data, true );
386
387 /**
388 * Hook: everest_forms_display_row_before.
389 */
390 do_action( 'everest_forms_display_row_before', $row_key, $form_data );
391
392 $conditions = array();
393
394 if ( ! empty( $form_data['settings']['form_rows'][ 'connection_' . $row_key ] ) && ! empty( $form_data['settings']['form_rows'][ 'connection_' . $row_key ]['conditional_logic_status'] ) ) {
395 $conditions = ! empty( $form_data['settings']['form_rows'][ 'connection_' . $row_key ] ) ? $form_data['settings']['form_rows'][ 'connection_' . $row_key ] : array();
396 }
397
398 echo '<div class="evf-frontend-row" data-row="' . esc_attr($row_key) . '"' . esc_attr($is_repeater) . ' conditional_rules="' . (isset($conditions) ? esc_attr(wp_json_encode($conditions)) : '') . '">'; // @codingStandardsIgnoreLine
399
400 foreach ( $row as $grid_key => $grid ) {
401 $number_of_grid = count( $row );
402
403 echo '<div class="evf-frontend-grid evf-grid-' . absint( $number_of_grid ) . '" data-grid="' . esc_attr( $grid_key ) . '">';
404
405 if ( ! is_array( $grid ) ) {
406 $grid = array();
407 }
408
409 foreach ( $grid as $field_key ) {
410 $field = isset( $form_data['form_fields'][ $field_key ] ) ? $form_data['form_fields'][ $field_key ] : array();
411 $field = apply_filters( 'everest_forms_field_data', $field, $form_data );
412
413 if ( empty( $field ) || evf_is_field_locked( $field['type'] ) ) {
414 continue;
415 }
416
417 $should_display_field = apply_filters( "everest_forms_should_display_field_{$field['type']}", true, $field, $form_data );
418
419 if ( true !== $should_display_field ) {
420 continue;
421 }
422
423 // Get field attributes.
424 $attributes = self::get_field_attributes( $field, $form_data );
425
426 do_action( 'everest_forms_display_before_field_wrapper', $field, $form_data );
427
428 // Get field properties.
429 $properties = self::get_field_properties( $field, $form_data, $attributes );
430
431 // Add properties to the field so it's available everywhere.
432 $field['properties'] = $properties;
433
434 do_action( 'everest_forms_display_field_before', $field, $form_data );
435
436 do_action( "everest_forms_display_field_{$field['type']}", $field, $attributes, $form_data );
437
438 do_action( 'everest_forms_display_field_after', $field, $form_data );
439
440 do_action( 'everest_forms_display_after_field_wrapper', $field, $form_data );
441 }
442
443 echo '</div>';
444 }
445
446 /**
447 * Hook: everest_forms_add_remove_buttons.
448 *
449 * @hooked EVF_Repeater_Fields->add_remove_buttons() Show Add and Remove buttons.
450 */
451 do_action( 'everest_forms_add_remove_buttons', $row, $form_data, $is_repeater );
452
453 echo '</div>';
454
455 /**
456 * Hook: everest_forms_display_row_after.
457 *
458 * @hooked EverestForms_MultiPart::display_row_after() Multi-Part markup (close previous part, open next).
459 */
460 do_action( 'everest_forms_display_row_after', $row_key, $form_data );
461 }
462
463 /**
464 * Hook: everest_forms_display_fields_after.
465 *
466 * @hooked EverestForms_MultiPart::display_fields_after() Multi-Part markup open.
467 */
468 do_action( 'everest_forms_display_fields_after', $form_data );
469
470 echo '</div>';
471 }
472
473 /**
474 * Anti-spam honeypot output if configured.
475 *
476 * @since 1.4.9
477 * @param array $form_data Form data and settings.
478 */
479 public static function honeypot( $form_data ) {
480 $names = array( 'Name', 'Phone', 'Comment', 'Message', 'Email', 'Website' );
481
482 // Output the honeypot container.
483 if ( isset( $form_data['settings']['honeypot'] ) && '1' === $form_data['settings']['honeypot'] ) {
484 echo '<div class="evf-honeypot-container evf-field-hp">';
485
486 echo '<label for="evf-' . esc_attr( $form_data['id'] ) . '-field-hp" class="evf-field-label">' . esc_attr( $names[ array_rand( $names ) ] ) . '</label>';
487
488 echo '<input type="text" name="everest_forms[hp]" id="evf-' . esc_attr( $form_data['id'] ) . '-field-hp" class="input-text">';
489
490 echo '</div>';
491 }
492 }
493
494 /**
495 * Anti-spam CleanTalk output if configured.
496 *
497 * @since 3.2.2
498 *
499 * @param [type] $form_data Form data.
500 */
501 public static function clean_talk( $form_data ) {
502
503 $is_cleantalk_activated = isset( $form_data['settings']['cleantalk'] ) ? $form_data['settings']['cleantalk'] : false;
504
505 if ( ! $is_cleantalk_activated ) {
506 return;
507 }
508
509 $detector_js_url = 'https://fd.cleantalk.org/ct-bot-detector-wrapper.js';
510 $clean_talk_inline = <<<JS
511 document.addEventListener("DOMContentLoaded", function () {
512 var loadInput = document.querySelector('input[name="everest_forms[evf_form_load_time]"]');
513 if (loadInput) {
514 loadInput.value = Math.floor(Date.now() / 1000);
515 }
516
517 var maxAttempts = 10;
518 var attempts = 0;
519 var token = false;
520 var interval = setInterval( function () {
521 var lStorage = localStorage.getItem('bot_detector_event_token');
522 if ( lStorage !== null ) {
523 try {
524 lStorage = JSON.parse( lStorage );
525 if ( lStorage.hasOwnProperty( 'value' ) && typeof lStorage.value === 'string' ) {
526 token = lStorage.value;
527 }
528 } catch ( e ) {
529 token = null;
530 }
531 }
532 if ( token ) {
533 var eventInput = document.querySelector( 'input[name="everest_forms[evf_event_token]"]' );
534 if ( eventInput ) {
535 eventInput.value = token;
536 }
537 clearInterval( interval );
538 }
539 if ( ++attempts >= maxAttempts ) {
540 clearInterval( interval );
541 }
542 }, 500);
543 });
544 JS;
545
546 // Enqueue cleanTalk scripts.
547 wp_enqueue_script(
548 'evf-clan-talk',
549 $detector_js_url,
550 array( 'jquery' ),
551 EVF_VERSION,
552 true
553 );
554
555 wp_add_inline_script( 'evf-clan-talk', $clean_talk_inline );
556
557 if ( isset( $form_data['settings']['cleantalk'] ) && '1' === $form_data['settings']['cleantalk'] ) {
558 echo '<input type="hidden" name="everest_forms[evf_event_token]" value="">';
559 echo '<input type="hidden" name="everest_forms[evf_form_load_time]" class="evf_form_load_time" value="">';
560 }
561 }
562
563 /**
564 * Google reCAPTCHA output if configured.
565 *
566 * @param array $form_data Form data and settings.
567 */
568 public static function recaptcha( $form_data ) {
569 $recaptcha_type = get_option( 'everest_forms_recaptcha_type', 'v2' );
570 $invisible_recaptcha = get_option( 'everest_forms_recaptcha_v2_invisible', 'no' );
571
572 if ( 'v2' === $recaptcha_type && 'no' === $invisible_recaptcha ) {
573 $site_key = get_option( 'everest_forms_recaptcha_v2_site_key' );
574 $secret_key = get_option( 'everest_forms_recaptcha_v2_secret_key' );
575 } elseif ( 'v2' === $recaptcha_type && 'yes' === $invisible_recaptcha ) {
576 $site_key = get_option( 'everest_forms_recaptcha_v2_invisible_site_key' );
577 $secret_key = get_option( 'everest_forms_recaptcha_v2_invisible_secret_key' );
578 } elseif ( 'v3' === $recaptcha_type ) {
579 $site_key = get_option( 'everest_forms_recaptcha_v3_site_key' );
580 $secret_key = get_option( 'everest_forms_recaptcha_v3_secret_key' );
581 } elseif ( 'hcaptcha' === $recaptcha_type ) {
582 $site_key = get_option( 'everest_forms_recaptcha_hcaptcha_site_key' );
583 $secret_key = get_option( 'everest_forms_recaptcha_hcaptcha_secret_key' );
584 } elseif ( 'turnstile' === $recaptcha_type ) {
585 $site_key = get_option( 'everest_forms_recaptcha_turnstile_site_key' );
586 $secret_key = get_option( 'everest_forms_recaptcha_turnstile_secret_key' );
587 $theme = get_option( 'everest_forms_recaptcha_turnstile_theme' );
588 $lang = get_option( 'everest_forms_recaptcha_recaptcha_language', 'en-GB' );
589 } else {
590 $site_key = '';
591 $secret_key = '';
592 }
593
594 if ( ! $site_key || ! $secret_key ) {
595 return;
596 }
597 // Check that the CAPTCHA is configured for the specific form.
598 if (
599 ! isset( $form_data['settings']['recaptcha_support'] ) ||
600 '1' !== $form_data['settings']['recaptcha_support']
601 ) {
602 return;
603 }
604 if ( evf_is_amp() ) {
605 if ( 'v3' === $recaptcha_type ) {
606 printf(
607 '<amp-recaptcha-input name="everest_forms[recaptcha]" data-sitekey="%s" data-action="%s" layout="nodisplay"></amp-recaptcha-input>',
608 esc_attr( $site_key ),
609 esc_attr( 'evf_' . $form_data['id'] )
610 );
611 }
612 return; // Only v3 is supported in AMP.
613 }
614
615 if ( isset( $form_data['settings']['recaptcha_support'] ) && '1' === $form_data['settings']['recaptcha_support'] ) {
616 $form_id = isset( $form_data['id'] ) ? absint( $form_data['id'] ) : 0;
617 $visible = ! empty( self::$parts[ $form_id ] ) ? 'style="display:none;"' : '';
618 $data = apply_filters(
619 'everest_forms_frontend_recaptcha',
620 array(
621 'sitekey' => trim( sanitize_text_field( $site_key ) ),
622 ),
623 $form_data
624 );
625
626 // Load reCAPTCHA support if form supports it.
627 if ( $site_key && $secret_key ) {
628 if ( 'v2' === $recaptcha_type ) {
629 $recaptcha_api = apply_filters( 'everest_forms_frontend_recaptcha_url', 'https://www.google.com/recaptcha/api.js?onload=EVFRecaptchaLoad&render=explicit', $recaptcha_type, $form_id );
630
631 if ( 'yes' === $invisible_recaptcha ) {
632 $data['size'] = 'invisible';
633 $recaptcha_inline = 'var EVFRecaptchaLoad = function(){jQuery(".g-recaptcha").each(function(index, el){var recaptchaID = grecaptcha.render(el,{callback:function(){EVFRecaptchaCallback(el);}},true); el.closest("form").querySelector("button[type=submit]").recaptchaID = recaptchaID;});};
634 var EVFRecaptchaCallback = function (el) {
635 var $form = el.closest("form");
636 if( typeof jQuery !== "undefined" ){
637 if( "1" === jQuery( $form ).attr( "data-ajax_submission" ) ) {
638 el.closest( "form" ).querySelector( "button[type=submit]" ).recaptchaID = "verified";
639 jQuery( $form ).find( ".evf-submit" ).trigger( "click" );
640 } else {
641 $form.submit();
642 }
643 grecaptcha.reset();
644 }
645 };
646 ';
647 } else {
648 $recaptcha_inline = 'var EVFRecaptchaLoad = function(){jQuery(".g-recaptcha").each(function(index, el){var recaptchaID = grecaptcha.render(el,{callback:function(){EVFRecaptchaCallback(el);}},true);jQuery(el).attr( "data-recaptcha-id", recaptchaID);});};';
649 $recaptcha_inline .= 'var EVFRecaptchaCallback = function(el){jQuery(el).parent().find(".evf-recaptcha-hidden").val("1").trigger("change").valid();};';
650 }
651 } elseif ( 'v3' === $recaptcha_type ) {
652 $recaptcha_api = apply_filters( 'everest_forms_frontend_recaptcha_url', 'https://www.google.com/recaptcha/api.js?render=' . $site_key, $recaptcha_type, $form_id );
653 $recaptcha_inline = 'var EVFRecaptchaLoad = function(){grecaptcha.execute("' . esc_html( $site_key ) . '",{action:"everest_form"}).then(function(token){var f=document.getElementsByName("everest_forms[recaptcha]");for(var i=0;i<f.length;i++){f[i].value = token;}});};grecaptcha.ready(EVFRecaptchaLoad);setInterval(EVFRecaptchaLoad, 110000);';
654 $recaptcha_inline .= 'grecaptcha.ready(function(){grecaptcha.execute("' . esc_html( $site_key ) . '",{action:"everest_form"}).then(function(token){var f=document.getElementsByName("everest_forms[recaptcha]");for(var i=0;i<f.length;i++){f[i].value = token;}});});';
655 } elseif ( 'hcaptcha' === $recaptcha_type ) {
656 $recaptcha_api = apply_filters( 'everest_forms_frontend_recaptcha_url', 'https://hcaptcha.com/1/api.js??onload=EVFRecaptchaLoad&render=explicit', $recaptcha_type, $form_id );
657 $recaptcha_inline = 'var EVFRecaptchaLoad = function(){jQuery(".g-recaptcha").each(function(index, el){var recaptchaID = hcaptcha.render(el,{callback:function(){EVFRecaptchaCallback(el);}},true);jQuery(el).attr( "data-recaptcha-id", recaptchaID);});};';
658 $recaptcha_inline .= 'var EVFRecaptchaCallback = function(el){jQuery(el).parent().find(".evf-recaptcha-hidden").val("1").trigger("change").valid();};';
659 } elseif ( 'turnstile' === $recaptcha_type ) {
660 $recaptcha_api = apply_filters( 'everest_forms_frontend_recaptcha_url', 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=EVFTurnstileLoad&render=explicit', $recaptcha_type, $form_id );
661 $recaptcha_inline = 'var EVFTurnstileLoad = function(){jQuery(".g-recaptcha").each(function(index, el){var recaptchaID = turnstile.render(el,{theme:"' . $theme . '",language:"' . $lang . '",callback:function(){EVFRecaptchaCallback(el);}},true);jQuery(el).attr( "data-recaptcha-id", recaptchaID);});};';
662 $recaptcha_inline .= 'var EVFRecaptchaCallback = function(el){jQuery(el).parent().find(".evf-recaptcha-hidden").val("1").trigger("change").valid();};';
663 }
664
665 // Enqueue reCaptcha scripts.
666 wp_enqueue_script(
667 'evf-recaptcha',
668 $recaptcha_api,
669 'v3' === $recaptcha_type ? array() : array( 'jquery' ),
670 'v3' === $recaptcha_type ? '3.0.0' : '2.0.0',
671 true
672 );
673
674 // Load reCaptcha callback once.
675 static $count = 1;
676 if ( 1 === $count ) {
677 wp_add_inline_script( 'evf-recaptcha', $recaptcha_inline );
678 $count++;
679 }
680
681 // Output the reCAPTCHA container.
682 $class = ( 'v3' === $recaptcha_type || ( 'v2' === $recaptcha_type && 'yes' === $invisible_recaptcha ) ) ? 'recaptcha-hidden' : '';
683 echo '<div class="evf-recaptcha-container ' . esc_attr( $class ) . '" style="display:' . ( ! empty( self::$parts[ $form_id ] ) ? 'none' : 'block' ) . '">';
684
685 if ( 'v2' === $recaptcha_type || 'hcaptcha' === $recaptcha_type || 'turnstile' === $recaptcha_type ) {
686 echo '<div ' . evf_html_attributes( '', array( 'g-recaptcha' ), $data ) . '></div>';
687
688 if ( 'hcaptcha' === $recaptcha_type && 'no' === $invisible_recaptcha || 'turnstile' === $recaptcha_type ) {
689 echo '<input type="text" name="g-recaptcha-hidden" class="evf-recaptcha-hidden" style="position:absolute!important;clip:rect(0,0,0,0)!important;height:1px!important;width:1px!important;border:0!important;overflow:hidden!important;padding:0!important;margin:0!important;" required>';
690 }
691 } else {
692 echo '<input type="hidden" name="everest_forms[recaptcha]" value="">';
693 }
694
695 echo '</div>';
696 }
697 }
698 }
699
700 /**
701 * Get field attributes.
702 *
703 * @param array $field Field.
704 * @param array $form_data Form data.
705 *
706 * @return array
707 */
708 private static function get_field_attributes( $field, $form_data ) {
709 $form_id = absint( $form_data['id'] );
710 $field_id = esc_attr( $field['id'] );
711 $attributes = array(
712 'field_class' => array( 'evf-field', 'evf-field-' . sanitize_html_class( $field['type'] ), 'form-row' ),
713 'field_id' => array( sprintf( 'evf-%d-field_%s-container', $form_id, $field_id ) ),
714 'field_style' => '',
715 'label_class' => array( 'evf-field-label' ),
716 'label_id' => '',
717 'description_class' => array( 'evf-field-description' ),
718 'description_id' => array(),
719 'input_id' => array( sprintf( 'evf-%d-field_%s', $form_id, $field_id ) ),
720 'input_class' => array(),
721 'input_data' => array(),
722 );
723
724 // Check user field defined classes.
725 if ( ! empty( $field['css'] ) ) {
726 $attributes['field_class'] = array_merge( $attributes['field_class'], evf_sanitize_classes( $field['css'], true ) );
727 }
728
729 // Check for input column layouts.
730 if ( ! empty( $field['input_columns'] ) ) {
731 if ( 'inline' === $field['input_columns'] ) {
732 $attributes['field_class'][] = 'everest-forms-list-inline';
733 } elseif ( '' !== $field['input_columns'] ) {
734 $attributes['field_class'][] = 'everest-forms-list-' . $field['input_columns'] . '-columns';
735 }
736 }
737
738 // Input class.
739 if ( ! in_array( $field['type'], array( 'checkbox', 'radio', 'payment-checkbox', 'payment-multiple' ), true ) ) {
740 $attributes['input_class'][] = 'input-text';
741 }
742
743 // Check label visibility.
744 if ( ! empty( $field['label_hide'] ) ) {
745 $attributes['label_class'][] = 'evf-label-hide';
746 }
747
748 // Check size.
749 if ( ! empty( $field['size'] ) ) {
750 $attributes['input_class'][] = 'evf-field-' . sanitize_html_class( $field['size'] );
751 }
752
753 // Check if required.
754 if ( ! empty( $field['required'] ) ) {
755 $attributes['field_class'][] = 'validate-required';
756 }
757
758 // Check if extra validation required.
759 if ( in_array( $field['type'], array( 'email', 'phone' ), true ) ) {
760 $attributes['field_class'][] = 'validate-' . esc_attr( $field['type'] );
761 }
762
763 // Check if there are errors.
764 if ( isset( evf()->task->errors[ $form_id ][ $field_id ] ) ) {
765 $attributes['input_class'][] = 'evf-error';
766 $attributes['field_class'][] = 'everest-forms-invalid';
767 }
768
769 // This filter is deprecated, filter the properties (below) instead.
770 $attributes = apply_filters( 'evf_field_atts', $attributes, $field, $form_data );
771
772 return $attributes;
773 }
774
775 /**
776 * Return base properties for a specific field.
777 *
778 * @param array $field Field data and settings.
779 * @param array $form_data Form data and settings.
780 * @param array $attributes List of field attributes.
781 *
782 * @return array
783 */
784 public static function get_field_properties( $field, $form_data, $attributes = array() ) {
785 if ( empty( $attributes ) ) {
786 $attributes = self::get_field_attributes( $field, $form_data );
787 }
788
789 // This filter is for backwards compatibility purposes.
790 $types = array( 'text', 'textarea', 'number', 'email', 'hidden', 'url', 'html', 'title', 'password', 'phone', 'address', 'checkbox', 'radio', 'select' );
791 if ( in_array( $field['type'], $types, true ) ) {
792 $field = apply_filters( "everest_forms_{$field['type']}_field_display", $field, $attributes, $form_data );
793 }
794
795 $form_id = absint( $form_data['id'] );
796 $field_id = sanitize_text_field( $field['id'] );
797
798 // Field container data.
799 $container_data = array();
800
801 // Embed required-field-message to the container if the field is required.
802 if ( isset( $field['required'] ) && ( '1' === $field['required'] || true === $field['required'] ) ) {
803 $has_sub_fields = false;
804 $sub_field_messages = array();
805 $required_validation = get_option( 'everest_forms_required_validation' );
806 if ( in_array( $field['type'], array( 'number', 'email', 'url', 'phone' ), true ) ) {
807 $required_validation = get_option( 'everest_forms_' . $field['type'] . '_validation' );
808 }
809
810 if ( 'likert' === $field['type'] ) {
811 $has_sub_fields = true;
812 $likert_rows = isset( $field['likert_rows'] ) ? $field['likert_rows'] : array();
813 $row_keys = array();
814 foreach ( $likert_rows as $row_key => $row_label ) {
815 $row_keys[] = $row_key;
816 $row_slug = 'required-field-message-' . $row_key;
817
818 $error_message = isset( $field[ $row_slug ] ) ? evf_string_translation( $form_data['id'], $field['id'], $field[ $row_slug ], '-' . $row_slug ) : $required_validation;
819 $sub_field_messages[ $row_key ] = htmlspecialchars( wp_kses( html_entity_decode( $error_message ), array() ) );
820 }
821 $container_data['row-keys'] = wp_json_encode( $row_keys );
822 } elseif ( 'address' === $field['type'] ) {
823 $has_sub_fields = true;
824 $sub_field_messages = array(
825 'address1' => isset( $field['required_field_message_setting'] ) && 'global' === $field['required_field_message_setting'] ? $required_validation : evf_string_translation( $form_data['id'], $field['id'], $field['required-field-message-address1'], '-required-field-message-address1' ),
826 'city' => isset( $field['required_field_message_setting'] ) && 'global' === $field['required_field_message_setting'] ? $required_validation : evf_string_translation( $form_data['id'], $field['id'], $field['required-field-message-city'], '-required-field-message-city' ),
827 'state' => isset( $field['required_field_message_setting'] ) && 'global' === $field['required_field_message_setting'] ? $required_validation : evf_string_translation( $form_data['id'], $field['id'], $field['required-field-message-state'], '-required-field-message-state' ),
828 'postal' => isset( $field['required_field_message_setting'] ) && 'global' === $field['required_field_message_setting'] ? $required_validation : evf_string_translation( $form_data['id'], $field['id'], $field['required-field-message-postal'], '-required-field-message-postal' ),
829 'country' => isset( $field['required_field_message_setting'] ) && 'global' === $field['required_field_message_setting'] ? $required_validation : evf_string_translation( $form_data['id'], $field['id'], $field['required-field-message-country'], '-required-field-message-country' ),
830 );
831 }
832
833 if ( true === $has_sub_fields ) {
834 foreach ( $sub_field_messages as $sub_field_type => $error_message ) {
835 $container_data[ 'required-field-message-' . $sub_field_type ] = htmlspecialchars( wp_kses( html_entity_decode( $error_message ), array() ) );
836 }
837 } else {
838 if ( isset( $field['required_field_message_setting'] ) && 'global' === $field['required_field_message_setting'] ) {
839 $container_data['required-field-message'] = htmlspecialchars( wp_kses( html_entity_decode( $required_validation ), array() ) );
840 } elseif ( isset( $field['required-field-message'] ) && '' !== $field['required-field-message'] ) {
841 $required_data = evf_string_translation( $form_data['id'], $field['id'], $field['required-field-message'], '-required-field-message' );
842 $container_data['required-field-message'] = htmlspecialchars( wp_kses( html_entity_decode( $required_data ), array() ) );
843 } else {
844 $container_data['required-field-message'] = htmlspecialchars( wp_kses( html_entity_decode( $required_validation ), array() ) );
845 }
846 }
847 }
848 $errors = isset( evf()->task->errors[ $form_id ][ $field_id ] ) ? evf()->task->errors[ $form_id ][ $field_id ] : '';
849 $defaults = isset($_POST['everest_forms']['form_fields'][$field_id]) && (! is_array($_POST['everest_forms']['form_fields'][$field_id]) && ! empty($_POST['everest_forms']['form_fields'][$field_id])) ? $_POST['everest_forms']['form_fields'][$field_id] : ''; // @codingStandardsIgnoreLine
850
851 /**
852 * Count the number of smart tags in the default value which contain form fields smart tag.
853 *
854 * @since 3.2.3
855 */
856 $count = 0;
857 $default_value = '';
858
859 if ( isset( $field['default_value'] ) ) {
860 preg_match_all( '/\{field_id="(.+?)"\}/', $field['default_value'], $ids );
861 if ( ! empty( $ids[1] ) ) {
862 $count++;
863 }
864 }
865
866 if ( $count > 0 ) {
867 $is_hidden = isset( $field['hidden_field_visibility'] ) ? evf_string_to_bool( $field['hidden_field_visibility'] ) : ( isset( $field['type'] ) && 'hidden' === $field['type'] ? true : false );
868
869 if ( $is_hidden ) {
870 $default_value = isset( $field['default_value'] ) ? apply_filters( 'everest_forms_process_smart_tags', $field['default_value'], $form_data ) : $defaults;
871 } else {
872 $default_value = isset( $field['default_value'] ) ? '' : $defaults;
873 }
874 } else {
875 $default_value = isset( $field['default_value'] ) ? apply_filters( 'everest_forms_process_smart_tags', $field['default_value'], $form_data ) : $defaults;
876 }
877
878 $properties = apply_filters(
879 'everest_forms_field_properties_' . $field['type'],
880 array(
881 'container' => array(
882 'attr' => array(
883 'style' => $attributes['field_style'],
884 ),
885 'class' => $attributes['field_class'],
886 'data' => $container_data,
887 'id' => implode( '', array_slice( $attributes['field_id'], 0 ) ),
888 ),
889 'label' => array(
890 'attr' => array(
891 'for' => sprintf( 'evf-%d-field_%s', $form_id, $field_id ),
892 ),
893 'class' => $attributes['label_class'],
894 'data' => array(),
895 'disabled' => ! empty( $field['label_disable'] ) ? true : false,
896 'hidden' => ! empty( $field['label_hide'] ) ? true : false,
897 'id' => $attributes['label_id'],
898 'required' => ! empty( $field['required'] ) ? true : false,
899 'value' => ! empty( $field['label'] ) ? $field['label'] : '',
900 ),
901 'inputs' => array(
902 'primary' => array(
903 'attr' => array(
904 'name' => "everest_forms[form_fields][{$field_id}]",
905 'value' => $default_value,
906 'placeholder' => isset( $field['placeholder'] ) ? evf_string_translation( $form_data['id'], $field['id'], $field['placeholder'], '-placeholder' ) : '',
907 ),
908 'class' => $attributes['input_class'],
909 'data' => $attributes['input_data'],
910 'id' => implode( array_slice( $attributes['input_id'], 0 ) ),
911 'required' => ! empty( $field['required'] ) ? 'required' : '',
912 ),
913 ),
914 'error' => array(
915 'attr' => array(
916 'for' => sprintf( 'evf-%d-field_%s', $form_id, $field_id ),
917 ),
918 'class' => array( 'evf-error' ),
919 'data' => array(),
920 'id' => '',
921 'value' => ! empty( $errors ) ? $errors : '',
922 ),
923 'description' => array(
924 'attr' => array(),
925 'class' => $attributes['description_class'],
926 'data' => array(),
927 'id' => implode( '', array_slice( $attributes['description_id'], 0 ) ),
928 'position' => 'after',
929 'value' => ! empty( $field['description'] ) ? $field['description'] : '',
930 ),
931 ),
932 $field,
933 $form_data
934 );
935
936 return apply_filters( 'everest_forms_field_properties', $properties, $field, $form_data );
937 }
938
939 /**
940 * Output the shortcode.
941 *
942 * @param array $atts Attributes.
943 */
944 public static function output( $atts ) {
945 wp_enqueue_script( 'everest-forms' );
946
947 $form_id = isset( $atts['id'] ) ? absint( $atts['id'] ) : 0;
948 $form_fields = evf_get_form_fields( $form_id );
949 $form_data = EVF()->form->get( $form_id, array( 'content_only' => true ) );
950 $form_fields = isset( $form_data['form_fields'] ) ? $form_data['form_fields'] : array();
951
952 foreach ( $form_fields as $form_field ) {
953 if (
954 ( isset( $form_field['type'] ) && in_array( $form_field['type'], array( 'rating', 'likert', 'yes-no', 'scale-rating' ), true ) ) ||
955 ( isset( $form_field['survey_status'] ) && absint( $form_field['survey_status'] ) === 1 ) ||
956 ( isset( $form_field['quiz_status'] ) && absint( $form_field['quiz_status'] ) === 1 )
957 ) {
958 wp_enqueue_script( 'everest-forms-survey-polls-quiz-script' );
959 }
960 }
961
962 // Load jQuery flatpickr libraries. https://github.com/flatpickr/flatpickr.
963 if ( isset( $atts['id'] ) && evf_is_field_exists( $atts['id'], 'date-time' ) ) {
964 wp_enqueue_style( 'flatpickr' );
965 wp_enqueue_script( 'flatpickr' );
966 }
967
968 // Load jQuery mailcheck library - https://github.com/mailcheck/mailcheck.
969 if ( isset( $atts['id'] ) && evf_is_field_exists( $atts['id'], 'email' ) && (bool) apply_filters( 'everest_forms_mailcheck_enabled', true ) ) {
970 wp_enqueue_script( 'mailcheck' );
971 }
972
973 // Add custom CSS/JS
974 if ( isset( $atts['id'] ) ) {
975 self::add_custom_css_js( $atts['id'] );
976 }
977
978 $atts = shortcode_atts(
979 array(
980 'id' => false,
981 'type' => false,
982 'size' => false,
983 'text' => false,
984 'title' => false,
985 'description' => false,
986 'header_title' => false,
987 'footer_title' => false,
988 'header_desc' => false,
989 'footer_desc' => false,
990 ),
991 $atts,
992 'output'
993 );
994
995 // Scripts load action.
996 do_action( 'everest_forms_shortcode_scripts', $atts );
997
998 ob_start();
999 self::view( $atts );
1000 echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1001 }
1002
1003 /**
1004 * Form view.
1005 *
1006 * @param array $atts Attributes.
1007 */
1008 private static function view( $atts ) {
1009 $id = isset( $atts['id'] ) ? $atts['id'] : false;
1010 $title = isset( $atts['title'] ) ? $atts['title'] : false;
1011 $description = isset( $atts['description'] ) ? $atts['description'] : false;
1012 $popup_type = isset( $atts['type'] ) ? $atts['type'] : false;
1013 $popup_text = isset( $atts['text'] ) ? $atts['text'] : false;
1014 if ( empty( $id ) ) {
1015 return;
1016 }
1017
1018 // Grab the form data, if not found then we bail.
1019 $form = evf()->form->get( (int) $id );
1020
1021 if ( empty( $form ) ) {
1022 return;
1023 }
1024
1025 // A draft form may render only for a preview by a user who can manage it — e.g. the
1026 // Create-with-AI screen's iframe preview of a not-yet-published AI draft (see
1027 // EVF_AI_Form_Builder::create_form()). Everyone else's draft-status gate is unchanged.
1028 $is_previewable_draft = 'draft' === $form->post_status && current_user_can( 'manage_everest_forms' );
1029 if ( 'publish' !== $form->post_status && 'inactive' !== $form->post_status && ! $is_previewable_draft ) {
1030 return;
1031 }
1032
1033 // Basic form information.
1034 $form_data = apply_filters( 'everest_forms_frontend_form_data', evf_decode( $form->post_content ) );
1035 // For form confirmation backward compatilibity.
1036 $form_data = evf_form_confirmation_backward_compatibility( $form_data );
1037
1038 $form_id = absint( $form->ID );
1039 $settings = isset( $form_data['settings'] ) ? $form_data['settings'] : array();
1040 $action = esc_url_raw( remove_query_arg( 'evf-forms' ) );
1041 $title = filter_var( $title, FILTER_VALIDATE_BOOLEAN );
1042 $description = filter_var( $description, FILTER_VALIDATE_BOOLEAN );
1043 $errors = isset( evf()->task->errors[ $form_id ] ) ? evf()->task->errors[ $form_id ] : array();
1044 $form_enabled = isset( $form_data['form_enabled'] ) ? absint( $form_data['form_enabled'] ) : 1;
1045 $kff_enabled = isset( $settings['keyboard_friendly_form'] ) ? absint( $settings['keyboard_friendly_form'] ) : 0;
1046 $disable_message = isset( $form_data['settings']['form_disable_message'] ) ? evf_string_translation( $form_data['id'], 'form_disable_message', $form_data['settings']['form_disable_message'] ) : __( 'This form is disabled.', 'everest-forms' );
1047 $stripe_via_selector = function_exists( 'evf_is_gateway_in_selector_allowlist' ) && evf_is_gateway_in_selector_allowlist( array( 'form_data' => $form_data, 'gateway' => 'stripe' ) );
1048 $square_via_selector = function_exists( 'evf_is_gateway_in_selector_allowlist' ) && evf_is_gateway_in_selector_allowlist( array( 'form_data' => $form_data, 'gateway' => 'square' ) );
1049 $paypal_via_selector = function_exists( 'evf_is_gateway_in_selector_allowlist' ) && evf_is_gateway_in_selector_allowlist( array( 'form_data' => $form_data, 'gateway' => 'paypal' ) );
1050 if ( ( isset( $form_data['payments']['stripe']['enable_stripe'] ) && '1' === $form_data['payments']['stripe']['enable_stripe'] ) || $stripe_via_selector || ( isset( $form_data['payments']['square']['enable_square'] ) && '1' === $form_data['payments']['square']['enable_square'] ) || $square_via_selector || $paypal_via_selector ) {
1051 $ajax_form_submission = 1;
1052 } else {
1053 $ajax_form_submission = isset( $settings['ajax_form_submission'] ) ? $settings['ajax_form_submission'] : 0;
1054 }
1055
1056 if ( 0 !== evf_string_to_bool( $ajax_form_submission ) ) {
1057 wp_enqueue_script( 'everest-forms-ajax-submission' );
1058 }
1059
1060 // If the form is disabled or does not contain any fields do not proceed.
1061 if ( empty( $form_data['form_fields'] ) ) {
1062 echo '<!-- Everest Forms: no fields, form hidden -->';
1063 return;
1064 } elseif ( 1 !== $form_enabled ) {
1065 if ( ! empty( $disable_message ) ) {
1066 printf( '<p class="everst-forms-form-disable-notice everest-forms-notice everest-forms-notice--info">%s</p>', esc_textarea( $disable_message ) );
1067 }
1068 return;
1069 }
1070
1071 // We need to stop output processing in case we are on AMP page.
1072 if ( evf_is_amp( false ) && ( ! current_theme_supports( 'amp' ) || apply_filters( 'evfforms_amp_pro', class_exists( 'EverestForms_Pro' ) ) || ! is_ssl() || ! defined( 'AMP__VERSION' ) || version_compare( AMP__VERSION, '1.2', '<' ) ) ) {
1073
1074 $full_page_url = home_url( add_query_arg( 'nonamp', '1' ) . '#evfforms-' . absint( $form->ID ) );
1075
1076 /**
1077 * Allow modifying the text or url for the full page on the AMP pages.
1078 *
1079 * @since 1.4.1.1
1080 * @since 1.7.1 Added $form_id, $full_page_url, and $form_data arguments.
1081 *
1082 * @param int $form_id Form id.
1083 * @param array $form_data Form data and settings.
1084 *
1085 * @return string
1086 */
1087 $text = (string) apply_filters(
1088 'evf_frontend_shortcode_amp_text',
1089 sprintf( /* translators: %s - URL to a non-amp version of a page with the form. */
1090 __( '<a href="%s">Go to the full page</a> to view and submit the form.', 'everest-forms' ),
1091 esc_url( $full_page_url )
1092 ),
1093 $form_id,
1094 $full_page_url,
1095 $form_data
1096 );
1097
1098 printf(
1099 '<p class="evf-shortcode-amp-text">%s</p>',
1100 wp_kses_post( $text )
1101 );
1102
1103 return;
1104 }
1105
1106 $message = isset( $form_data['settings']['successful_form_submission_message'] ) ? $form_data['settings']['successful_form_submission_message'] : esc_html__( 'Thanks for contacting us! We will be in touch with you shortly.', 'everest-forms' );
1107
1108 // Before output hook.
1109 do_action( 'everest_forms_frontend_output_before', $form_data, $form );
1110
1111 // Check for return hash.
1112 if (
1113 ! empty( $_GET['everest_forms_return'] ) // phpcs:ignore WordPress.Security.NonceVerification
1114 && evf()->task->is_valid_hash
1115 && absint( evf()->task->form_data['id'] ) === $form_id
1116 ) {
1117 $query_args = base64_decode($_GET['everest_forms_return']); // phpcs:ignore
1118 parse_str( $query_args, $query_arg );
1119 $message = isset( $form_data['settings']['successful_form_submission_message'] ) ? $form_data['settings']['successful_form_submission_message'] : esc_html__( 'Thanks for contacting us! We will be in touch with you shortly.', 'everest-forms' );
1120 $pdf_submission = isset( $form_data['settings']['pdf_submission']['enable_pdf_submission'] ) && 0 !== $form_data['settings']['pdf_submission']['enable_pdf_submission'] ? $form_data['settings']['pdf_submission'] : '';
1121 if ( defined( 'EVF_PDF_SUBMISSION_VERSION' ) && ( 'yes' === get_option( 'everest_forms_pdf_download_after_submit', 'no' ) || ( isset( $pdf_submission['everest_forms_pdf_download_after_submit'] ) && 'yes' === $pdf_submission['everest_forms_pdf_download_after_submit'] ) ) ) {
1122 global $__everest_form_id;
1123 global $__everest_form_entry_id;
1124 $__everest_form_id = $form_id;
1125 $__everest_form_entry_id = isset( $query_arg['entry_id'] ) ? $query_arg['entry_id'] : 0;
1126 }
1127
1128 if ( 'same' === $form_data['settings']['redirect_to'] ) {
1129 evf_add_notice( $message, 'success' );
1130 }
1131
1132 do_action( 'everest_forms_frontend_output_success', evf()->task->form_data, evf()->task->form_fields, evf()->task->entry_id );
1133 return;
1134 }
1135
1136 // Check the form state type
1137 $form_state_type = isset( $form_data['settings']['form_state_type'] ) ? $form_data['settings']['form_state_type'] : 'hide';
1138
1139 if ( 'hide' === $form_state_type ) {
1140 $message_display_location = isset( $form_data['settings']['message_display_location_of_hide'] ) ? $form_data['settings']['message_display_location_of_hide'] : 'hide';
1141 } else {
1142 $message_display_location = isset( $form_data['settings']['message_display_location_of_reset'] ) ? $form_data['settings']['message_display_location_of_reset'] : 'top';
1143 }
1144 // If conditional logic match then getting messag and position.
1145 if ( ! empty( $_REQUEST['evf_popup_message'] ) ) {
1146 $message = sanitize_text_field( $_REQUEST['evf_popup_message'] );
1147 }
1148 if ( ! empty( $_REQUEST['evf_message_display_location'] ) ) {
1149 $message_display_location = sanitize_text_field( $_REQUEST['evf_message_display_location'] );
1150 }
1151
1152 $form_state_type = '';
1153 if ( ! empty( $_REQUEST['evf_form_state_type'] ) ) {
1154 $form_state_type = sanitize_text_field( $_REQUEST['evf_form_state_type'] );
1155 }
1156
1157 $success = apply_filters( 'everest_forms_success', false, $form_id );
1158 if ( $success && ! empty( $form_data ) && 'hide' === $message_display_location ) {
1159 $hide_classes = apply_filters( 'everest_forms_frontend_container_class', array(), $form_data );
1160 // The container's own background image (v1 direct background-image, or Style
1161 // Customizer v2's ::before layer) isn't part of the replaced content below, so it
1162 // needs its own class-driven CSS rule to disappear too (EVF-2684).
1163 $hide_classes[] = 'everest-forms-form-hidden';
1164 if ( ! empty( $settings['form_class'] ) ) {
1165 $hide_classes = array_merge( $hide_classes, explode( ' ', $settings['form_class'] ) );
1166 }
1167 if ( ! empty( $settings['layout_class'] ) ) {
1168 $hide_classes = array_merge( $hide_classes, explode( ' ', $settings['layout_class'] ) );
1169 }
1170 $hide_classes = evf_sanitize_classes( $hide_classes, true );
1171
1172 printf( '<div class="evf-container %s" id="evf-%d">', esc_attr( $hide_classes ), absint( $form_id ) );
1173 do_action( 'everest_forms_frontend_output_success', $form_data );
1174 echo '</div><!-- .evf-container -->';
1175 return;
1176 }
1177
1178 // Allow filter to return early if some condition is not meet.
1179 if ( ! apply_filters( 'everest_forms_frontend_load', true, $form_data ) ) {
1180 do_action( 'everest_forms_frontend_not_loaded', $form_data, $form );
1181 return;
1182 }
1183
1184 /**
1185 * BW compatiable for multi-parts form.
1186 *
1187 * @todo Remove in Major EVF version 1.6.0
1188 */
1189 if ( defined( 'EVF_MULTI_PART_PLUGIN_FILE' ) ) {
1190 include_once ABSPATH . 'wp-admin/includes/plugin.php';
1191 $plugin_data = get_plugin_data( EVF_MULTI_PART_PLUGIN_FILE, false, false );
1192
1193 if ( version_compare( $plugin_data['Version'], '1.3.0', '<' ) ) {
1194 $settings_defaults = array(
1195 'indicator' => 'progress',
1196 'indicator_color' => '#7e3bd0',
1197 'nav_align' => 'center',
1198 );
1199
1200 if ( isset( $form_data['settings']['enable_multi_part'] ) && evf_string_to_bool( $form_data['settings']['enable_multi_part'] ) ) {
1201 $settings = isset( $form_data['settings']['multi_part'] ) ? $form_data['settings']['multi_part'] : array();
1202
1203 if ( ! empty( $form_data['multi_part'] ) ) {
1204 self::$parts = array(
1205 'total' => count( $form_data['multi_part'] ),
1206 'current' => 1,
1207 'parts' => array_values( $form_data['multi_part'] ),
1208 'settings' => wp_parse_args( $settings, $settings_defaults ),
1209 );
1210 }
1211 } else {
1212 self::$parts = array(
1213 'total' => '',
1214 'current' => '',
1215 'parts' => array(),
1216 'settings' => $settings_defaults,
1217 );
1218 }
1219 }
1220 }
1221
1222 // Allow Multi-Part to be customized.
1223 $parts = ! empty( self::$parts[ $form_id ] ) ? self::$parts[ $form_id ] : array();
1224 self::$parts[ $form_id ] = apply_filters( 'everest_forms_parts_data', $parts, $form_data, $form_id );
1225
1226 // Allow final action to be customized.
1227 $action = apply_filters( 'everest_forms_frontend_form_action', $action, $form_data );
1228
1229 // Allow form container classes to be filtered and user defined classes.
1230 $classes = apply_filters( 'everest_forms_frontend_container_class', array(), $form_data );
1231 if ( ! empty( $settings['form_class'] ) ) {
1232 $classes = array_merge( $classes, explode( ' ', $settings['form_class'] ) );
1233 }
1234 if ( ! empty( $settings['layout_class'] ) ) {
1235 $classes = array_merge( $classes, explode( ' ', $settings['layout_class'] ) );
1236 }
1237 $classes = evf_sanitize_classes( $classes, true );
1238
1239 $form_atts = array(
1240 'id' => sprintf( 'evf-form-%d', absint( $form_id ) ),
1241 'class' => array( 'everest-form' ),
1242 'data' => array(
1243 'formid' => absint( $form_id ),
1244 'ajax_submission' => $ajax_form_submission,
1245 'keyboard_friendly_form' => $kff_enabled,
1246 ),
1247 'atts' => array(
1248 'method' => 'post',
1249 'enctype' => 'multipart/form-data',
1250 'action' => esc_url( $action ),
1251 ),
1252 );
1253
1254 if ( evf_is_amp() ) {
1255
1256 // Set submitting state.
1257 if ( ! isset( $form_atts['atts']['on'] ) ) {
1258 $form_atts['atts']['on'] = '';
1259 } else {
1260 $form_atts['atts']['on'] .= ';';
1261 }
1262 $form_atts['atts']['on'] .= sprintf(
1263 'submit:AMP.setState( %1$s ); submit-success:AMP.setState( %2$s ); submit-error:AMP.setState( %2$s );',
1264 wp_json_encode(
1265 array(
1266 self::get_form_amp_state_id( $form_id ) => array(
1267 'submitting' => true,
1268 ),
1269 )
1270 ),
1271 wp_json_encode(
1272 array(
1273 self::get_form_amp_state_id( $form_id ) => array(
1274 'submitting' => false,
1275 ),
1276 )
1277 )
1278 );
1279
1280 // Upgrade the form to be an amp-form to avoid sanitizer conversion.
1281 if ( isset( $form_atts['atts']['action'] ) ) {
1282 $form_atts['atts']['action-xhr'] = $form_atts['atts']['action'];
1283 unset( $form_atts['atts']['action'] );
1284
1285 $form_atts['atts']['verify-xhr'] = $form_atts['atts']['action-xhr'];
1286 }
1287 }
1288
1289 $form_atts = apply_filters( 'everest_forms_frontend_form_atts', $form_atts, $form_data );
1290 // Begin to build the output.
1291 do_action( 'everest_forms_frontend_output_container_before', $form_data, $form );
1292
1293 printf( '<div class="evf-container %s" id="evf-%d">', esc_attr( $classes ), absint( $form_id ) );
1294
1295 do_action( 'everest_forms_frontend_output_form_before', $form_data, $form, $errors );
1296 if ( isset( $atts['type'] ) && 'popup-button' === $popup_type ) {
1297 printf( "<button class='everest-forms-modal-link everest-forms-modal-link-%s'>%s</button>", esc_attr( $atts['id'] ), esc_html( $popup_text ) );
1298 do_action( 'everest_form_popup', $atts );
1299 } elseif ( isset( $atts['type'] ) && 'popup-link' === $popup_type ) {
1300 printf( "<a href='javascript:void(0);' class='everest-forms-modal-link everest-forms-modal-link-%s'>%s</a>", esc_attr( $atts['id'] ), esc_html( $popup_text ) );
1301 do_action( 'everest_form_popup', $atts );
1302 } elseif ( isset( $atts['type'] ) && 'popup' === $popup_type ) {
1303 do_action( 'everest_form_popup', $atts );
1304 } else {
1305 if ( $success && ! empty( $form_data ) && 'top' === $message_display_location ) {
1306 evf_add_notice( $message, 'success' );
1307 do_action( 'everest_forms_frontend_output_success', $form_data );
1308 } elseif ( $success && ! empty( $form_data ) && 'popup' === $message_display_location ) {
1309 $form_atts['data']['message_location'] = $message_display_location;
1310 $form_atts['data']['message'] = esc_html( $message );
1311 }
1312 // Adding the form state type. hide or reset
1313 $form_atts['data']['form_state_type'] = $form_state_type;
1314
1315 echo '<form ' . evf_html_attributes( $form_atts['id'], $form_atts['class'], $form_atts['data'], $form_atts['atts'] ) . '>';
1316 if ( evf_is_amp() ) {
1317 $state = array(
1318 'submitting' => false,
1319 );
1320 printf(
1321 '<amp-state id="%s"><script type="application/json">%s</script></amp-state>',
1322 self::get_form_amp_state_id( $form_id ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1323 wp_json_encode( $state )
1324 );
1325 }
1326 do_action( 'everest_forms_frontend_output', $form_data, $title, $description, $errors );
1327
1328 echo '</form>';
1329
1330 if ( $success && ! empty( $form_data ) && 'bottom' === $message_display_location ) {
1331 do_action( 'everest_forms_frontend_output_success', $form_data );
1332 evf_add_notice( $message, 'success' );
1333 do_action( 'everest_forms_frontend_output_success', $form_data );
1334 }
1335 }
1336
1337 do_action( 'everest_forms_frontend_output_form_after', $form_data, $form );
1338
1339 echo '</div><!-- .evf-container -->';
1340
1341 // After output hook.
1342 do_action( 'everest_forms_frontend_output_after', $form_data, $form );
1343
1344 // Debug information.
1345 if ( is_super_admin() ) {
1346 evf_debug_data( $form_data );
1347 }
1348 }
1349
1350 /**
1351 * ReCaptcha Langauge.
1352 *
1353 * @param url $url Recaptcha URL.
1354 *
1355 * @return $url
1356 */
1357 public static function evf_recaptcha_language( $url ) {
1358 return esc_url_raw( add_query_arg( array( 'hl' => get_option( 'everest_forms_recaptcha_recaptcha_language', 'en-GB' ) ), $url ) );
1359 }
1360
1361 /**
1362 * Adds custom CSS and JavaScript code.
1363 *
1364 * @param int $form_id Form ID.
1365 * @since 2.0.2
1366 * @return void
1367 */
1368 public static function add_custom_css_js( $form_id ) {
1369 $form_id = absint( $form_id );
1370 if ( $form_id <= 0 ) {
1371 return;
1372 }
1373
1374 $form = evf()->form->get( $form_id );
1375 // Check the form_data exist or not.
1376 if ( ! $form ) {
1377 return;
1378 }
1379
1380 $hook = false;
1381
1382 if ( ! did_action( 'wp_head' ) ) {
1383 $hook = 'wp_head';
1384 } elseif ( ! did_action( 'wp_footer' ) ) {
1385 $hook = 'wp_footer';
1386 }
1387
1388 $form_data = apply_filters( 'everest_forms_frontend_form_data', evf_decode( $form->post_content ) );
1389 $settings = isset( $form_data['settings'] ) ? $form_data['settings'] : array();
1390
1391 if ( isset( $settings['evf-enable-custom-css'] ) && evf_string_to_bool( $settings['evf-enable-custom-css'] ) ) {
1392 $custom_css = isset( $settings['evf-custom-css'] ) ? $settings['evf-custom-css'] : '';
1393 $custom_css = preg_match( '#</?\w+#', $custom_css ) ? '' : $custom_css;
1394 if ( ! empty( $custom_css ) ) {
1395 if ( $hook ) {
1396 add_action(
1397 $hook,
1398 function () use ( $custom_css, $form_id ) {
1399 ?>
1400 <style id="<?php echo esc_attr( 'evf-custom-css-' . $form_id ); ?>">
1401 <?php echo esc_attr( $custom_css ); ?>
1402 </style>
1403 <?php
1404 }
1405 );
1406 } else {
1407 ?>
1408 <style id="<?php echo esc_attr( 'evf-custom-css-' . $form_id ); ?>">
1409 <?php echo esc_attr( $custom_css ); ?>
1410 </style>
1411 <?php
1412 }
1413 }
1414 }
1415
1416 if ( isset( $settings['evf-enable-custom-js'] ) && evf_string_to_bool( $settings['evf-enable-custom-js'] ) ) {
1417 $custom_js = isset( $settings['evf-custom-js'] ) ? wp_specialchars_decode( wp_kses_decode_entities( $settings['evf-custom-js'] ) ) : '';
1418 if ( ! empty( $custom_js ) ) {
1419 $custom_js = sprintf(
1420 '( function( $ ) {
1421 $(document).ready( function() {
1422 try {
1423 %s
1424 }
1425 catch( err ) {}
1426 });
1427 })( jQuery )',
1428 $custom_js
1429 );
1430
1431 if ( ! wp_script_is('evf-custom', 'registered') ) {
1432 wp_register_script(
1433 'evf-custom',
1434 '',
1435 array('jquery'),
1436 EVF_VERSION,
1437 true
1438 );
1439 }
1440
1441 if ( ! wp_script_is('evf-custom', 'enqueued' ) ) {
1442 wp_add_inline_script('evf-custom', $custom_js);
1443 wp_enqueue_script('evf-custom');
1444 }
1445 }
1446 }
1447 }
1448
1449 /**
1450 * Function to enable the minimum form submission waiting time.
1451 *
1452 * @since 3.0.2
1453 *
1454 * @param array $form_data Form Data.
1455 */
1456 public static function evf_form_submission_waiting_time( $form_data ) {
1457 $form_submission_waiting_time_enable = isset( $form_data['settings']['form_submission_min_waiting_time'] ) ? $form_data['settings']['form_submission_min_waiting_time'] : '';
1458 $submission_duration = isset( $form_data['settings']['form_submission_min_waiting_time_input'] ) ? $form_data['settings']['form_submission_min_waiting_time_input'] : '';
1459
1460 if ( '1' === $form_submission_waiting_time_enable ) {
1461 echo "<input type='hidden' id='evf_submission_start_time' name='evf_submission_start_time'/>";
1462 } else {
1463 return '';
1464 }
1465 }
1466 /**
1467 * This fuction add the inline script to update the nonce to avoid nonce from caching.
1468 *
1469 * @since 3.3.0
1470 *
1471 * @param [type] $form_data The form data.
1472 * @param [type] $title The title for the form.
1473 * @param [type] $description The Form description.
1474 * @return void
1475 */
1476 public static function inline_script_to_update_nonce( $form_data, $title, $description ) {
1477 $form_id = $form_data['id'];
1478 $form = evf()->form->get( absint( $form_id ) );
1479
1480 if ( empty( $form ) ) {
1481 return;
1482 }
1483
1484 add_action(
1485 'wp_footer',
1486 function () use ( $form_id ) {
1487 echo '<script type="text/javascript">jQuery(function() {'
1488 . 'jQuery.ajax({'
1489 . "url: '" . esc_url( admin_url( 'admin-ajax.php', is_ssl() ? 'https' : 'http' ) ) . "',"
1490 . 'type: "POST",'
1491 . 'data: {'
1492 . 'action: "everest_forms_get_form_update_nonce",'
1493 . 'form_id: "' . (int) $form_id . '",'
1494 . '},'
1495 . 'success: function (response) {'
1496 . "jQuery('#_wpnonce" . (int) $form_id . "').val( response.data );"
1497 . '}'
1498 . '});'
1499 . '})</script>';
1500 },
1501 99
1502 );
1503 }
1504 }
1505