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

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