PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 5.0.04
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v5.0.04
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 5.0.04, at classes/controllers/FrmFieldsController.php

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