PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.14
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.14
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 / helpers / FrmFieldsHelper.php

FrmFieldsHelper.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.14, at classes/helpers/FrmFieldsHelper.php

2,333 lines 68.8 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 FrmFieldsHelper {
7
8 public static function setup_new_vars( $type = '', $form_id = '' ) {
9
10 if ( strpos( $type, '|' ) ) {
11 list( $type, $setting ) = explode( '|', $type );
12 }
13
14 $values = self::get_default_field( $type );
15
16 global $wpdb;
17 $field_count = FrmDb::get_var(
18 'frm_fields',
19 array( 'form_id' => $form_id ),
20 'field_order',
21 array( 'order_by' => 'field_order DESC' )
22 );
23
24 $values['field_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_fields', 'field_key' );
25 $values['form_id'] = $form_id;
26 $values['field_order'] = $field_count + 1;
27
28 $values['field_options']['custom_html'] = self::get_default_html( $type );
29
30 if ( ! empty( $setting ) ) {
31 if ( in_array( $type, array( 'data', 'lookup' ), true ) ) {
32 $values['field_options']['data_type'] = $setting;
33 } else {
34 $values['field_options'][ $setting ] = 1;
35 }
36 }
37
38 // Increase the field order of submit field and fields in the same row.
39 $last_row_field_ids = FrmAppHelper::get_post_param( 'last_row_field_ids', array() );
40 if ( $last_row_field_ids ) {
41 foreach ( $last_row_field_ids as $index => $last_row_field_id ) {
42 FrmField::update(
43 $last_row_field_id,
44 array( 'field_order' => $field_count + $index + 2 )
45 );
46 }
47 }
48
49 return $values;
50 }
51
52 public static function get_html_id( $field, $plus = '' ) {
53 return apply_filters( 'frm_field_html_id', 'field_' . $field['field_key'] . $plus, $field );
54 }
55
56 public static function setup_edit_vars( $field, $doing_ajax = false ) {
57 $values = self::field_object_to_array( $field );
58
59 return apply_filters( 'frm_setup_edit_field_vars', $values, array( 'doing_ajax' => $doing_ajax ) );
60 }
61
62 public static function field_object_to_array( $field ) {
63 $values = (array) $field;
64
65 self::fill_field_array( $field, $values );
66
67 $values['custom_html'] = isset( $field->field_options['custom_html'] ) ? $field->field_options['custom_html'] : self::get_default_html( $field->type );
68
69 return $values;
70 }
71
72 private static function fill_field_array( $field, array &$field_array ) {
73 $field_array['options'] = $field->options;
74 $field_array['value'] = $field->default_value;
75
76 self::prepare_edit_front_field( $field_array, $field );
77
78 $field_array = array_merge( (array) $field->field_options, $field_array );
79 }
80
81 /**
82 * Prepare field while creating a new entry
83 *
84 * @since 3.0
85 */
86 public static function prepare_new_front_field( &$field_array, $field, $args = array() ) {
87 $args['action'] = 'new';
88 self::prepare_front_field( $field_array, $field, $args );
89 }
90
91 /**
92 * Prepare field while editing an entry
93 *
94 * @since 3.0
95 */
96 public static function prepare_edit_front_field( &$field_array, $field, $entry_id = 0, $args = array() ) {
97 $args['entry_id'] = $entry_id;
98 $args['action'] = 'edit';
99 self::prepare_front_field( $field_array, $field, $args );
100 }
101
102 /**
103 * Prepare field while creating a new entry
104 *
105 * @since 3.0
106 */
107 private static function prepare_front_field( &$field_array, $field, $args ) {
108 self::fill_default_field_opts( $field, $field_array );
109 self::fill_cleared_strings( $field, $field_array );
110
111 // Track the original field's type
112 $field_array['original_type'] = isset( $field->field_options['original_type'] ) ? $field->field_options['original_type'] : $field->type;
113
114 self::prepare_field_options_for_display( $field_array, $field, $args );
115
116 if ( $args['action'] === 'edit' ) {
117 $field_array = apply_filters( 'frm_setup_edit_fields_vars', $field_array, $field, $args['entry_id'], $args );
118 } else {
119 $field_array = apply_filters( 'frm_setup_new_fields_vars', $field_array, $field, $args );
120 }
121 }
122
123 /**
124 * @since 3.0
125 *
126 * @param string $type
127 *
128 * @return array
129 */
130 public static function get_default_field_options( $type ) {
131 $field_type = FrmFieldFactory::get_field_type( $type );
132
133 return $field_type->get_default_field_options();
134 }
135
136 /**
137 * @since 3.0
138 *
139 * @param object $field
140 * @param array $values
141 */
142 private static function fill_default_field_opts( $field, array &$values ) {
143 $check_post = FrmAppHelper::is_admin_page() && $_POST && isset( $_POST['field_options'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
144
145 $defaults = self::get_default_field_options_from_field( $field, $values );
146 if ( ! $check_post ) {
147 $defaults['required_indicator'] = '';
148 $defaults['original_type'] = $field->type;
149 }
150
151 foreach ( $defaults as $opt => $default ) {
152 $values[ $opt ] = isset( $field->field_options[ $opt ] ) ? $field->field_options[ $opt ] : $default;
153
154 if ( $check_post ) {
155 self::get_posted_field_setting( $opt . '_' . $field->id, $values[ $opt ] );
156 }
157
158 unset( $opt, $default );
159 }
160 }
161
162 /**
163 * Fill the required message, invalid message,
164 * and refill the HTML when cleared
165 *
166 * @since 3.0
167 *
168 * @param object $field
169 * @param array $field_array
170 */
171 private static function fill_cleared_strings( $field, array &$field_array ) {
172 if ( '' == $field_array['blank'] && '1' === $field_array['required'] ) {
173 $field_array['blank'] = self::default_blank_msg();
174 }
175
176 if ( '' === $field_array['invalid'] ) {
177 if ( 'captcha' === $field->type ) {
178 $frm_settings = FrmAppHelper::get_settings();
179 $field_array['invalid'] = $frm_settings->re_msg;
180 } else {
181 $field_array['invalid'] = self::default_invalid_msg();
182 }
183 }
184
185 if ( '' == $field_array['custom_html'] ) {
186 $field_array['custom_html'] = self::get_default_html( $field->type );
187 }
188 }
189
190 /**
191 * @since 6.8.3
192 *
193 * @return string
194 */
195 public static function default_invalid_msg() {
196 /* translators: %s: [field_name] shortcode (Which gets replaced by a Field Name) */
197 return sprintf( __( '%s is invalid', 'formidable' ), '[field_name]' );
198 }
199
200 /**
201 * @since 6.8.3
202 *
203 * @return string
204 */
205 public static function default_unique_msg() {
206 $frm_settings = FrmAppHelper::get_settings();
207 $unique_message = $frm_settings->unique_msg;
208 $unique_message = str_replace( 'This value', '[field_name]', $unique_message );
209 return $unique_message;
210 }
211
212 /**
213 * @since 6.8.3
214 *
215 * @return string
216 */
217 public static function default_blank_msg() {
218 $frm_settings = FrmAppHelper::get_settings();
219 $blank_message = $frm_settings->blank_msg;
220 $blank_message = str_replace( 'This field', '[field_name]', $blank_message );
221 return $blank_message;
222 }
223
224 /**
225 * @since 3.0
226 *
227 * @param string $setting
228 * @param mixed $value
229 */
230 private static function get_posted_field_setting( $setting, &$value ) {
231 if ( ! isset( $_POST['field_options'][ $setting ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
232 return;
233 }
234
235 if ( strpos( $setting, 'html' ) !== false ) {
236 // Strip slashes from HTML but not regex or script tags.
237 $value = wp_unslash( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
238 } elseif ( strpos( $setting, 'format_' ) === 0 ) {
239 // TODO: Remove stripslashes on output, and use on input only.
240 $value = sanitize_text_field( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Missing
241 } else {
242 $value = wp_unslash( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
243 FrmAppHelper::sanitize_value( 'wp_kses_post', $value );
244 }
245 }
246
247 /**
248 * @since 3.0
249 *
250 * @param object $field
251 * @param array $values The field array is needed for hooks.
252 *
253 * @return array
254 */
255 public static function get_default_field_options_from_field( $field, $values = array() ) {
256 $field_type = self::get_original_field( $field );
257 $opts = $field_type->get_default_field_options();
258
259 $opts = apply_filters( 'frm_default_field_opts', $opts, $values, $field );
260 $opts = apply_filters( 'frm_default_' . $field->type . '_field_opts', $opts, $values, $field );
261
262 return $opts;
263 }
264
265 /**
266 * @since 3.0
267 *
268 * @param object $field
269 *
270 * @return FrmFieldType
271 */
272 private static function get_original_field( $field ) {
273 $original_type = FrmField::get_option( $field, 'original_type' );
274 if ( ! empty( $original_type ) && $field->type != $original_type ) {
275 $field->type = $original_type;
276 }
277
278 return FrmFieldFactory::get_field_object( $field );
279 }
280
281 /**
282 * @since 3.0
283 *
284 * @param array $field_array
285 * @param object $field
286 * @param array $atts
287 */
288 private static function prepare_field_options_for_display( &$field_array, $field, $atts ) {
289 $field_obj = FrmFieldFactory::get_field_object( $field );
290 $field_array = $field_obj->prepare_front_field( $field_array, $atts );
291 }
292
293 /**
294 * @since 3.0
295 *
296 * @param string $type
297 *
298 * @return array
299 */
300 public static function get_default_field( $type ) {
301 $field_type = FrmFieldFactory::get_field_type( $type );
302
303 return $field_type->get_new_field_defaults();
304 }
305
306 public static function fill_field( &$values, $field, $form_id, $new_key = '' ) {
307 global $wpdb;
308
309 $values['field_key'] = FrmAppHelper::get_unique_key( $new_key, $wpdb->prefix . 'frm_fields', 'field_key' );
310 $values['form_id'] = $form_id;
311 $values['options'] = maybe_serialize( $field->options );
312 $values['default_value'] = FrmAppHelper::maybe_json_encode( $field->default_value );
313
314 foreach ( array( 'name', 'description', 'type', 'field_order', 'field_options', 'required' ) as $col ) {
315 $values[ $col ] = $field->{$col};
316 }
317 }
318
319 /**
320 * @since 2.0
321 *
322 * @param array|object $field
323 * @param string $error
324 *
325 * @return string
326 */
327 public static function get_error_msg( $field, $error ) {
328 $frm_settings = FrmAppHelper::get_settings();
329
330 $conf_msg = __( 'The entered values do not match', 'formidable' );
331 $defaults = array(
332 'unique_msg' => array(
333 'full' => self::default_unique_msg(),
334 /* translators: %s: Field name */
335 'part' => sprintf( __( '%s must be unique', 'formidable' ), '[field_name]' ),
336 ),
337 'invalid' => array(
338 'full' => __( 'This field is invalid', 'formidable' ),
339 /* translators: %s: Field name */
340 'part' => sprintf( __( '%s is invalid', 'formidable' ), '[field_name]' ),
341 ),
342 'blank' => array(
343 'full' => $frm_settings->blank_msg,
344 'part' => $frm_settings->blank_msg,
345 ),
346 'conf_msg' => array(
347 'full' => $conf_msg,
348 'part' => $conf_msg,
349 ),
350 );
351
352 $msg = FrmField::get_option( $field, $error );
353 $msg = empty( $msg ) ? $defaults[ $error ]['part'] : $msg;
354 $msg = do_shortcode( $msg );
355
356 $msg = self::maybe_replace_substrings_with_field_name( $msg, $error, $field );
357
358 return $msg;
359 }
360
361 /**
362 * @since 6.8.3
363 *
364 * @param string $msg
365 * @param string $error
366 * @param array|object $field
367 */
368 private static function maybe_replace_substrings_with_field_name( $msg, $error, $field ) {
369 $field_name = is_array( $field ) ? $field['name'] : $field->name;
370 $field_name = FrmAppHelper::maybe_kses( $field_name );
371 $substrings = self::get_substrings_to_replace_with_field_name( $field_name, compact( 'msg', 'error', 'field' ) );
372
373 // Use the "This value"/"This field" placeholder strings if field name is empty.
374 if ( ! $field_name ) {
375 if ( 'unique_msg' === $error ) {
376 $field_name = __( 'This value', 'formidable' );
377 } else {
378 $field_name = __( 'This field', 'formidable' );
379 }
380 }
381
382 $msg = str_replace( $substrings, $field_name, $msg );
383 return $msg;
384 }
385
386 /**
387 * @since 6.8.3
388 *
389 * @param string $field_name
390 * @param array $filter_args {
391 * Filter arguments.
392 *
393 * @type string $msg The current error message before the substrings are replaced.
394 * @type string $error A key including 'unique_msg', 'invalid', 'blank', or 'conf_msg'.
395 * @type array|object $field The field with the error.
396 * }
397 * @return array
398 */
399 private static function get_substrings_to_replace_with_field_name( $field_name, $filter_args ) {
400 $substrings = array( '[field_name]' );
401 if ( $field_name ) {
402 array_push( $substrings, 'This value', 'This field' );
403 }
404
405 /**
406 * @since 6.8.3
407 *
408 * @param array<string> $substrings
409 * @param array $filter_args
410 */
411 $filtered_substrings = apply_filters( 'frm_error_substrings_to_replace_with_field_name', $substrings, $filter_args );
412
413 if ( is_array( $filtered_substrings ) ) {
414 $substrings = $filtered_substrings;
415 } else {
416 _doing_it_wrong( __FUNCTION__, 'Only arrays should be returned when using the frm_error_substrings_to_replace_with_field_name filter.', '6.8.3' );
417 }
418
419 return $substrings;
420 }
421
422 public static function get_form_fields( $form_id, $error = array() ) {
423 $fields = FrmField::get_all_for_form( $form_id );
424
425 return apply_filters( 'frm_get_paged_fields', $fields, $form_id, $error );
426 }
427
428 public static function get_default_html( $type = 'text' ) {
429 $field = FrmFieldFactory::get_field_type( $type );
430 $default_html = $field->default_html();
431
432 // these hooks are here for reverse compatibility since 3.0
433 if ( ! apply_filters( 'frm_normal_field_type_html', true, $type ) ) {
434 $default_html = apply_filters( 'frm_other_custom_html', '', $type );
435 }
436
437 return apply_filters( 'frm_custom_html', $default_html, $type );
438 }
439
440 /**
441 * @param array $fields
442 * @param array $errors
443 * @param object $form
444 * @param object $form_action
445 */
446 public static function show_fields( $fields, $errors, $form, $form_action ) {
447 foreach ( $fields as $field ) {
448 $field_obj = FrmFieldFactory::get_field_type( $field['type'], $field );
449 $field_obj->show_field( compact( 'errors', 'form', 'form_action' ) );
450 }
451 }
452
453 /**
454 * @since 3.0
455 *
456 * @param array $atts
457 * @param array|string $value
458 */
459 public static function run_wpautop( $atts, &$value ) {
460 $autop = isset( $atts['wpautop'] ) ? $atts['wpautop'] : true;
461 if ( apply_filters( 'frm_use_wpautop', $autop ) ) {
462 if ( is_array( $value ) ) {
463 $value = implode( "\n", $value );
464 }
465 $value = wpautop( $value );
466 }
467 }
468
469 /**
470 * Get the class to use for the label position
471 *
472 * @since 2.05
473 */
474 public static function &label_position( $position, $field, $form ) {
475 if ( $position && $position != '' ) {
476 if ( $position === 'inside' && ! self::is_placeholder_field_type( $field['type'] ) ) {
477 $position = 'top';
478 }
479
480 return $position;
481 }
482
483 $position = FrmStylesController::get_style_val( 'position', $form );
484 if ( $position === 'none' ) {
485 $position = 'top';
486 } elseif ( $position === 'no_label' ) {
487 $position = 'none';
488 } elseif ( $position === 'inside' && ! self::is_placeholder_field_type( $field['type'] ) ) {
489 $position = 'top';
490 }
491
492 $position = apply_filters( 'frm_html_label_position', $position, $field, $form );
493 $position = ! empty( $position ) ? $position : 'top';
494
495 return $position;
496 }
497
498 /**
499 * Check if this field type allows placeholders
500 *
501 * @since 2.05
502 * @param string $type
503 * @return bool
504 */
505 public static function is_placeholder_field_type( $type ) {
506 return ! in_array( $type, array( 'radio', 'checkbox', 'hidden', 'file' ), true );
507 }
508
509 public static function get_checkbox_id( $field, $opt_key, $type = 'checkbox' ) {
510 $id = $field['id'];
511 if ( isset( $field['in_section'] ) && $field['in_section'] && ! FrmAppHelper::is_admin_page( 'formidable' ) ) {
512 $id .= '-' . $field['in_section'];
513 }
514
515 return 'frm_' . $type . '_' . $id . '-' . $opt_key;
516 }
517
518 public static function show_single_option( $field ) {
519 self::hidden_field_option( $field );
520
521 if ( ! is_array( $field['options'] ) ) {
522 return;
523 }
524
525 $base_name = 'default_value_' . $field['id'];
526 $html_id = isset( $field['html_id'] ) ? $field['html_id'] : self::get_html_id( $field );
527
528 $default_type = self::get_default_value_type( $field );
529
530 foreach ( $field['options'] as $opt_key => $opt ) {
531 $field_val = self::get_value_from_array( $opt, $opt_key, $field );
532 $opt = self::get_label_from_array( $opt, $opt_key, $field );
533
534 $field_name = $base_name . ( $default_type === 'checkbox' ? '[' . $opt_key . ']' : '' );
535
536 $checked = ( isset( $field['default_value'] ) && ( ( ! is_array( $field['default_value'] ) && $field['default_value'] == $field_val ) || ( is_array( $field['default_value'] ) && in_array( $field_val, $field['default_value'] ) ) ) );
537
538 // If this is an "Other" option, get the HTML for it.
539 if ( self::is_other_opt( $opt_key ) ) {
540 if ( FrmAppHelper::pro_is_installed() ) {
541 require FrmProAppHelper::plugin_path() . '/classes/views/frmpro-fields/other-option.php';
542 }
543 } else {
544 require FrmAppHelper::plugin_path() . '/classes/views/frm-fields/single-option.php';
545 }
546
547 unset( $checked );
548 }
549 }
550
551 /**
552 * Include hidden row for javascript to duplicate.
553 *
554 * @since 4.0
555 * @param array $field
556 */
557 private static function hidden_field_option( $field ) {
558 // Don't duplicate during an ajax add option.
559 $ajax_action = FrmAppHelper::get_param( 'action', '', 'post', 'sanitize_text_field' );
560 if ( $ajax_action === 'frm_add_field_option' ) {
561 return;
562 }
563
564 $opt_key = '000';
565 $field_val = __( 'New Option', 'formidable' );
566 $opt = __( 'New Option', 'formidable' );
567 $checked = false;
568 $field_name = 'default_value_' . $field['id'];
569 $html_id = isset( $field['html_id'] ) ? $field['html_id'] : self::get_html_id( $field );
570
571 $default_type = self::get_default_value_type( $field );
572 $field_name .= ( $default_type === 'checkbox' ? '[' . $opt_key . ']' : '' );
573
574 require FrmAppHelper::plugin_path() . '/classes/views/frm-fields/single-option.php';
575 }
576
577 /**
578 * @since 4.0
579 *
580 * @param array $field
581 * @return string radio or checkbox
582 */
583 private static function get_default_value_type( $field ) {
584 $default_type = $field['type'];
585 if ( $field['type'] === 'select' ) {
586 $default_type = FrmField::is_multiple_select( $field ) ? 'checkbox' : 'radio';
587 }
588 return $default_type;
589 }
590
591 public static function get_value_from_array( $opt, $opt_key, $field ) {
592 $opt = apply_filters( 'frm_field_value_saved', $opt, $opt_key, $field );
593
594 return FrmFieldsController::check_value( $opt, $opt_key, $field );
595 }
596
597 public static function get_label_from_array( $opt, $opt_key, $field ) {
598 $opt = apply_filters( 'frm_field_label_seen', $opt, $opt_key, $field );
599
600 return FrmFieldsController::check_label( $opt );
601 }
602
603 /**
604 * Shows the inline modal.
605 *
606 * @since 4.0
607 * @since 6.4.1 Added `inside_class` in the arguments.
608 *
609 * @param array $args The arguments.
610 */
611 public static function inline_modal( $args ) {
612 $defaults = array(
613 'id' => '',
614 'class' => '',
615 'show' => 0,
616 'callback' => array(),
617 'args' => array(),
618 'title' => '',
619 'inside_class' => 'inside',
620 );
621 $args = array_merge( $defaults, $args );
622
623 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/inline-modal.php';
624 }
625
626 /**
627 * @since 4.0
628 */
629 public static function smart_values() {
630 $continue = apply_filters( 'frm_smart_values_box', true );
631 if ( $continue === true ) {
632 $upgrade_link = array(
633 'medium' => 'builder',
634 'content' => 'smart-tags',
635 );
636 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/smart-values.php';
637 }
638 }
639
640 /**
641 * @since 4.0
642 */
643 public static function input_mask() {
644 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/input-mask-info.php';
645 }
646
647 /**
648 * @since 4.0
649 */
650 public static function layout_classes() {
651 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/layout-classes.php';
652 }
653
654 /**
655 * @param int $tax_id
656 *
657 * @return string
658 */
659 public static function get_term_link( $tax_id ) {
660 $tax = get_taxonomy( $tax_id );
661 if ( ! $tax ) {
662 return '';
663 }
664
665 $link = sprintf(
666 /* translators: %1$s: Start HTML link, %2$s: Content type label, %3$s: Content type, %4$s: End HTML link */
667 esc_html__( 'Options are dynamically created from your %1$s%2$s: %3$s%4$s', 'formidable' ),
668 '<a href="' . esc_url( admin_url( 'edit-tags.php?taxonomy=' . $tax->name ) ) . '" target="_blank">',
669 esc_html__( 'taxonomy', 'formidable' ),
670 empty( $tax->labels->name ) ? esc_html__( 'Categories', 'formidable' ) : $tax->labels->name,
671 '</a>'
672 );
673 unset( $tax );
674
675 return $link;
676 }
677
678 public static function value_meets_condition( $observed_value, $cond, $hide_opt ) {
679 $hide_opt = self::get_value_for_comparison( $hide_opt );
680 $observed_value = self::get_value_for_comparison( $observed_value );
681
682 if ( is_array( $observed_value ) ) {
683 return self::array_value_condition( $observed_value, $cond, $hide_opt );
684 }
685
686 $m = false;
687 if ( $cond === '==' ) {
688 $m = $observed_value == $hide_opt;
689 } elseif ( $cond === '!=' ) {
690 $m = $observed_value != $hide_opt;
691 } elseif ( $cond === '>' ) {
692 $m = $observed_value > $hide_opt;
693 } elseif ( $cond === '>=' ) {
694 $m = $observed_value >= $hide_opt;
695 } elseif ( $cond === '<' ) {
696 $m = $observed_value < $hide_opt;
697 } elseif ( $cond === '<=' ) {
698 $m = $observed_value <= $hide_opt;
699 } elseif ( $cond === 'LIKE' || $cond === 'not LIKE' ) {
700 $m = stripos( $observed_value, $hide_opt );
701 if ( $cond === 'not LIKE' ) {
702 $m = $m === false;
703 } else {
704 $m = $m !== false;
705 }
706 } elseif ( $cond === '%LIKE' ) {
707 // ends with
708 $length = strlen( $hide_opt );
709 $substr = substr( $observed_value, strlen( $observed_value ) - $length );
710 $m = 0 === strcasecmp( $substr, $hide_opt );
711 } elseif ( 'LIKE%' === $cond ) {
712 // starts with
713 $length = strlen( $hide_opt );
714 $substr = substr( $observed_value, 0, $length );
715 $m = 0 === strcasecmp( $substr, $hide_opt );
716 }//end if
717
718 return $m;
719 }
720
721 /**
722 * Trim and sanitize the values
723 *
724 * @since 2.05
725 */
726 private static function get_value_for_comparison( $value ) {
727 // Remove white space from hide_opt
728 if ( ! is_array( $value ) ) {
729 $value = trim( $value );
730 }
731
732 FrmAppHelper::sanitize_value( 'wp_kses_post', $value );
733
734 return $value;
735 }
736
737 public static function array_value_condition( $observed_value, $cond, $hide_opt ) {
738 $m = false;
739 if ( $cond === '==' ) {
740 if ( is_array( $hide_opt ) ) {
741 $m = array_intersect( $hide_opt, $observed_value );
742 $m = ! empty( $m );
743 } else {
744 $m = in_array( $hide_opt, $observed_value );
745 }
746 } elseif ( $cond === '!=' ) {
747 $m = ! in_array( $hide_opt, $observed_value );
748 } elseif ( $cond === '>' ) {
749 $min = min( $observed_value );
750 $m = $min > $hide_opt;
751 } elseif ( $cond === '<' ) {
752 $max = max( $observed_value );
753 $m = $max < $hide_opt;
754 } elseif ( $cond === 'LIKE' || $cond === 'not LIKE' ) {
755 foreach ( $observed_value as $ob ) {
756 $m = strpos( $ob, $hide_opt );
757 if ( $m !== false ) {
758 $m = true;
759 break;
760 }
761 }
762
763 if ( $cond === 'not LIKE' ) {
764 $m = $m === false;
765 }
766 } elseif ( $cond === '%LIKE' ) {
767 // ends with
768 foreach ( $observed_value as $ob ) {
769 if ( $hide_opt === substr( $ob, strlen( $ob ) - strlen( $hide_opt ) ) ) {
770 $m = true;
771 break;
772 }
773 }
774 } elseif ( $cond === 'LIKE%' ) {
775 // starts with
776 foreach ( $observed_value as $ob ) {
777 if ( $hide_opt === substr( $ob, 0, strlen( $hide_opt ) ) ) {
778 $m = true;
779 break;
780 }
781 }
782 }//end if
783
784 return $m;
785 }
786
787 /**
788 * Replace a few basic shortcodes and field ids
789 *
790 * @since 2.0
791 * @return string
792 */
793 public static function basic_replace_shortcodes( $value, $form, $entry ) {
794 if ( strpos( $value, '[sitename]' ) !== false ) {
795 $new_value = wp_specialchars_decode( FrmAppHelper::site_name(), ENT_QUOTES );
796 $value = str_replace( '[sitename]', $new_value, $value );
797 }
798
799 $value = apply_filters( 'frm_content', $value, $form, $entry );
800 $value = do_shortcode( $value );
801
802 return $value;
803 }
804
805 public static function get_shortcodes( $content, $form_id ) {
806 if ( FrmAppHelper::pro_is_installed() ) {
807 return FrmProDisplaysHelper::get_shortcodes( $content, $form_id );
808 }
809
810 $fields = FrmField::getAll(
811 array(
812 'fi.form_id' => (int) $form_id,
813 'fi.type not' => FrmField::no_save_fields(),
814 )
815 );
816
817 $tagregexp = self::allowed_shortcodes( $fields );
818
819 preg_match_all( "/\[(if )?($tagregexp)\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?/s", $content, $matches, PREG_PATTERN_ORDER );
820
821 return $matches;
822 }
823
824 public static function allowed_shortcodes( $fields = array() ) {
825 $tagregexp = array(
826 'editlink',
827 'id',
828 'key',
829 'ip',
830 'siteurl',
831 'sitename',
832 'admin_email',
833 'post[-|_]id',
834 'created[-|_]at',
835 'updated[-|_]at',
836 'updated[-|_]by',
837 'parent[-|_]id',
838 );
839
840 foreach ( $fields as $field ) {
841 $tagregexp[] = $field->id;
842 $tagregexp[] = $field->field_key;
843 }
844
845 $tagregexp = implode( '|', $tagregexp );
846
847 return $tagregexp;
848 }
849
850 public static function replace_content_shortcodes( $content, $entry, $shortcodes ) {
851 foreach ( $shortcodes[0] as $short_key => $tag ) {
852 if ( empty( $tag ) ) {
853 continue;
854 }
855
856 $atts = FrmShortcodeHelper::get_shortcode_attribute_array( $shortcodes[3][ $short_key ] );
857 $tag = FrmShortcodeHelper::get_shortcode_tag( $shortcodes, $short_key );
858
859 $atts['entry'] = $entry;
860 $atts['tag'] = $tag;
861 $replace_with = self::get_value_for_shortcode( $atts );
862
863 if ( $replace_with !== null ) {
864 $replace_with = self::trigger_shortcode_atts( $replace_with, $atts );
865 self::sanitize_embedded_shortcodes( compact( 'entry' ), $replace_with );
866 $content = str_replace( $shortcodes[0][ $short_key ], $replace_with, $content );
867 }
868
869 unset( $atts, $replace_with );
870 }
871
872 return $content;
873 }
874
875 /**
876 * @param string $replace_with
877 * @param array $atts
878 * @return string
879 */
880 private static function trigger_shortcode_atts( $replace_with, $atts ) {
881 $supported_atts = array( 'remove_accents', 'sanitize', 'sanitize_url' );
882 $included_atts = array_intersect( $supported_atts, array_keys( $atts ) );
883 foreach ( $included_atts as $included_att ) {
884 if ( '0' === $atts[ $included_att ] ) {
885 // Skip any option that uses 0 so sanitize_url=0 does not encode.
886 continue;
887 }
888 $function = 'atts_' . $included_att;
889 $replace_with = self::$function( $replace_with, $atts );
890 }
891 return $replace_with;
892 }
893
894 /**
895 * Converts all accent characters to ASCII characters.
896 *
897 * @since 6.3.1
898 *
899 * @param string $replace_with The text to remove accents from.
900 *
901 * @return string
902 */
903 public static function atts_remove_accents( $replace_with ) {
904 return remove_accents( $replace_with );
905 }
906
907 /**
908 * @param string $replace_with
909 * @return string
910 */
911 private static function atts_sanitize( $replace_with ) {
912 return sanitize_title_with_dashes( $replace_with );
913 }
914
915 /**
916 * @param string $replace_with
917 * @return string
918 */
919 private static function atts_sanitize_url( $replace_with ) {
920 return urlencode( $replace_with );
921 }
922
923 /**
924 * Prevent shortcodes in fields from being processed
925 *
926 * @since 3.01.02
927 *
928 * @param array $atts Includes entry object.
929 * @param string $value
930 */
931 public static function sanitize_embedded_shortcodes( $atts, &$value ) {
932 $atts['value'] = $value;
933 $should_sanitize = apply_filters( 'frm_sanitize_shortcodes', true, $atts );
934 if ( $should_sanitize ) {
935 $value = str_replace( '[', '&#91;', $value );
936 }
937 }
938
939 /**
940 * @since 3.0
941 *
942 * @param array $atts
943 *
944 * @return string
945 */
946 private static function get_value_for_shortcode( $atts ) {
947 $clean_tag = str_replace( '-', '_', $atts['tag'] );
948
949 $shortcode_values = array(
950 'id' => $atts['entry']->id,
951 'key' => $atts['entry']->item_key,
952 'ip' => $atts['entry']->ip,
953 );
954
955 $dynamic_default = array( 'admin_email', 'siteurl', 'frmurl', 'sitename', 'get' );
956
957 if ( isset( $shortcode_values[ $atts['tag'] ] ) ) {
958 $replace_with = $shortcode_values[ $atts['tag'] ];
959 } elseif ( in_array( $atts['tag'], $dynamic_default, true ) ) {
960 $replace_with = self::dynamic_default_values( $atts['tag'], $atts );
961 } elseif ( $clean_tag === 'user_agent' ) {
962 $description = $atts['entry']->description;
963 $replace_with = FrmEntriesHelper::get_browser( $description['browser'] );
964 } elseif ( $clean_tag === 'created_at' || $clean_tag === 'updated_at' ) {
965 $atts['tag'] = $clean_tag;
966 $replace_with = self::get_entry_timestamp( $atts );
967 } elseif ( $clean_tag === 'created_by' || $clean_tag === 'updated_by' ) {
968 $replace_with = self::get_display_value( $atts['entry']->{$clean_tag}, (object) array( 'type' => 'user_id' ), $atts );
969 } else {
970 $replace_with = self::get_field_shortcode_value( $atts );
971 }
972
973 return $replace_with;
974 }
975
976 /**
977 * @since 3.0
978 *
979 * @param array $atts
980 *
981 * @return string
982 */
983 private static function get_entry_timestamp( $atts ) {
984 if ( isset( $atts['format'] ) ) {
985 $time_format = ' ';
986 } else {
987 $atts['format'] = get_option( 'date_format' );
988 $time_format = '';
989 }
990
991 return FrmAppHelper::get_formatted_time( $atts['entry']->{$atts['tag']}, $atts['format'], $time_format );
992 }
993
994 /**
995 * @since 3.0
996 *
997 * @param array $atts
998 *
999 * @return string|null
1000 */
1001 private static function get_field_shortcode_value( $atts ) {
1002 $field = FrmField::getOne( $atts['tag'] );
1003 if ( empty( $field ) ) {
1004 return null;
1005 }
1006
1007 if ( isset( $atts['show'] ) && $atts['show'] === 'field_label' ) {
1008 $replace_with = $field->name;
1009 } elseif ( isset( $atts['show'] ) && $atts['show'] === 'description' ) {
1010 $replace_with = $field->description;
1011 } else {
1012 $replace_with = FrmEntryMeta::get_meta_value( $atts['entry'], $field->id );
1013 $string_value = $replace_with;
1014 if ( is_array( $replace_with ) ) {
1015 $sep = isset( $atts['sep'] ) ? $atts['sep'] : ', ';
1016 $string_value = implode( $sep, $replace_with );
1017 }
1018
1019 if ( empty( $string_value ) && $string_value != '0' ) {
1020 $replace_with = '';
1021 } else {
1022 $atts['entry_id'] = $atts['entry']->id;
1023 $atts['entry_key'] = $atts['entry']->item_key;
1024 $replace_with = self::get_display_value( $replace_with, $field, $atts );
1025 }
1026 }
1027
1028 return $replace_with;
1029 }
1030
1031 /**
1032 * Get the value to replace a few standard shortcodes
1033 *
1034 * @since 2.0
1035 * @return string
1036 */
1037 public static function dynamic_default_values( $tag, $atts = array(), $return_array = false ) {
1038 $new_value = '';
1039 switch ( $tag ) {
1040 case 'admin_email':
1041 $new_value = get_option( 'admin_email' );
1042 break;
1043 case 'siteurl':
1044 $new_value = FrmAppHelper::site_url();
1045 break;
1046 case 'frmurl':
1047 $new_value = FrmAppHelper::plugin_url();
1048 break;
1049 case 'sitename':
1050 $new_value = FrmAppHelper::site_name();
1051 break;
1052 case 'get':
1053 $new_value = self::process_get_shortcode( $atts, $return_array );
1054 }
1055
1056 return $new_value;
1057 }
1058
1059 /**
1060 * Process the [get] shortcode
1061 *
1062 * @since 2.0
1063 * @return array|string
1064 */
1065 public static function process_get_shortcode( $atts, $return_array = false ) {
1066 if ( ! isset( $atts['param'] ) ) {
1067 return '';
1068 }
1069
1070 if ( strpos( $atts['param'], '&#91;' ) ) {
1071 $atts['param'] = str_replace( '&#91;', '[', $atts['param'] );
1072 $atts['param'] = str_replace( '&#93;', ']', $atts['param'] );
1073 }
1074
1075 $new_value = FrmAppHelper::get_param( $atts['param'], '', 'get', 'sanitize_text_field' );
1076 $new_value = FrmAppHelper::get_query_var( $new_value, $atts['param'] );
1077
1078 if ( $new_value == '' ) {
1079 if ( ! isset( $atts['prev_val'] ) ) {
1080 $atts['prev_val'] = '';
1081 }
1082
1083 $new_value = isset( $atts['default'] ) ? $atts['default'] : $atts['prev_val'];
1084 }
1085
1086 if ( is_array( $new_value ) && ! $return_array ) {
1087 $new_value = implode( ', ', $new_value );
1088 }
1089
1090 return $new_value;
1091 }
1092
1093 public static function get_display_value( $value, $field, $atts = array() ) {
1094
1095 $value = apply_filters( 'frm_get_' . $field->type . '_display_value', $value, $field, $atts );
1096 $value = apply_filters( 'frm_get_display_value', $value, $field, $atts );
1097
1098 $value = self::get_unfiltered_display_value( compact( 'value', 'field', 'atts' ) );
1099
1100 return apply_filters( 'frm_display_value', $value, $field, $atts );
1101 }
1102
1103 /**
1104 * @param array $atts Includes value, field, and atts.
1105 */
1106 public static function get_unfiltered_display_value( $atts ) {
1107 $value = $atts['value'];
1108 $field = $atts['field'];
1109 $atts = isset( $atts['atts'] ) ? $atts['atts'] : $atts;
1110
1111 if ( is_array( $field ) ) {
1112 $field = $field['id'];
1113 }
1114
1115 $field_obj = FrmFieldFactory::get_field_object( $field );
1116
1117 return $field_obj->get_display_value( $value, $atts );
1118 }
1119
1120 /**
1121 * Get a value from the user profile from the user ID
1122 *
1123 * @since 3.0
1124 *
1125 * @return string
1126 */
1127 public static function get_user_display_name( $user_id, $user_info = 'display_name', $args = array() ) {
1128 $defaults = array(
1129 'blank' => false,
1130 'link' => false,
1131 'size' => 96,
1132 );
1133
1134 $args = wp_parse_args( $args, $defaults );
1135
1136 $user = get_userdata( $user_id );
1137 $info = '';
1138
1139 if ( $user ) {
1140 if ( $user_info === 'avatar' ) {
1141 $info = get_avatar( $user_id, $args['size'] );
1142 } elseif ( $user_info === 'author_link' ) {
1143 $info = get_author_posts_url( $user_id );
1144 } else {
1145 $info = isset( $user->$user_info ) ? $user->$user_info : '';
1146 }
1147
1148 if ( 'display_name' === $user_info && empty( $info ) && ! $args['blank'] ) {
1149 $info = $user->user_login;
1150 }
1151 }
1152
1153 if ( $args['link'] ) {
1154 $info = '<a href="' . esc_url( admin_url( 'user-edit.php?user_id=' . $user_id ) ) . '">' . $info . '</a>';
1155 }
1156
1157 return $info;
1158 }
1159
1160 /**
1161 * @param string $type
1162 * @return array
1163 */
1164 public static function get_field_types( $type ) {
1165 $single_input = self::single_input_fields();
1166 $multiple_input = array( 'radio', 'checkbox', 'select', 'scale', 'star', 'lookup' );
1167 $field_selection = FrmField::all_field_selection();
1168 $field_types = array();
1169
1170 if ( in_array( $type, $single_input, true ) ) {
1171 self::field_types_for_input( $single_input, $field_selection, $field_types );
1172 } elseif ( in_array( $type, $multiple_input, true ) ) {
1173 self::field_types_for_input( $multiple_input, $field_selection, $field_types );
1174 } elseif ( isset( $field_selection[ $type ] ) ) {
1175 $field_types[ $type ] = $field_selection[ $type ];
1176 }
1177
1178 $field_types = apply_filters( 'frm_switch_field_types', $field_types, compact( 'type', 'field_selection' ) );
1179
1180 return $field_types;
1181 }
1182
1183 /**
1184 * Get a list of all fields that use a single value input.
1185 *
1186 * @since 4.0
1187 */
1188 public static function single_input_fields() {
1189 $fields = array(
1190 'text',
1191 'textarea',
1192 'rte',
1193 'number',
1194 'email',
1195 'url',
1196 'date',
1197 'phone',
1198 'hidden',
1199 'time',
1200 'tag',
1201 'password',
1202 );
1203 return apply_filters( 'frm_single_input_fields', $fields );
1204 }
1205
1206 /**
1207 * @param string[] $inputs
1208 * @param array $fields
1209 * @param array $field_types
1210 * @return void
1211 */
1212 private static function field_types_for_input( $inputs, $fields, &$field_types ) {
1213 foreach ( $inputs as $input ) {
1214 // This may not be set if a field type was removed using the frm_available_fields or frm_pro_available_fields filters.
1215 if ( array_key_exists( $input, $fields ) ) {
1216 $field_types[ $input ] = $fields[ $input ];
1217 }
1218 unset( $input );
1219 }
1220 }
1221
1222 /**
1223 * Check if current field option is an "other" option
1224 *
1225 * @since 2.0.6
1226 *
1227 * @param string $opt_key
1228 *
1229 * @return bool Returns true if current field option is an "Other" option
1230 */
1231 public static function is_other_opt( $opt_key ) {
1232 return $opt_key && strpos( $opt_key, 'other_' ) === 0;
1233 }
1234
1235 /**
1236 * Get value that belongs in "Other" text box
1237 *
1238 * @since 2.0.6
1239 *
1240 * @param array $args
1241 */
1242 public static function get_other_val( $args ) {
1243 $defaults = array(
1244 'opt_key' => 0,
1245 'field' => array(),
1246 'parent' => false,
1247 'pointer' => false,
1248 );
1249 $args = wp_parse_args( $args, $defaults );
1250
1251 $opt_key = $args['opt_key'];
1252 $field = $args['field'];
1253 $parent = $args['parent'];
1254 $pointer = $args['pointer'];
1255 $other_val = '';
1256
1257 // If option is an "other" option and there is a value set for this field,
1258 // check if the value belongs in the current "Other" option text field
1259 if ( ! self::is_other_opt( $opt_key ) || ! FrmField::is_option_true( $field, 'value' ) ) {
1260 return $other_val;
1261 }
1262
1263 // Check posted vals before checking saved values
1264 // For fields inside repeating sections - note, don't check if $pointer is true because it will often be zero
1265 if ( $parent && isset( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1266 if ( FrmField::is_field_with_multiple_values( $field ) ) {
1267 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1268 $other_val = isset( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ][ $opt_key ] ) ? sanitize_text_field( wp_unslash( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ][ $opt_key ] ) ) : '';
1269 } else {
1270 $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1271 }
1272
1273 return $other_val;
1274 }
1275
1276 if ( isset( $field['id'] ) && isset( $_POST['item_meta']['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1277 // For normal fields
1278
1279 if ( FrmField::is_field_with_multiple_values( $field ) ) {
1280 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1281 $other_val = isset( $_POST['item_meta']['other'][ $field['id'] ][ $opt_key ] ) ? sanitize_text_field( wp_unslash( $_POST['item_meta']['other'][ $field['id'] ][ $opt_key ] ) ) : '';
1282 } else {
1283 $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta']['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1284 }
1285
1286 return $other_val;
1287 }//end if
1288
1289 // For checkboxes
1290 if ( $field['type'] === 'checkbox' && is_array( $field['value'] ) ) {
1291 // Check if there is an "other" val in saved value and make sure the
1292 // "other" val is not equal to the Other checkbox option
1293 if ( isset( $field['value'][ $opt_key ] ) && $field['options'][ $opt_key ] != $field['value'][ $opt_key ] ) {
1294 $other_val = $field['value'][ $opt_key ];
1295 }
1296 } else {
1297 /**
1298 * For radio buttons and dropdowns
1299 * Check if saved value equals any of the options. If not, set it as the other value.
1300 */
1301 foreach ( $field['options'] as $opt_key => $opt_val ) {
1302 $temp_val = is_array( $opt_val ) ? $opt_val['value'] : $opt_val;
1303 // Multi-select dropdowns - key is not preserved
1304 if ( is_array( $field['value'] ) ) {
1305 $o_key = array_search( $temp_val, $field['value'] );
1306 if ( isset( $field['value'][ $o_key ] ) ) {
1307 unset( $field['value'][ $o_key ], $o_key );
1308 }
1309 } elseif ( $temp_val == $field['value'] ) {
1310 // For radio and regular dropdowns
1311 return '';
1312 } else {
1313 $other_val = $field['value'];
1314 }
1315 unset( $opt_key, $opt_val, $temp_val );
1316 }
1317 // For multi-select dropdowns only
1318 if ( is_array( $field['value'] ) && ! empty( $field['value'] ) ) {
1319 $other_val = reset( $field['value'] );
1320 }
1321 }//end if
1322
1323 return $other_val;
1324 }
1325
1326 /**
1327 * Check if there is a saved value for the "Other" text field. If so, set it as the $other_val.
1328 * Intended for front-end use
1329 *
1330 * @since 2.0.6
1331 *
1332 * @param array $args Should include field, opt_key and field name.
1333 * @param bool $other_opt
1334 * @param string $checked
1335 *
1336 * @return array $other_args
1337 */
1338 public static function prepare_other_input( $args, &$other_opt, &$checked ) {
1339 $other_args = array(
1340 'name' => '',
1341 'value' => '',
1342 );
1343
1344 // Check if this is an "Other" option.
1345 if ( ! self::is_other_opt( $args['opt_key'] ) ) {
1346 return $other_args;
1347 }
1348
1349 $other_opt = true;
1350
1351 self::set_other_name( $args, $other_args );
1352 self::set_other_value( $args, $other_args );
1353
1354 if ( '' !== $other_args['value'] ) {
1355 $checked = 'checked="checked" ';
1356 }
1357
1358 // If 'other' is selected as one of the default values for a checkbox field, 'checked' attribute should be on.
1359 if ( ! $checked &&
1360 $args['field']['type'] === 'checkbox' &&
1361 is_array( $args['field']['value'] ) &&
1362 isset( $args['field_val'] ) &&
1363 in_array( $args['field_val'], $args['field']['value'], true )
1364 ) {
1365 $checked = 'checked="checked" ';
1366 }
1367
1368 return $other_args;
1369 }
1370
1371 /**
1372 * @since 2.0.6
1373 * @param array $args
1374 * @param array $other_args
1375 */
1376 private static function set_other_name( $args, &$other_args ) {
1377 // Set up name for other field
1378 $other_args['name'] = str_replace( '[]', '', $args['field_name'] );
1379 $other_args['name'] = preg_replace( '/\[' . $args['field']['id'] . '\]$/', '', $other_args['name'] );
1380 $other_args['name'] = $other_args['name'] . '[other][' . $args['field']['id'] . ']';
1381
1382 // Converts item_meta[field_id] => item_meta[other][field_id] and
1383 // item_meta[parent][0][field_id] => item_meta[parent][0][other][field_id]
1384 if ( FrmField::is_field_with_multiple_values( $args['field'] ) ) {
1385 $other_args['name'] .= '[' . $args['opt_key'] . ']';
1386 }
1387 }
1388
1389 /**
1390 * Find the parent and pointer, and get text for "other" text field
1391 *
1392 * @since 2.0.6
1393 * @param array $args
1394 * @param array $other_args
1395 */
1396 private static function set_other_value( $args, &$other_args ) {
1397 $parent = '';
1398 $pointer = '';
1399
1400 // Check for parent ID and pointer
1401 $temp_array = explode( '[', $args['field_name'] );
1402
1403 // Count should only be greater than 3 if inside of a repeating section
1404 if ( count( $temp_array ) > 3 ) {
1405 $parent = str_replace( ']', '', $temp_array[1] );
1406 $pointer = str_replace( ']', '', $temp_array[2] );
1407 }
1408
1409 // Get text for "other" text field
1410 $other_args['value'] = self::get_other_val(
1411 array(
1412 'opt_key' => $args['opt_key'],
1413 'field' => $args['field'],
1414 'parent' => $parent,
1415 'pointer' => $pointer,
1416 )
1417 );
1418 }
1419
1420 /**
1421 * If this field includes an other option, show it
1422 *
1423 * @since 2.0.6
1424 * @param array $args
1425 */
1426 public static function include_other_input( $args ) {
1427 if ( ! $args['other_opt'] ) {
1428 return;
1429 }
1430
1431 $classes = array( 'frm_other_input' );
1432 if ( ! $args['checked'] || trim( $args['checked'] ) == '' ) {
1433 // hide the field if the other option is not selected
1434 $classes[] = 'frm_pos_none';
1435 }
1436 if ( $args['field']['type'] === 'select' && $args['field']['multiple'] ) {
1437 $classes[] = 'frm_other_full';
1438 }
1439
1440 // Set up HTML ID for Other field
1441 $other_id = self::get_other_field_html_id( $args['field']['type'], $args['html_id'], $args['opt_key'] );
1442
1443 $label = isset( $args['opt_label'] ) ? $args['opt_label'] : $args['field']['name'];
1444
1445 echo '<label for="' . esc_attr( $other_id ) . '" class="frm_screen_reader frm_hidden">' .
1446 esc_html( $label ) .
1447 '</label>' .
1448 '<input type="text" id="' . esc_attr( $other_id ) . '" class="' . esc_attr( implode( ' ', $classes ) ) . '" ' .
1449 ( $args['read_only'] ? ' readonly="readonly" disabled="disabled"' : '' ) .
1450 ' name="' . esc_attr( $args['name'] ) . '" value="' . esc_attr( $args['value'] ) . '" />';
1451 }
1452
1453 /**
1454 * Get the HTML id for an "Other" text field
1455 * Note: This does not affect fields in repeating sections
1456 *
1457 * @since 2.0.08
1458 *
1459 * @param string $type Field type.
1460 * @param string $html_id
1461 * @param bool|string $opt_key
1462 *
1463 * @return string $other_id
1464 */
1465 public static function get_other_field_html_id( $type, $html_id, $opt_key = false ) {
1466 $other_id = $html_id;
1467
1468 // If hidden radio field, add an opt key of 0
1469 if ( $type === 'radio' && $opt_key === false ) {
1470 $opt_key = 0;
1471 }
1472
1473 if ( $opt_key !== false ) {
1474 $other_id .= '-' . $opt_key;
1475 }
1476
1477 $other_id .= '-otext';
1478
1479 return $other_id;
1480 }
1481
1482 public static function switch_field_ids( $val ) {
1483 global $frm_duplicate_ids;
1484 $replace = array();
1485 $replace_with = array();
1486 foreach ( (array) $frm_duplicate_ids as $old => $new ) {
1487 $replace[] = '[if ' . $old . ']';
1488 $replace_with[] = '[if ' . $new . ']';
1489 $replace[] = '[if ' . $old . ' ';
1490 $replace_with[] = '[if ' . $new . ' ';
1491 $replace[] = '[/if ' . $old . ']';
1492 $replace_with[] = '[/if ' . $new . ']';
1493 $replace[] = '[\/if ' . $old . ']';
1494 $replace_with[] = '[\/if ' . $new . ']';
1495 $replace[] = '[foreach ' . $old . ']';
1496 $replace_with[] = '[foreach ' . $new . ']';
1497 $replace[] = '[/foreach ' . $old . ']';
1498 $replace_with[] = '[/foreach ' . $new . ']';
1499 $replace[] = '[\/foreach ' . $old . ']';
1500 $replace_with[] = '[\/foreach ' . $new . ']';
1501 $replace[] = '[' . $old . ']';
1502 $replace_with[] = '[' . $new . ']';
1503 $replace[] = '[' . $old . ' ';
1504 $replace_with[] = '[' . $new . ' ';
1505 $replace[] = 'field_id="' . $old . '"';
1506 $replace_with[] = 'field_id="' . $new . '"';
1507 $replace[] = 'field_id=\"' . $old . '\"';
1508 $replace_with[] = 'field_id=\"' . $new . '\"';
1509 unset( $old, $new );
1510 }//end foreach
1511 if ( is_array( $val ) ) {
1512 foreach ( $val as $k => $v ) {
1513 if ( is_string( $v ) ) {
1514 if ( 'custom_html' === $k ) {
1515 $val[ $k ] = self::switch_ids_except_strings( $replace, $replace_with, array( '[if description]', '[description]', '[/if description]' ), $v );
1516 unset( $k, $v );
1517 continue;
1518 }
1519 $val[ $k ] = str_replace( $replace, $replace_with, $v );
1520 unset( $k, $v );
1521 }
1522 }
1523 } else {
1524 $val = str_replace( $replace, $replace_with, $val );
1525 }
1526
1527 return $val;
1528 }
1529
1530 /**
1531 * Removes exception strings from replacement arrays and replaces the rest in the provided value string.
1532 *
1533 * @since 6.14
1534 *
1535 * @param array $replace Values to be replaced.
1536 * @param array $replace_with Replacement values.
1537 * @param array $exceptions Array of strings to skip.
1538 * @param string $value Value to be updated.
1539 *
1540 * @return string
1541 */
1542 private static function switch_ids_except_strings( $replace, $replace_with, $exceptions, $value ) {
1543 foreach ( $exceptions as $exception ) {
1544 $index = array_search( $exception, $replace, true );
1545 if ( false === $index ) {
1546 continue;
1547 }
1548 unset( $replace[ $index ] );
1549 unset( $replace_with[ $index ] );
1550 }
1551 $value = str_replace( $replace, $replace_with, $value );
1552 return $value;
1553 }
1554
1555 /**
1556 * @since 4.0
1557 */
1558 public static function bulk_options_overlay() {
1559 $prepop = array();
1560 self::get_bulk_prefilled_opts( $prepop, true );
1561
1562 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/bulk-options-overlay.php';
1563 }
1564
1565 public static function get_us_states() {
1566 $states = array(
1567 'AL' => 'Alabama',
1568 'AK' => 'Alaska',
1569 'AR' => 'Arkansas',
1570 'AZ' => 'Arizona',
1571 'CA' => 'California',
1572 'CO' => 'Colorado',
1573 'CT' => 'Connecticut',
1574 'DE' => 'Delaware',
1575 'DC' => 'District of Columbia',
1576 'FL' => 'Florida',
1577 'GA' => 'Georgia',
1578 'HI' => 'Hawaii',
1579 'ID' => 'Idaho',
1580 'IL' => 'Illinois',
1581 'IN' => 'Indiana',
1582 'IA' => 'Iowa',
1583 'KS' => 'Kansas',
1584 'KY' => 'Kentucky',
1585 'LA' => 'Louisiana',
1586 'ME' => 'Maine',
1587 'MD' => 'Maryland',
1588 'MA' => 'Massachusetts',
1589 'MI' => 'Michigan',
1590 'MN' => 'Minnesota',
1591 'MS' => 'Mississippi',
1592 'MO' => 'Missouri',
1593 'MT' => 'Montana',
1594 'NE' => 'Nebraska',
1595 'NV' => 'Nevada',
1596 'NH' => 'New Hampshire',
1597 'NJ' => 'New Jersey',
1598 'NM' => 'New Mexico',
1599 'NY' => 'New York',
1600 'NC' => 'North Carolina',
1601 'ND' => 'North Dakota',
1602 'OH' => 'Ohio',
1603 'OK' => 'Oklahoma',
1604 'OR' => 'Oregon',
1605 'PA' => 'Pennsylvania',
1606 'RI' => 'Rhode Island',
1607 'SC' => 'South Carolina',
1608 'SD' => 'South Dakota',
1609 'TN' => 'Tennessee',
1610 'TX' => 'Texas',
1611 'UT' => 'Utah',
1612 'VT' => 'Vermont',
1613 'VA' => 'Virginia',
1614 'WA' => 'Washington',
1615 'WV' => 'West Virginia',
1616 'WI' => 'Wisconsin',
1617 'WY' => 'Wyoming',
1618 );
1619
1620 return apply_filters( 'frm_us_states', $states );
1621 }
1622
1623 public static function get_countries() {
1624 $countries = array(
1625 __( 'Afghanistan', 'formidable' ),
1626 __( 'Aland Islands', 'formidable' ),
1627 __( 'Albania', 'formidable' ),
1628 __( 'Algeria', 'formidable' ),
1629 __( 'American Samoa', 'formidable' ),
1630 __( 'Andorra', 'formidable' ),
1631 __( 'Angola', 'formidable' ),
1632 __( 'Anguilla', 'formidable' ),
1633 __( 'Antarctica', 'formidable' ),
1634 __( 'Antigua and Barbuda', 'formidable' ),
1635 __( 'Argentina', 'formidable' ),
1636 __( 'Armenia', 'formidable' ),
1637 __( 'Aruba', 'formidable' ),
1638 __( 'Australia', 'formidable' ),
1639 __( 'Austria', 'formidable' ),
1640 __( 'Azerbaijan', 'formidable' ),
1641 __( 'Bahamas', 'formidable' ),
1642 __( 'Bahrain', 'formidable' ),
1643 __( 'Bangladesh', 'formidable' ),
1644 __( 'Barbados', 'formidable' ),
1645 __( 'Belarus', 'formidable' ),
1646 __( 'Belgium', 'formidable' ),
1647 __( 'Belize', 'formidable' ),
1648 __( 'Benin', 'formidable' ),
1649 __( 'Bermuda', 'formidable' ),
1650 __( 'Bhutan', 'formidable' ),
1651 __( 'Bolivia', 'formidable' ),
1652 __( 'Bonaire, Sint Eustatius and Saba', 'formidable' ),
1653 __( 'Bosnia and Herzegovina', 'formidable' ),
1654 __( 'Botswana', 'formidable' ),
1655 __( 'Bouvet Island', 'formidable' ),
1656 __( 'Brazil', 'formidable' ),
1657 __( 'British Indian Ocean Territory', 'formidable' ),
1658 __( 'Brunei', 'formidable' ),
1659 __( 'Bulgaria', 'formidable' ),
1660 __( 'Burkina Faso', 'formidable' ),
1661 __( 'Burundi', 'formidable' ),
1662 __( 'Cambodia', 'formidable' ),
1663 __( 'Cameroon', 'formidable' ),
1664 __( 'Canada', 'formidable' ),
1665 __( 'Cape Verde', 'formidable' ),
1666 __( 'Cayman Islands', 'formidable' ),
1667 __( 'Central African Republic', 'formidable' ),
1668 __( 'Chad', 'formidable' ),
1669 __( 'Chile', 'formidable' ),
1670 __( 'China', 'formidable' ),
1671 __( 'Christmas Island', 'formidable' ),
1672 __( 'Cocos (Keeling) Islands', 'formidable' ),
1673 __( 'Colombia', 'formidable' ),
1674 __( 'Comoros', 'formidable' ),
1675 __( 'Congo', 'formidable' ),
1676 __( 'Cook Islands', 'formidable' ),
1677 __( 'Costa Rica', 'formidable' ),
1678 __( 'C&ocirc;te d\'Ivoire', 'formidable' ),
1679 __( 'Croatia', 'formidable' ),
1680 __( 'Cuba', 'formidable' ),
1681 __( 'Curacao', 'formidable' ),
1682 __( 'Cyprus', 'formidable' ),
1683 __( 'Czech Republic', 'formidable' ),
1684 __( 'Denmark', 'formidable' ),
1685 __( 'Djibouti', 'formidable' ),
1686 __( 'Dominica', 'formidable' ),
1687 __( 'Dominican Republic', 'formidable' ),
1688 __( 'East Timor', 'formidable' ),
1689 __( 'Ecuador', 'formidable' ),
1690 __( 'Egypt', 'formidable' ),
1691 __( 'El Salvador', 'formidable' ),
1692 __( 'Equatorial Guinea', 'formidable' ),
1693 __( 'Eritrea', 'formidable' ),
1694 __( 'Estonia', 'formidable' ),
1695 __( 'Ethiopia', 'formidable' ),
1696 __( 'Falkland Islands (Malvinas)', 'formidable' ),
1697 __( 'Faroe Islands', 'formidable' ),
1698 __( 'Fiji', 'formidable' ),
1699 __( 'Finland', 'formidable' ),
1700 __( 'France', 'formidable' ),
1701 __( 'French Guiana', 'formidable' ),
1702 __( 'French Polynesia', 'formidable' ),
1703 __( 'French Southern Territories', 'formidable' ),
1704 __( 'Gabon', 'formidable' ),
1705 __( 'Gambia', 'formidable' ),
1706 __( 'Georgia', 'formidable' ),
1707 __( 'Germany', 'formidable' ),
1708 __( 'Ghana', 'formidable' ),
1709 __( 'Gibraltar', 'formidable' ),
1710 __( 'Greece', 'formidable' ),
1711 __( 'Greenland', 'formidable' ),
1712 __( 'Grenada', 'formidable' ),
1713 __( 'Guadeloupe', 'formidable' ),
1714 __( 'Guam', 'formidable' ),
1715 __( 'Guatemala', 'formidable' ),
1716 __( 'Guernsey', 'formidable' ),
1717 __( 'Guinea', 'formidable' ),
1718 __( 'Guinea-Bissau', 'formidable' ),
1719 __( 'Guyana', 'formidable' ),
1720 __( 'Haiti', 'formidable' ),
1721 __( 'Heard Island and McDonald Islands', 'formidable' ),
1722 __( 'Holy See', 'formidable' ),
1723 __( 'Honduras', 'formidable' ),
1724 __( 'Hong Kong', 'formidable' ),
1725 __( 'Hungary', 'formidable' ),
1726 __( 'Iceland', 'formidable' ),
1727 __( 'India', 'formidable' ),
1728 __( 'Indonesia', 'formidable' ),
1729 __( 'Iran', 'formidable' ),
1730 __( 'Iraq', 'formidable' ),
1731 __( 'Ireland', 'formidable' ),
1732 __( 'Israel', 'formidable' ),
1733 __( 'Isle of Man', 'formidable' ),
1734 __( 'Italy', 'formidable' ),
1735 __( 'Jamaica', 'formidable' ),
1736 __( 'Japan', 'formidable' ),
1737 __( 'Jersey', 'formidable' ),
1738 __( 'Jordan', 'formidable' ),
1739 __( 'Kazakhstan', 'formidable' ),
1740 __( 'Kenya', 'formidable' ),
1741 __( 'Kiribati', 'formidable' ),
1742 __( 'North Korea', 'formidable' ),
1743 __( 'South Korea', 'formidable' ),
1744 __( 'Kosovo', 'formidable' ),
1745 __( 'Kuwait', 'formidable' ),
1746 __( 'Kyrgyzstan', 'formidable' ),
1747 __( 'Laos', 'formidable' ),
1748 __( 'Latvia', 'formidable' ),
1749 __( 'Lebanon', 'formidable' ),
1750 __( 'Lesotho', 'formidable' ),
1751 __( 'Liberia', 'formidable' ),
1752 __( 'Libya', 'formidable' ),
1753 __( 'Liechtenstein', 'formidable' ),
1754 __( 'Lithuania', 'formidable' ),
1755 __( 'Luxembourg', 'formidable' ),
1756 __( 'Macao', 'formidable' ),
1757 __( 'Macedonia', 'formidable' ),
1758 __( 'Madagascar', 'formidable' ),
1759 __( 'Malawi', 'formidable' ),
1760 __( 'Malaysia', 'formidable' ),
1761 __( 'Maldives', 'formidable' ),
1762 __( 'Mali', 'formidable' ),
1763 __( 'Malta', 'formidable' ),
1764 __( 'Marshall Islands', 'formidable' ),
1765 __( 'Martinique', 'formidable' ),
1766 __( 'Mauritania', 'formidable' ),
1767 __( 'Mauritius', 'formidable' ),
1768 __( 'Mayotte', 'formidable' ),
1769 __( 'Mexico', 'formidable' ),
1770 __( 'Micronesia', 'formidable' ),
1771 __( 'Moldova', 'formidable' ),
1772 __( 'Monaco', 'formidable' ),
1773 __( 'Mongolia', 'formidable' ),
1774 __( 'Montenegro', 'formidable' ),
1775 __( 'Montserrat', 'formidable' ),
1776 __( 'Morocco', 'formidable' ),
1777 __( 'Mozambique', 'formidable' ),
1778 __( 'Myanmar', 'formidable' ),
1779 __( 'Namibia', 'formidable' ),
1780 __( 'Nauru', 'formidable' ),
1781 __( 'Nepal', 'formidable' ),
1782 __( 'Netherlands', 'formidable' ),
1783 __( 'New Caledonia', 'formidable' ),
1784 __( 'New Zealand', 'formidable' ),
1785 __( 'Nicaragua', 'formidable' ),
1786 __( 'Niger', 'formidable' ),
1787 __( 'Nigeria', 'formidable' ),
1788 __( 'Niue', 'formidable' ),
1789 __( 'Norfolk Island', 'formidable' ),
1790 __( 'Northern Mariana Islands', 'formidable' ),
1791 __( 'Norway', 'formidable' ),
1792 __( 'Oman', 'formidable' ),
1793 __( 'Pakistan', 'formidable' ),
1794 __( 'Palau', 'formidable' ),
1795 __( 'Palestine', 'formidable' ),
1796 __( 'Panama', 'formidable' ),
1797 __( 'Papua New Guinea', 'formidable' ),
1798 __( 'Paraguay', 'formidable' ),
1799 __( 'Peru', 'formidable' ),
1800 __( 'Philippines', 'formidable' ),
1801 __( 'Pitcairn', 'formidable' ),
1802 __( 'Poland', 'formidable' ),
1803 __( 'Portugal', 'formidable' ),
1804 __( 'Puerto Rico', 'formidable' ),
1805 __( 'Qatar', 'formidable' ),
1806 __( 'Reunion', 'formidable' ),
1807 __( 'Romania', 'formidable' ),
1808 __( 'Russia', 'formidable' ),
1809 __( 'Rwanda', 'formidable' ),
1810 __( 'Saint Barthelemy', 'formidable' ),
1811 __( 'Saint Helena, Ascension and Tristan da Cunha', 'formidable' ),
1812 __( 'Saint Kitts and Nevis', 'formidable' ),
1813 __( 'Saint Lucia', 'formidable' ),
1814 __( 'Saint Martin (French part)', 'formidable' ),
1815 __( 'Saint Pierre and Miquelon', 'formidable' ),
1816 __( 'Saint Vincent and the Grenadines', 'formidable' ),
1817 __( 'Samoa', 'formidable' ),
1818 __( 'San Marino', 'formidable' ),
1819 __( 'Sao Tome and Principe', 'formidable' ),
1820 __( 'Saudi Arabia', 'formidable' ),
1821 __( 'Senegal', 'formidable' ),
1822 __( 'Serbia', 'formidable' ),
1823 __( 'Seychelles', 'formidable' ),
1824 __( 'Sierra Leone', 'formidable' ),
1825 __( 'Singapore', 'formidable' ),
1826 __( 'Sint Maarten (Dutch part)', 'formidable' ),
1827 __( 'Slovakia', 'formidable' ),
1828 __( 'Slovenia', 'formidable' ),
1829 __( 'Solomon Islands', 'formidable' ),
1830 __( 'Somalia', 'formidable' ),
1831 __( 'South Africa', 'formidable' ),
1832 __( 'South Georgia and the South Sandwich Islands', 'formidable' ),
1833 __( 'South Sudan', 'formidable' ),
1834 __( 'Spain', 'formidable' ),
1835 __( 'Sri Lanka', 'formidable' ),
1836 __( 'Sudan', 'formidable' ),
1837 __( 'Suriname', 'formidable' ),
1838 __( 'Svalbard and Jan Mayen', 'formidable' ),
1839 __( 'Swaziland', 'formidable' ),
1840 __( 'Sweden', 'formidable' ),
1841 __( 'Switzerland', 'formidable' ),
1842 __( 'Syria', 'formidable' ),
1843 __( 'Taiwan', 'formidable' ),
1844 __( 'Tajikistan', 'formidable' ),
1845 __( 'Tanzania', 'formidable' ),
1846 __( 'Thailand', 'formidable' ),
1847 __( 'Timor-Leste', 'formidable' ),
1848 __( 'Togo', 'formidable' ),
1849 __( 'Tokelau', 'formidable' ),
1850 __( 'Tonga', 'formidable' ),
1851 __( 'Trinidad and Tobago', 'formidable' ),
1852 __( 'Tunisia', 'formidable' ),
1853 __( 'Turkey', 'formidable' ),
1854 __( 'Turkmenistan', 'formidable' ),
1855 __( 'Turks and Caicos Islands', 'formidable' ),
1856 __( 'Tuvalu', 'formidable' ),
1857 __( 'Uganda', 'formidable' ),
1858 __( 'Ukraine', 'formidable' ),
1859 __( 'United Arab Emirates', 'formidable' ),
1860 __( 'United Kingdom', 'formidable' ),
1861 __( 'United States', 'formidable' ),
1862 __( 'United States Minor Outlying Islands', 'formidable' ),
1863 __( 'Uruguay', 'formidable' ),
1864 __( 'Uzbekistan', 'formidable' ),
1865 __( 'Vanuatu', 'formidable' ),
1866 __( 'Vatican City', 'formidable' ),
1867 __( 'Venezuela', 'formidable' ),
1868 __( 'Vietnam', 'formidable' ),
1869 __( 'Virgin Islands, British', 'formidable' ),
1870 __( 'Virgin Islands, U.S.', 'formidable' ),
1871 __( 'Wallis and Futuna', 'formidable' ),
1872 __( 'Western Sahara', 'formidable' ),
1873 __( 'Yemen', 'formidable' ),
1874 __( 'Zambia', 'formidable' ),
1875 __( 'Zimbabwe', 'formidable' ),
1876 );
1877
1878 sort( $countries, SORT_LOCALE_STRING );
1879 return apply_filters( 'frm_countries', $countries );
1880 }
1881
1882 /**
1883 * Gets bulk prefilled options.
1884 *
1885 * @since 5.0.04 Add `$include_class` param.
1886 *
1887 * @param array $prepop Bulk options.
1888 * @param array|false $include_class Include the class in the bulk options.
1889 */
1890 public static function get_bulk_prefilled_opts( array &$prepop, $include_class = false ) {
1891 // Countries.
1892 $countries = self::get_countries();
1893 if ( $include_class ) {
1894 $countries['class'] = 'frm-countries-opts';
1895 }
1896
1897 $prepop[ __( 'Countries', 'formidable' ) ] = $countries;
1898
1899 // State abv.
1900 $states = self::get_us_states();
1901 $state_abv = array_keys( $states );
1902 sort( $state_abv );
1903 if ( $include_class ) {
1904 $state_abv['class'] = 'frm-state-abv-opts';
1905 }
1906
1907 $prepop[ __( 'U.S. State Abbreviations', 'formidable' ) ] = $state_abv;
1908
1909 // States.
1910 $states = array_values( $states );
1911 sort( $states );
1912 if ( $include_class ) {
1913 $states['class'] = 'frm-states-opts';
1914 }
1915
1916 $prepop[ __( 'U.S. States', 'formidable' ) ] = $states;
1917 unset( $state_abv, $states );
1918
1919 // Age.
1920 $ages = array(
1921 __( 'Under 18', 'formidable' ),
1922 __( '18-24', 'formidable' ),
1923 __( '25-34', 'formidable' ),
1924 __( '35-44', 'formidable' ),
1925 __( '45-54', 'formidable' ),
1926 __( '55-64', 'formidable' ),
1927 __( '65 or Above', 'formidable' ),
1928 __( 'Prefer Not to Answer', 'formidable' ),
1929 );
1930 if ( $include_class ) {
1931 $ages['class'] = 'frm-age-opts';
1932 }
1933
1934 $prepop[ __( 'Age', 'formidable' ) ] = $ages;
1935
1936 // Satisfaction.
1937 $satisfaction = array(
1938 __( 'Very Unsatisfied', 'formidable' ),
1939 __( 'Unsatisfied', 'formidable' ),
1940 __( 'Neutral', 'formidable' ),
1941 __( 'Satisfied', 'formidable' ),
1942 __( 'Very Satisfied', 'formidable' ),
1943 __( 'N/A', 'formidable' ),
1944 );
1945 if ( $include_class ) {
1946 $satisfaction['class'] = 'frm-satisfaction-opts';
1947 }
1948
1949 $prepop[ __( 'Satisfaction', 'formidable' ) ] = $satisfaction;
1950
1951 // Importance.
1952 $importance = array(
1953 __( 'Not at all Important', 'formidable' ),
1954 __( 'Somewhat Important', 'formidable' ),
1955 __( 'Neutral', 'formidable' ),
1956 __( 'Important', 'formidable' ),
1957 __( 'Very Important', 'formidable' ),
1958 __( 'N/A', 'formidable' ),
1959 );
1960 if ( $include_class ) {
1961 $importance['class'] = 'frm-importance-opts';
1962 }
1963
1964 $prepop[ __( 'Importance', 'formidable' ) ] = $importance;
1965
1966 // Agreement.
1967 $agreement = array(
1968 __( 'Strongly Disagree', 'formidable' ),
1969 __( 'Disagree', 'formidable' ),
1970 __( 'Neutral', 'formidable' ),
1971 __( 'Agree', 'formidable' ),
1972 __( 'Strongly Agree', 'formidable' ),
1973 __( 'N/A', 'formidable' ),
1974 );
1975 if ( $include_class ) {
1976 $agreement['class'] = 'frm-agreement-opts';
1977 }
1978
1979 $prepop[ __( 'Agreement', 'formidable' ) ] = $agreement;
1980
1981 // Likely.
1982 $likely = array(
1983 __( 'Extremely Unlikely', 'formidable' ),
1984 __( 'Unlikely', 'formidable' ),
1985 __( 'Neutral', 'formidable' ),
1986 __( 'Likely', 'formidable' ),
1987 __( 'Extremely Likely', 'formidable' ),
1988 __( 'N/A', 'formidable' ),
1989 );
1990 if ( $include_class ) {
1991 $likely['class'] = 'frm-likely-opts';
1992 }
1993
1994 $prepop[ __( 'Likely', 'formidable' ) ] = $likely;
1995
1996 $prepop = apply_filters( 'frm_bulk_field_choices', $prepop );
1997 }
1998
1999 /**
2000 * Display a field value selector
2001 *
2002 * @since 2.03.05
2003 *
2004 * @param int $selector_field_id
2005 * @param array $selector_args
2006 */
2007 public static function display_field_value_selector( $selector_field_id, $selector_args ) {
2008 $field_value_selector = FrmFieldFactory::create_field_value_selector( $selector_field_id, $selector_args );
2009 $field_value_selector->display();
2010 }
2011
2012 /**
2013 * Convert a field object to a flat array
2014 *
2015 * @since 2.03.05
2016 *
2017 * @param object $field
2018 *
2019 * @return array
2020 */
2021 public static function convert_field_object_to_flat_array( $field ) {
2022 $field_options = $field->field_options;
2023 $field_array = get_object_vars( $field );
2024 unset( $field_array['field_options'] );
2025
2026 return $field_array + $field_options;
2027 }
2028
2029 /**
2030 * @since 4.04
2031 *
2032 * @param array $args
2033 * @return void
2034 */
2035 public static function show_add_field_buttons( $args ) {
2036 $field_key = $args['field_key'];
2037 $field_type = $args['field_type'];
2038 $field_label = FrmAppHelper::icon_by_class( FrmFormsHelper::get_field_link_icon( $field_type ), array( 'echo' => false ) );
2039 $field_name = FrmFormsHelper::get_field_link_name( $field_type );
2040 $field_label .= ' <span>' . $field_name . '</span>';
2041
2042 if ( ! empty( $field_type['is_new'] ) ) {
2043 ob_start();
2044 FrmAppHelper::show_pill_text();
2045 $field_label .= ob_get_clean();
2046 }
2047
2048 // If the individual field isn't allowed, disable it.
2049 $run_filter = true;
2050 $single_no_allow = ' ';
2051 $install_data = '';
2052 $requires = '';
2053 $link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
2054 $has_show_upgrade_class = strpos( $field_type['icon'], ' frm_show_upgrade' );
2055 $show_upgrade = $has_show_upgrade_class || false !== strpos( $args['no_allow_class'], 'frm_show_upgrade' );
2056
2057 if ( $has_show_upgrade_class ) {
2058 $single_no_allow .= 'frm_show_upgrade';
2059 $field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
2060 $run_filter = false;
2061 if ( isset( $field_type['addon'] ) ) {
2062 $upgrading = FrmAddonsController::install_link( $field_type['addon'] );
2063 if ( isset( $upgrading['url'] ) ) {
2064 $install_data = json_encode( $upgrading );
2065 }
2066 $requires = FrmFormsHelper::get_plan_required( $upgrading );
2067 } elseif ( isset( $field_type['require'] ) ) {
2068 $requires = $field_type['require'];
2069 }
2070 }
2071
2072 $upgrade_label = '';
2073 $upgrade_message = '';
2074 if ( $show_upgrade ) {
2075 /* translators: %s: Field name */
2076 $upgrade_label = sprintf( esc_html__( '%s fields', 'formidable' ), $field_name );
2077
2078 if ( isset( $field_type['message'] ) ) {
2079 $upgrade_message = FrmAppHelper::kses( $field_type['message'], array( 'a', 'img' ) );
2080 }
2081 }
2082
2083 $li_params = array(
2084 'class' => 'frmbutton frm6 ' . $args['no_allow_class'] . $single_no_allow . ' frm_t' . str_replace( '|', '-', $field_key ),
2085 'id' => $field_key,
2086 'data-upgrade' => $upgrade_label,
2087 'data-link' => $link,
2088 'data-medium' => 'builder',
2089 'data-oneclick' => $install_data,
2090 'data-content' => $field_key,
2091 'data-requires' => $requires,
2092 );
2093
2094 if ( ! empty( $field_type['hide'] ) ) {
2095 $li_params['class'] .= ' frm_hidden';
2096 }
2097
2098 if ( ! empty( $field_type['upsell_image'] ) ) {
2099 $li_params['data-upsell-image'] = $field_type['upsell_image'];
2100 }
2101
2102 if ( $upgrade_message ) {
2103 $li_params['data-message'] = $upgrade_message;
2104 }
2105 ?>
2106 <li <?php FrmAppHelper::array_to_html_params( $li_params, true ); ?>>
2107 <?php
2108 if ( $run_filter ) {
2109 $field_label = apply_filters( 'frmpro_field_links', $field_label, $args['id'], $field_key );
2110 }
2111 echo FrmAppHelper::kses( $field_label, array( 'a', 'i', 'span', 'use', 'svg' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2112 ?>
2113 </li>
2114 <?php
2115 }
2116
2117 /**
2118 * Shows Display format option.
2119 *
2120 * @since 5.0.04
2121 *
2122 * @param array $field Field data.
2123 */
2124 public static function show_radio_display_format( $field ) {
2125 $options = self::get_display_format_options( $field );
2126
2127 $args = self::get_display_format_args( $field, $options );
2128
2129 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/radio-display-format.php';
2130 }
2131
2132 /**
2133 * Creates an array that contains variables used for display format options setting.
2134 *
2135 * @since 6.3.2
2136 *
2137 * @param array $field The field.
2138 *
2139 * @return array
2140 */
2141 public static function get_display_format_options( $field ) {
2142 $options = array(
2143 '0' => array(
2144 'text' => __( 'Simple', 'formidable' ),
2145 'svg' => 'frm_simple_radio',
2146 ),
2147 '1' => array(
2148 'text' => __( 'Images', 'formidable' ),
2149 'svg' => 'frm_image_as_option',
2150 'addon' => 'pro',
2151 'upgrade' => __( 'Image Options', 'formidable' ),
2152 'message' => __( 'Show images instead of radio buttons or check boxes. This is ideal for polls, surveys, segmenting questionnaires and more.', 'formidable' ) . '<img src="' . esc_url( FrmAppHelper::plugin_url() ) . '/images/image-options.png" />',
2153 'content' => 'image-options',
2154 ),
2155 'buttons' => array(
2156 'text' => __( 'Buttons', 'formidable' ),
2157 'svg' => 'frm_button_as_option',
2158 'addon' => 'surveys',
2159 'upgrade' => __( 'Button Options', 'formidable' ),
2160 'message' => __( 'Show buttons for radio buttons or check boxes. This is ideal for polls, surveys, segmenting questionnaires and more.', 'formidable' ),
2161 'content' => 'button-options',
2162 ),
2163 );
2164
2165 /**
2166 * Allows modifying the options of Display format setting of Radio field.
2167 *
2168 * @since 5.0.04
2169 *
2170 * @param array $options Options.
2171 * @param array $field
2172 */
2173 $options = apply_filters( 'frm_' . $field['type'] . '_display_format_options', $options, $field );
2174
2175 return $options;
2176 }
2177
2178 /**
2179 * Gets display format arguments to pass to the images_dropdown() method.
2180 *
2181 * @since 5.0.04
2182 *
2183 * @param array $field Field data.
2184 * @param array $options Options array.
2185 * @return array
2186 */
2187 public static function get_display_format_args( $field, $options ) {
2188 $args = array(
2189 'selected' => '0',
2190 'options' => array(),
2191 'name' => 'field_options[image_options_' . $field['id'] . ']',
2192 'input_attrs' => array(
2193 'class' => 'frm_toggle_image_options',
2194 ),
2195 );
2196
2197 self::fill_image_setting_options( $options, $args );
2198
2199 /**
2200 * Allows modifying the arguments of Display format setting of Radio field.
2201 *
2202 * @since 5.0.04
2203 *
2204 * @param array $args Arguments.
2205 * @param array $method_args The arguments from the method. Contains `field`, `options`.
2206 */
2207 return apply_filters( 'frm_' . $field['type'] . '_display_format_args', $args, compact( 'field', 'options' ) );
2208 }
2209
2210 /**
2211 * @since 5.0.04
2212 */
2213 private static function fill_image_setting_options( $options, &$args ) {
2214 foreach ( $options as $key => $option ) {
2215 $args['options'][ $key ] = $option;
2216
2217 if ( ! empty( $option['addon'] ) ) {
2218 $args['options'][ $key ]['custom_attrs'] = self::fill_image_setting_addon_link( $option );
2219 }
2220
2221 unset( $args['options'][ $key ]['addon'] );
2222 $fill = array( 'upgrade', 'message', 'content' );
2223 foreach ( $fill as $f ) {
2224 unset( $args['options'][ $key ][ $f ], $f );
2225 }
2226 }
2227 }
2228
2229 /**
2230 * @since 5.0.04
2231 *
2232 * @return array
2233 */
2234 private static function fill_image_setting_addon_link( $option ) {
2235 $custom_attrs = array(
2236 'class' => 'frm_noallow frm_show_upgrade',
2237 'data-medium' => 'builder',
2238 );
2239
2240 // translators: Add-on name.
2241 $custom_attrs['data-upgrade'] = sprintf( __( 'Formidable %s', 'formidable' ), ucwords( $option['addon'] ) );
2242
2243 $fill = array( 'upgrade', 'message', 'content' );
2244 foreach ( $fill as $f ) {
2245 if ( isset( $option[ $f ] ) ) {
2246 $custom_attrs[ 'data-' . $f ] = $option[ $f ];
2247 }
2248 }
2249
2250 if ( 'pro' === $option['addon'] ) {
2251 return $custom_attrs;
2252 }
2253
2254 $upgrading = FrmAddonsController::install_link( $option['addon'] );
2255 if ( isset( $upgrading['url'] ) ) {
2256 $install_data = wp_json_encode( $upgrading );
2257 } else {
2258 $install_data = '';
2259 }
2260
2261 $custom_attrs['data-oneclick'] = $install_data;
2262 $custom_attrs['data-requires'] = FrmFormsHelper::get_plan_required( $upgrading );
2263
2264 return $custom_attrs;
2265 }
2266
2267 /**
2268 * Maybe adjust a field value based on type.
2269 * Some types require unserializing an array.
2270 * These types are defined by a array_allowed property on their field model class.
2271 *
2272 * @since 6.2
2273 *
2274 * @param mixed $value
2275 * @param string $field_type
2276 * @return void
2277 */
2278 public static function prepare_field_value( &$value, $field_type ) {
2279 $field_object = FrmFieldFactory::get_field_type( $field_type );
2280 $value = $field_object->maybe_decode_value( $value );
2281 }
2282
2283 /**
2284 * @since 6.8
2285 *
2286 * @param int|string $form_id
2287 * @param array $field_ids If this is not empty, the results will be filtered by field id.
2288 * @return array
2289 */
2290 public static function get_draft_field_results( $form_id, $field_ids = array() ) {
2291 if ( FrmAppHelper::pro_is_installed() ) {
2292 $child_form_ids = FrmDb::get_col( 'frm_forms', array( 'parent_form_id' => $form_id ) );
2293 $form_ids = array_merge( array( $form_id ), $child_form_ids );
2294 } else {
2295 $form_ids = array( $form_id );
2296 }
2297
2298 $where = array(
2299 'form_id' => $form_ids,
2300 // Do a soft check for fields that look like drafts only.
2301 'field_options LIKE' => 's:5:"draft";i:1;',
2302 );
2303
2304 if ( $field_ids ) {
2305 $where['id'] = $field_ids;
2306 }
2307
2308 $rows = FrmDb::get_results( 'frm_fields', $where, 'id, field_options' );
2309
2310 return array_filter(
2311 $rows,
2312 function ( $row ) {
2313 FrmAppHelper::unserialize_or_decode( $row->field_options );
2314 return is_array( $row->field_options ) && ! empty( $row->field_options['draft'] );
2315 }
2316 );
2317 }
2318
2319 /**
2320 * This is called when loading the form builder.
2321 * Any unsaved draft fields get added to a hidden draft_fields input on load.
2322 *
2323 * @since 6.8
2324 *
2325 * @param int|string $form_id
2326 * @return array
2327 */
2328 public static function get_all_draft_field_ids( $form_id ) {
2329 $draft_field_rows = self::get_draft_field_results( $form_id );
2330 return wp_list_pluck( $draft_field_rows, 'id' );
2331 }
2332 }
2333