PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.8.2
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.8.2
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / controllers / FrmFieldsController.php

FrmFieldsController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.8.2, at classes/controllers/FrmFieldsController.php

949 lines 26.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmFieldsController {
7
8 public static function load_field() {
9 FrmAppHelper::permission_check( 'frm_edit_forms' );
10 check_ajax_referer( 'frm_ajax', 'nonce' );
11
12 // Javascript may be included in some field settings.
13 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
14 $fields = isset( $_POST['field'] ) ? wp_unslash( $_POST['field'] ) : array();
15 if ( empty( $fields ) ) {
16 wp_die();
17 }
18
19 $_GET['page'] = 'formidable';
20
21 $values = array(
22 'id' => FrmAppHelper::get_post_param( 'form_id', '', 'absint' ),
23 'doing_ajax' => true,
24 );
25 $field_html = array();
26
27 foreach ( $fields as $field ) {
28 $field = htmlspecialchars_decode( nl2br( $field ) );
29 $field = json_decode( $field );
30 if ( ! isset( $field->id ) || ! is_numeric( $field->id ) ) {
31 // this field may have already been loaded
32 continue;
33 }
34
35 if ( ! isset( $field->value ) ) {
36 $field->value = '';
37 }
38 $field->field_options = json_decode( json_encode( $field->field_options ), true );
39 $field->options = json_decode( json_encode( $field->options ), true );
40 $field->default_value = json_decode( json_encode( $field->default_value ), true );
41
42 ob_start();
43 self::load_single_field( $field, $values );
44 $field_html[ absint( $field->id ) ] = ob_get_contents();
45 ob_end_clean();
46 }
47
48 echo json_encode( $field_html );
49
50 wp_die();
51 }
52
53 /**
54 * Create a new field with ajax
55 */
56 public static function create() {
57 FrmAppHelper::permission_check( 'frm_edit_forms' );
58 check_ajax_referer( 'frm_ajax', 'nonce' );
59
60 $field_type = FrmAppHelper::get_post_param( 'field_type', '', 'sanitize_text_field' );
61 $form_id = FrmAppHelper::get_post_param( 'form_id', 0, 'absint' );
62
63 do_action( 'frm_before_create_field', $field_type, $form_id );
64
65 $field = self::include_new_field( $field_type, $form_id );
66
67 // this hook will allow for multiple fields to be added at once
68 do_action( 'frm_after_field_created', $field, $form_id );
69
70 wp_die();
71 }
72
73 /**
74 * Set up and create a new field
75 *
76 * @param string $field_type
77 * @param integer $form_id
78 *
79 * @return array|bool
80 */
81 public static function include_new_field( $field_type, $form_id ) {
82 $field_values = FrmFieldsHelper::setup_new_vars( $field_type, $form_id );
83
84 // When a new field is added to the form, flag it as draft and hide it from the front-end.
85 $field_values['field_options']['draft'] = 1;
86
87 /**
88 * @param array $field_values
89 */
90 $field_values = apply_filters( 'frm_before_field_created', $field_values );
91 $field_id = FrmField::create( $field_values );
92
93 if ( ! $field_id ) {
94 return false;
95 }
96
97 $field = self::get_field_array_from_id( $field_id );
98
99 $values = array();
100 if ( FrmAppHelper::pro_is_installed() ) {
101 $values['post_type'] = FrmProFormsHelper::post_type( $form_id );
102
103 $parent_form_id = FrmDb::get_var( 'frm_forms', array( 'id' => $form_id ), 'parent_form_id' );
104 if ( $parent_form_id ) {
105 $field['parent_form_id'] = $parent_form_id;
106 }
107 }
108
109 self::load_single_field( $field, $values, $form_id );
110
111 return $field;
112 }
113
114 public static function duplicate() {
115 FrmAppHelper::permission_check( 'frm_edit_forms' );
116 check_ajax_referer( 'frm_ajax', 'nonce' );
117
118 $field_id = FrmAppHelper::get_post_param( 'field_id', 0, 'absint' );
119 $form_id = FrmAppHelper::get_post_param( 'form_id', 0, 'absint' );
120
121 $new_field = FrmField::duplicate_single_field( $field_id, $form_id );
122
123 if ( is_array( $new_field ) && ! empty( $new_field['field_id'] ) ) {
124 self::load_single_field( $new_field['field_id'], $new_field['values'] );
125 }
126
127 wp_die();
128 }
129
130 /**
131 * @since 3.0
132 *
133 * @param int $field_id
134 *
135 * @return array
136 */
137 public static function get_field_array_from_id( $field_id ) {
138 $field = FrmField::getOne( $field_id );
139
140 return FrmFieldsHelper::setup_edit_vars( $field );
141 }
142
143 /**
144 * @since 3.0
145 *
146 * @param int|array|object $field_object
147 * @param array $values
148 * @param int $form_id
149 */
150 public static function load_single_field( $field_object, $values, $form_id = 0 ) {
151 global $frm_vars;
152 $frm_vars['is_admin'] = true;
153
154 if ( is_numeric( $field_object ) ) {
155 $field_object = FrmField::getOne( $field_object );
156 } elseif ( is_array( $field_object ) ) {
157 $field = $field_object;
158 $field_object = FrmField::getOne( $field['id'] );
159 }
160
161 $field_obj = FrmFieldFactory::get_field_factory( $field_object );
162 $display = self::display_field_options( array(), $field_obj );
163
164 $ajax_loading = isset( $values['ajax_load'] ) && $values['ajax_load'];
165 $ajax_this_field = isset( $values['count'] ) && $values['count'] > 10 && ! in_array( $field_object->type, array( 'divider', 'end_divider' ) );
166
167 if ( $ajax_loading && $ajax_this_field ) {
168 $li_classes = self::get_classes_for_builder_field( array(), $display, $field_obj );
169 include( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/ajax-field-placeholder.php' );
170 } else {
171 if ( ! isset( $field ) && is_object( $field_object ) ) {
172 $field_object->parent_form_id = isset( $values['id'] ) ? $values['id'] : $field_object->form_id;
173
174 $field = FrmFieldsHelper::setup_edit_vars( $field_object );
175 }
176
177 $li_classes = self::get_classes_for_builder_field( $field, $display, $field_obj );
178 $li_classes .= ' ui-state-default widgets-holder-wrap';
179
180 require( FrmAppHelper::plugin_path() . '/classes/views/frm-forms/add_field.php' );
181 }
182 }
183
184 /**
185 * @since 3.0
186 */
187 private static function get_classes_for_builder_field( $field, $display, $field_info ) {
188 $li_classes = $field_info->form_builder_classes( $display['type'] );
189 $li_classes .= ' frm_form_field frmstart ';
190
191 if ( isset( $field['classes'] ) ) {
192 $li_classes .= trim( $field['classes'] ) . ' ';
193 }
194
195 $li_classes .= 'frmend';
196
197 if ( $field ) {
198 $li_classes = apply_filters( 'frm_build_field_class', $li_classes, $field );
199 }
200
201 return $li_classes;
202 }
203
204 public static function destroy() {
205 FrmAppHelper::permission_check( 'frm_edit_forms' );
206 check_ajax_referer( 'frm_ajax', 'nonce' );
207
208 $field_id = FrmAppHelper::get_post_param( 'field_id', 0, 'absint' );
209 FrmField::destroy( $field_id );
210 wp_die();
211 }
212
213 /**
214 * Field Options.
215 */
216 public static function import_options() {
217 FrmAppHelper::permission_check( 'frm_edit_forms' );
218 check_ajax_referer( 'frm_ajax', 'nonce' );
219
220 if ( ! is_admin() || ! current_user_can( 'frm_edit_forms' ) ) {
221 return;
222 }
223
224 $field_id = FrmAppHelper::get_param( 'field_id', '', 'post', 'absint' );
225 $field = FrmField::getOne( $field_id );
226
227 if ( ! in_array( $field->type, array( 'radio', 'checkbox', 'select' ) ) ) {
228 return;
229 }
230
231 $field = FrmFieldsHelper::setup_edit_vars( $field );
232 $opts = FrmAppHelper::get_param( 'opts', '', 'post', 'wp_kses_post' );
233 $opts = explode( "\n", rtrim( $opts, "\n" ) );
234 $opts = array_map( 'trim', $opts );
235
236 $separate = FrmAppHelper::get_param( 'separate', '', 'post', 'sanitize_text_field' );
237 $field['separate_value'] = ( $separate === 'true' );
238
239 if ( $field['separate_value'] ) {
240 foreach ( $opts as $opt_key => $opt ) {
241 if ( strpos( $opt, '|' ) !== false ) {
242 $vals = explode( '|', $opt );
243 $opts[ $opt_key ] = array(
244 'label' => trim( $vals[0] ),
245 'value' => trim( $vals[1] ),
246 );
247 unset( $vals );
248 }
249 unset( $opt_key, $opt );
250 }
251 }
252
253 // Keep other options after bulk update.
254 if ( isset( $field['field_options']['other'] ) && $field['field_options']['other'] == true ) {
255 $other_array = array();
256 foreach ( $field['options'] as $opt_key => $opt ) {
257 if ( FrmFieldsHelper::is_other_opt( $opt_key ) ) {
258 $other_array[ $opt_key ] = $opt;
259 }
260 unset( $opt_key, $opt );
261 }
262 if ( ! empty( $other_array ) ) {
263 $opts = array_merge( $opts, $other_array );
264 }
265 }
266
267 $field['options'] = $opts;
268
269 FrmFieldsHelper::show_single_option( $field );
270
271 wp_die();
272 }
273
274 /**
275 * @since 4.0
276 *
277 * @param array $atts - Includes field array, field_obj, display array, values array.
278 */
279 public static function load_single_field_settings( $atts ) {
280 $field = $atts['field'];
281 $field_obj = $atts['field_obj'];
282 $values = $atts['values'];
283 $display = $atts['display'];
284 unset( $atts );
285
286 if ( ! isset( $field['unique'] ) ) {
287 $field['unique'] = false;
288 }
289
290 if ( ! isset( $field['read_only'] ) ) {
291 $field['read_only'] = false;
292 }
293
294 $field_types = FrmFieldsHelper::get_field_types( $field['type'] );
295 $pro_field_selection = FrmField::pro_field_selection();
296 $all_field_types = array_merge( $pro_field_selection, FrmField::field_selection() );
297 $disabled_fields = FrmAppHelper::pro_is_installed() ? array() : $pro_field_selection;
298 $frm_settings = FrmAppHelper::get_settings();
299
300 if ( ! isset( $all_field_types[ $field['type'] ] ) ) {
301 // Add fallback for an add-on field type that has been deactivated.
302 $all_field_types[ $field['type'] ] = array(
303 'name' => ucfirst( $field['type'] ),
304 'icon' => 'frm_icon_font frm_pencil_icon',
305 );
306 } elseif ( ! is_array( $all_field_types[ $field['type'] ] ) ) {
307 // Fallback for fields added in a more basic way.
308 FrmFormsHelper::prepare_field_type( $all_field_types[ $field['type'] ] );
309 }
310
311 $type_name = $all_field_types[ $field['type'] ]['name'];
312 if ( $field['type'] === 'divider' && FrmField::is_option_true( $field, 'repeat' ) ) {
313 $type_name = $all_field_types['divider|repeat']['name'];
314 }
315
316 if ( $display['default'] ) {
317 $default_value_types = self::default_value_types( $field, compact( 'display' ) );
318 }
319
320 if ( $display['clear_on_focus'] && is_array( $field['placeholder'] ) ) {
321 $field['placeholder'] = implode( ', ', $field['placeholder'] );
322 }
323
324 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/settings.php';
325 }
326
327 /**
328 * Get the list of default value types that can be toggled in the builder.
329 *
330 * @since 4.0
331 * @return array
332 */
333 private static function default_value_types( $field, $atts ) {
334 $types = array(
335 'default_value' => array(
336 'class' => '',
337 'icon' => 'frm_icon_font frm_text2_icon',
338 'title' => __( 'Default Value (Text)', 'formidable' ),
339 'data' => array(
340 'frmshow' => '#default-value-for-',
341 ),
342 ),
343 'calc' => array(
344 'class' => 'frm_show_upgrade frm_noallow',
345 'title' => __( 'Default Value (Calculation)', 'formidable' ),
346 'icon' => 'frm_icon_font frm_calculator_icon',
347 'data' => array(
348 'medium' => 'calculations',
349 'upgrade' => __( 'Calculator forms', 'formidable' ),
350 ),
351 ),
352 'get_values_field' => array(
353 'class' => 'frm_show_upgrade frm_noallow',
354 'title' => __( 'Default Value (Lookup)', 'formidable' ),
355 'icon' => 'frm_icon_font frm_search_icon',
356 'data' => array(
357 'medium' => 'lookup',
358 'upgrade' => __( 'Lookup fields', 'formidable' ),
359 ),
360 ),
361 );
362
363 $types = apply_filters( 'frm_default_value_types', $types, $atts );
364
365 if ( FrmAppHelper::pro_is_installed() && ! FrmAppHelper::meets_min_pro_version( '4.0' ) ) {
366 // Prevent settings from showing in 2 spots.
367 unset( $types['calc'], $types['get_values_field'] );
368 }
369
370 // Set active class.
371 $settings = array_keys( $types );
372 $active = 'default_value';
373
374 foreach ( $settings as $type ) {
375 if ( ! empty( $field[ $type ] ) ) {
376 $active = $type;
377 }
378 }
379
380 $types[ $active ]['class'] .= ' current';
381 $types[ $active ]['current'] = true;
382
383 return $types;
384 }
385
386 public static function change_type( $type ) {
387 $type_switch = array(
388 'scale' => 'radio',
389 'star' => 'radio',
390 '10radio' => 'radio',
391 'rte' => 'textarea',
392 'website' => 'url',
393 'image' => 'url',
394 );
395 if ( isset( $type_switch[ $type ] ) ) {
396 $type = $type_switch[ $type ];
397 }
398
399 $pro_fields = FrmField::pro_field_selection();
400 // We want to keep credit_card types as credit card types for Stripe Lite.
401 // The credit_card key is set for backward compatibility.
402 unset( $pro_fields['credit_card'] );
403
404 if ( array_key_exists( $type, $pro_fields ) ) {
405 $type = 'text';
406 }
407
408 return $type;
409 }
410
411 /**
412 * @param array $settings
413 * @param object $field_info
414 *
415 * @return array
416 */
417 public static function display_field_options( $settings, $field_info = null ) {
418 if ( $field_info ) {
419 $settings = $field_info->display_field_settings();
420 $settings['field_data'] = $field_info->field;
421 }
422
423 return apply_filters( 'frm_display_field_options', $settings );
424 }
425
426 /**
427 * Display the format option
428 *
429 * @since 3.0
430 *
431 * @param array $field
432 */
433 public static function show_format_option( $field ) {
434 include( FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/value-format.php' );
435 }
436
437 public static function input_html( $field, $echo = true ) {
438 $class = array();
439 self::add_input_classes( $field, $class );
440
441 $add_html = array();
442 self::add_html_size( $field, $add_html );
443 self::add_html_length( $field, $add_html );
444 self::add_html_placeholder( $field, $add_html, $class );
445 self::add_validation_messages( $field, $add_html );
446
447 $class = apply_filters( 'frm_field_classes', implode( ' ', $class ), $field );
448
449 FrmFormsHelper::add_html_attr( $class, 'class', $add_html );
450
451 self::add_shortcodes_to_html( $field, $add_html );
452 self::add_pattern_attribute( $field, $add_html );
453
454 $add_html = apply_filters( 'frm_field_extra_html', $add_html, $field );
455 $add_html = ' ' . implode( ' ', $add_html ) . ' ';
456
457 if ( $echo ) {
458 echo $add_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
459 }
460
461 return $add_html;
462 }
463
464 private static function add_input_classes( $field, array &$class ) {
465 if ( isset( $field['input_class'] ) && ! empty( $field['input_class'] ) ) {
466 $class[] = $field['input_class'];
467 }
468
469 if ( $field['type'] == 'hidden' || $field['type'] == 'user_id' ) {
470 return;
471 }
472
473 if ( isset( $field['size'] ) && $field['size'] > 0 ) {
474 $class[] = 'auto_width';
475 }
476 }
477
478 private static function add_html_size( $field, array &$add_html ) {
479 $size_fields = array(
480 'select',
481 'data',
482 'time',
483 'hidden',
484 'file',
485 'lookup',
486 );
487
488 if ( ! isset( $field['size'] ) || $field['size'] <= 0 || in_array( $field['type'], $size_fields ) ) {
489 return;
490 }
491
492 if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
493 return;
494 }
495
496 if ( is_numeric( $field['size'] ) ) {
497 $field['size'] .= 'px';
498 }
499
500 $important = apply_filters( 'frm_use_important_width', 1, $field );
501 // Note: This inline styling must stay since we cannot realistically set a class for every possible field size.
502 $add_html['style'] = 'style="width:' . esc_attr( $field['size'] ) . ( $important ? ' !important' : '' ) . '"';
503
504 self::add_html_cols( $field, $add_html );
505 }
506
507 private static function add_html_cols( $field, array &$add_html ) {
508 if ( ! in_array( $field['type'], array( 'textarea', 'rte' ), true ) ) {
509 return;
510 }
511
512 // Convert to cols for textareas.
513 $calc = array(
514 '' => 9,
515 'px' => 9,
516 'rem' => 0.444,
517 'em' => 0.544,
518 );
519
520 // include "col" for valid html
521 $unit = trim( preg_replace( '/[0-9]+/', '', $field['size'] ) );
522
523 if ( ! isset( $calc[ $unit ] ) ) {
524 return;
525 }
526
527 $size = (float) str_replace( $unit, '', $field['size'] ) / $calc[ $unit ];
528
529 $add_html['cols'] = 'cols="' . absint( $size ) . '"';
530 }
531
532 private static function add_html_length( $field, array &$add_html ) {
533 // Check for max setting and if this field accepts maxlength.
534 $fields = array(
535 'textarea',
536 'rte',
537 'hidden',
538 'file',
539 );
540
541 if ( FrmField::is_option_empty( $field, 'max' ) || in_array( $field['type'], $fields ) ) {
542 return;
543 }
544
545 if ( FrmAppHelper::is_admin_page( 'formidable' ) ) {
546 // Don't load on form builder page.
547 return;
548 }
549
550 $add_html['maxlength'] = 'maxlength="' . esc_attr( $field['max'] ) . '"';
551 }
552
553 private static function add_html_placeholder( $field, array &$add_html, array &$class ) {
554 if ( $field['default_value'] != '' ) {
555 if ( is_array( $field['default_value'] ) ) {
556 $add_html['data-frmval'] = 'data-frmval="' . esc_attr( json_encode( $field['default_value'] ) ) . '"';
557 } else {
558 self::add_frmval_to_input( $field, $add_html );
559 }
560 }
561
562 $field['placeholder'] = self::prepare_placeholder( $field );
563 if ( $field['placeholder'] == '' || is_array( $field['placeholder'] ) ) {
564 // don't include a json placeholder
565 return;
566 }
567
568 $frm_settings = FrmAppHelper::get_settings();
569
570 if ( $frm_settings->use_html ) {
571 self::add_placeholder_to_input( $field, $add_html );
572 } else {
573 self::add_frmval_to_input( $field, $add_html );
574
575 $class[] = 'frm_toggle_default';
576
577 if ( $field['value'] == $field['placeholder'] ) {
578 $class[] = 'frm_default';
579 }
580 }
581 }
582
583 /**
584 * Prepares field placeholder.
585 *
586 * @since 5.4 This doesn't call `FrmFieldsController::get_default_value_from_name()` anymore.
587 *
588 * @param array $field Field array.
589 * @return string
590 */
591 private static function prepare_placeholder( $field ) {
592 $placeholder = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
593
594 return $placeholder;
595 }
596
597 /**
598 * If the label position is "inside",
599 * get the label to use as the placeholder
600 *
601 * @since 2.05
602 * @since 5.4 Remove the logic code for "inside" label position.
603 *
604 * @param array $field
605 *
606 * @return string
607 */
608 public static function get_default_value_from_name( $field ) {
609 return '';
610 }
611
612 /**
613 * Maybe add a blank placeholder option before any options
614 * in a dropdown.
615 *
616 * @since 4.04
617 * @return bool True if placeholder was added.
618 */
619 public static function add_placeholder_to_select( $field ) {
620 $placeholder = FrmField::get_option( $field, 'placeholder' );
621 if ( empty( $placeholder ) ) {
622 $placeholder = self::get_default_value_from_name( $field );
623 }
624
625 $use_placeholder = $placeholder;
626 $autocomplete = FrmField::get_option( $field, 'autocom' );
627
628 if ( $autocomplete ) {
629 $use_chosen = ! is_callable( 'FrmProAppHelper::use_chosen_js' ) || FrmProAppHelper::use_chosen_js();
630 if ( $use_chosen ) {
631 $use_placeholder = '';
632 }
633 }
634
635 if ( $placeholder !== '' ) {
636 $placeholder_attributes = array(
637 'class' => 'frm-select-placeholder',
638 'value' => '',
639 'data-placeholder' => 'true',
640 );
641
642 if ( $autocomplete && empty( $use_chosen ) ) {
643 // This is required for Slim Select.
644 $placeholder_attributes['data-placeholder'] = 'true';
645 }
646
647 FrmHtmlHelper::echo_dropdown_option( $use_placeholder, false, $placeholder_attributes );
648 return true;
649 }
650
651 return false;
652 }
653
654 /**
655 * Use HMTL5 placeholder with js fallback
656 *
657 * @param array $field
658 * @param array $add_html
659 */
660 private static function add_placeholder_to_input( $field, &$add_html ) {
661 if ( FrmFieldsHelper::is_placeholder_field_type( $field['type'] ) ) {
662 $add_html['placeholder'] = 'placeholder="' . esc_attr( $field['placeholder'] ) . '"';
663 }
664 }
665
666 private static function add_frmval_to_input( $field, &$add_html ) {
667 if ( $field['placeholder'] != '' ) {
668 $add_html['data-frmval'] = 'data-frmval="' . esc_attr( $field['placeholder'] ) . '"';
669
670 if ( 'select' === $field['type'] ) {
671 $add_html['data-frmplaceholder'] = 'data-frmplaceholder="' . esc_attr( $field['placeholder'] ) . '"';
672 }
673 }
674
675 if ( $field['default_value'] != '' ) {
676 $add_html['data-frmval'] = 'data-frmval="' . esc_attr( $field['default_value'] ) . '"';
677 }
678 }
679
680 private static function add_validation_messages( $field, array &$add_html ) {
681 if ( FrmField::is_required( $field ) ) {
682 $required_message = FrmFieldsHelper::get_error_msg( $field, 'blank' );
683 $add_html['data-reqmsg'] = 'data-reqmsg="' . esc_attr( $required_message ) . '"';
684 self::maybe_add_html_required( $field, $add_html );
685 }
686
687 if ( ! FrmField::is_option_empty( $field, 'invalid' ) ) {
688 $invalid_message = FrmFieldsHelper::get_error_msg( $field, 'invalid' );
689 $add_html['data-invmsg'] = 'data-invmsg="' . esc_attr( $invalid_message ) . '"';
690 }
691
692 if ( ! empty( $add_html['data-reqmsg'] ) || ! empty( $add_html['data-invmsg'] ) ) {
693 self::maybe_add_error_html_for_js_validation( $field, $add_html );
694 }
695 }
696
697 /**
698 * @since 5.0.03
699 *
700 * @param array $field
701 * @param array $add_html
702 */
703 private static function maybe_add_error_html_for_js_validation( $field, array &$add_html ) {
704 $form = self::get_form_for_js_validation( $field );
705 if ( false === $form ) {
706 return;
707 }
708
709 $error_body = self::pull_custom_error_body_from_custom_html( $form, $field );
710 if ( false !== $error_body ) {
711 $error_body = urlencode( $error_body );
712 $add_html['data-error-html'] = 'data-error-html="' . esc_attr( $error_body ) . '"';
713 }
714 }
715
716 /**
717 * @since 5.0.03
718 *
719 * @param array $field
720 * @return stdClass|false false if there is no form object found with JS validation active.
721 */
722 private static function get_form_for_js_validation( $field ) {
723 global $frm_vars;
724 if ( ! empty( $frm_vars['js_validate_forms'] ) ) {
725 if ( isset( $frm_vars['js_validate_forms'][ $field['form_id'] ] ) ) {
726 return $frm_vars['js_validate_forms'][ $field['form_id'] ];
727 }
728 if ( ! empty( $field['parent_form_id'] ) && isset( $frm_vars['js_validate_forms'][ $field['parent_form_id'] ] ) ) {
729 return $frm_vars['js_validate_forms'][ $field['parent_form_id'] ];
730 }
731 }
732 return false;
733 }
734
735 /**
736 * @param stdClass $form
737 * @param array $field
738 * @param array $errors
739 * @return string|false
740 */
741 public static function pull_custom_error_body_from_custom_html( $form, $field, $errors = array() ) {
742 if ( empty( $field['custom_html'] ) ) {
743 return false;
744 }
745
746 $custom_html = $field['custom_html'];
747 $custom_html = apply_filters( 'frm_before_replace_shortcodes', $custom_html, $field, $errors, $form );
748
749 $start = strpos( $custom_html, '[if error]' );
750 if ( false === $start ) {
751 return false;
752 }
753
754 $end = strpos( $custom_html, '[/if error]' );
755 if ( false === $end || $end < $start ) {
756 return false;
757 }
758
759 $error_body = substr( $custom_html, $start + 10, $end - $start - 10 );
760 $default_html = array(
761 '<div class="frm_error" id="frm_error_field_[key]">[error]</div>',
762 '<div class="frm_error" role="alert" id="frm_error_field_[key]">[error]</div>',
763 '<div class="frm_error">[error]</div>',
764 '<div class="frm_error" role="alert">[error]</div>',
765 );
766
767 if ( in_array( $error_body, $default_html, true ) ) {
768 return false;
769 }
770
771 return $error_body;
772 }
773
774 /**
775 * If 'required' is added to a conditionally hidden field, the form won't
776 * submit in many browsers. Check to make sure the javascript to conditionally
777 * remove it is present if needed.
778 *
779 * @since 3.06.01
780 * @param array $field
781 * @param array $add_html
782 */
783 private static function maybe_add_html_required( $field, array &$add_html ) {
784 $excluded_field_types =
785 FrmField::is_radio( $field ) ||
786 FrmField::is_checkbox( $field ) ||
787 FrmField::is_field_type( $field, 'file' ) ||
788 FrmField::is_field_type( $field, 'nps' ) ||
789 FrmField::is_field_type( $field, 'scale' );
790
791 if ( $excluded_field_types ) {
792 return;
793 }
794
795 $include_html = FrmAppHelper::meets_min_pro_version( '3.06.01' );
796 if ( $include_html ) {
797 $add_html['aria-required'] = 'aria-required="true"';
798 }
799 }
800
801 private static function add_shortcodes_to_html( $field, array &$add_html ) {
802 if ( FrmField::is_option_empty( $field, 'shortcodes' ) ) {
803 return;
804 }
805
806 if ( ! empty( $field['autocomplete'] ) ) {
807 unset( $field['shortcodes']['autocomplete'] );
808 }
809
810 foreach ( $field['shortcodes'] as $k => $v ) {
811 if ( 'opt' === $k ) {
812 continue;
813 }
814
815 if ( is_numeric( $k ) && strpos( $v, '=' ) ) {
816 $add_html[] = $v;
817 } elseif ( ! empty( $k ) && isset( $add_html[ $k ] ) ) {
818 $add_html[ $k ] = str_replace( $k . '="', $k . '="' . $v, $add_html[ $k ] );
819 } else {
820 $add_html[ $k ] = $k . '="' . esc_attr( $v ) . '"';
821 }
822
823 unset( $k, $v );
824 }
825 }
826
827 /**
828 * Add pattern attribute
829 *
830 * @since 3.0
831 *
832 * @param array $field
833 * @param array $add_html
834 */
835 private static function add_pattern_attribute( $field, array &$add_html ) {
836 $has_format = FrmField::is_option_true_in_array( $field, 'format' );
837 $format_field = FrmField::is_field_type( $field, 'text' );
838
839 if ( $field['type'] == 'phone' || ( $has_format && $format_field ) ) {
840 $frm_settings = FrmAppHelper::get_settings();
841
842 if ( $frm_settings->use_html ) {
843 $format = FrmEntryValidate::phone_format( $field );
844 $format = substr( $format, 2, - 1 );
845
846 $add_html['pattern'] = 'pattern="' . esc_attr( $format ) . '"';
847 }
848 }
849 }
850
851 public static function check_value( $opt, $opt_key, $field ) {
852 if ( is_array( $opt ) ) {
853 if ( FrmField::is_option_true( $field, 'separate_value' ) ) {
854 $opt = isset( $opt['value'] ) ? $opt['value'] : ( isset( $opt['label'] ) ? $opt['label'] : reset( $opt ) );
855 } else {
856 $opt = isset( $opt['label'] ) ? $opt['label'] : reset( $opt );
857 }
858 }
859
860 return $opt;
861 }
862
863 public static function check_label( $opt ) {
864 if ( is_array( $opt ) ) {
865 $opt = ( isset( $opt['label'] ) ? $opt['label'] : reset( $opt ) );
866 }
867
868 return $opt;
869 }
870
871 /**
872 * @deprecated 4.0
873 */
874 public static function update_ajax_option() {
875 _deprecated_function( __METHOD__, '4.0' );
876 FrmAppHelper::permission_check( 'frm_edit_forms' );
877 check_ajax_referer( 'frm_ajax', 'nonce' );
878
879 $field_id = FrmAppHelper::get_post_param( 'field', 0, 'absint' );
880 if ( ! $field_id ) {
881 wp_die();
882 }
883
884 $field = FrmField::getOne( $field_id );
885
886 if ( isset( $_POST['separate_value'] ) ) {
887 $new_val = FrmField::is_option_true( $field, 'separate_value' ) ? 0 : 1;
888
889 $field->field_options['separate_value'] = $new_val;
890 unset( $new_val );
891 }
892
893 FrmField::update(
894 $field_id,
895 array(
896 'field_options' => $field->field_options,
897 'form_id' => $field->form_id,
898 )
899 );
900 wp_die();
901 }
902
903 /**
904 * @deprecated 4.0
905 */
906 public static function import_choices() {
907 _deprecated_function( __METHOD__, '4.0' );
908 wp_die();
909 }
910
911 /**
912 * Add Single Option or Other Option.
913 *
914 * @deprecated 4.0 Moved to Pro for Other option only.
915 */
916 public static function add_option() {
917 _deprecated_function( __METHOD__, '4.0', 'FrmProFieldsController::add_other_option' );
918 }
919
920 /**
921 * @deprecated 4.0
922 */
923 public static function update_order() {
924 FrmDeprecated::update_order();
925 }
926
927 /**
928 * @deprecated 3.0
929 * @codeCoverageIgnore
930 */
931 public static function edit_name( $field = 'name', $id = '' ) {
932 FrmDeprecated::edit_name( $field, $id );
933 }
934
935 /**
936 * @deprecated 3.0
937 * @codeCoverageIgnore
938 *
939 * @param int $field_id
940 * @param array $values
941 * @param int $form_id
942 *
943 * @return array
944 */
945 public static function include_single_field( $field_id, $values, $form_id = 0 ) {
946 return FrmDeprecated::include_single_field( $field_id, $values, $form_id );
947 }
948 }
949