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

2,303 lines 67.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 $val[ $k ] = str_replace( $replace, $replace_with, $v );
1515 unset( $k, $v );
1516 }
1517 }
1518 } else {
1519 $val = str_replace( $replace, $replace_with, $val );
1520 }
1521
1522 return $val;
1523 }
1524
1525 /**
1526 * @since 4.0
1527 */
1528 public static function bulk_options_overlay() {
1529 $prepop = array();
1530 self::get_bulk_prefilled_opts( $prepop, true );
1531
1532 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/bulk-options-overlay.php';
1533 }
1534
1535 public static function get_us_states() {
1536 $states = array(
1537 'AL' => 'Alabama',
1538 'AK' => 'Alaska',
1539 'AR' => 'Arkansas',
1540 'AZ' => 'Arizona',
1541 'CA' => 'California',
1542 'CO' => 'Colorado',
1543 'CT' => 'Connecticut',
1544 'DE' => 'Delaware',
1545 'DC' => 'District of Columbia',
1546 'FL' => 'Florida',
1547 'GA' => 'Georgia',
1548 'HI' => 'Hawaii',
1549 'ID' => 'Idaho',
1550 'IL' => 'Illinois',
1551 'IN' => 'Indiana',
1552 'IA' => 'Iowa',
1553 'KS' => 'Kansas',
1554 'KY' => 'Kentucky',
1555 'LA' => 'Louisiana',
1556 'ME' => 'Maine',
1557 'MD' => 'Maryland',
1558 'MA' => 'Massachusetts',
1559 'MI' => 'Michigan',
1560 'MN' => 'Minnesota',
1561 'MS' => 'Mississippi',
1562 'MO' => 'Missouri',
1563 'MT' => 'Montana',
1564 'NE' => 'Nebraska',
1565 'NV' => 'Nevada',
1566 'NH' => 'New Hampshire',
1567 'NJ' => 'New Jersey',
1568 'NM' => 'New Mexico',
1569 'NY' => 'New York',
1570 'NC' => 'North Carolina',
1571 'ND' => 'North Dakota',
1572 'OH' => 'Ohio',
1573 'OK' => 'Oklahoma',
1574 'OR' => 'Oregon',
1575 'PA' => 'Pennsylvania',
1576 'RI' => 'Rhode Island',
1577 'SC' => 'South Carolina',
1578 'SD' => 'South Dakota',
1579 'TN' => 'Tennessee',
1580 'TX' => 'Texas',
1581 'UT' => 'Utah',
1582 'VT' => 'Vermont',
1583 'VA' => 'Virginia',
1584 'WA' => 'Washington',
1585 'WV' => 'West Virginia',
1586 'WI' => 'Wisconsin',
1587 'WY' => 'Wyoming',
1588 );
1589
1590 return apply_filters( 'frm_us_states', $states );
1591 }
1592
1593 public static function get_countries() {
1594 $countries = array(
1595 __( 'Afghanistan', 'formidable' ),
1596 __( 'Aland Islands', 'formidable' ),
1597 __( 'Albania', 'formidable' ),
1598 __( 'Algeria', 'formidable' ),
1599 __( 'American Samoa', 'formidable' ),
1600 __( 'Andorra', 'formidable' ),
1601 __( 'Angola', 'formidable' ),
1602 __( 'Anguilla', 'formidable' ),
1603 __( 'Antarctica', 'formidable' ),
1604 __( 'Antigua and Barbuda', 'formidable' ),
1605 __( 'Argentina', 'formidable' ),
1606 __( 'Armenia', 'formidable' ),
1607 __( 'Aruba', 'formidable' ),
1608 __( 'Australia', 'formidable' ),
1609 __( 'Austria', 'formidable' ),
1610 __( 'Azerbaijan', 'formidable' ),
1611 __( 'Bahamas', 'formidable' ),
1612 __( 'Bahrain', 'formidable' ),
1613 __( 'Bangladesh', 'formidable' ),
1614 __( 'Barbados', 'formidable' ),
1615 __( 'Belarus', 'formidable' ),
1616 __( 'Belgium', 'formidable' ),
1617 __( 'Belize', 'formidable' ),
1618 __( 'Benin', 'formidable' ),
1619 __( 'Bermuda', 'formidable' ),
1620 __( 'Bhutan', 'formidable' ),
1621 __( 'Bolivia', 'formidable' ),
1622 __( 'Bonaire, Sint Eustatius and Saba', 'formidable' ),
1623 __( 'Bosnia and Herzegovina', 'formidable' ),
1624 __( 'Botswana', 'formidable' ),
1625 __( 'Bouvet Island', 'formidable' ),
1626 __( 'Brazil', 'formidable' ),
1627 __( 'British Indian Ocean Territory', 'formidable' ),
1628 __( 'Brunei', 'formidable' ),
1629 __( 'Bulgaria', 'formidable' ),
1630 __( 'Burkina Faso', 'formidable' ),
1631 __( 'Burundi', 'formidable' ),
1632 __( 'Cambodia', 'formidable' ),
1633 __( 'Cameroon', 'formidable' ),
1634 __( 'Canada', 'formidable' ),
1635 __( 'Cape Verde', 'formidable' ),
1636 __( 'Cayman Islands', 'formidable' ),
1637 __( 'Central African Republic', 'formidable' ),
1638 __( 'Chad', 'formidable' ),
1639 __( 'Chile', 'formidable' ),
1640 __( 'China', 'formidable' ),
1641 __( 'Christmas Island', 'formidable' ),
1642 __( 'Cocos (Keeling) Islands', 'formidable' ),
1643 __( 'Colombia', 'formidable' ),
1644 __( 'Comoros', 'formidable' ),
1645 __( 'Congo', 'formidable' ),
1646 __( 'Cook Islands', 'formidable' ),
1647 __( 'Costa Rica', 'formidable' ),
1648 __( 'C&ocirc;te d\'Ivoire', 'formidable' ),
1649 __( 'Croatia', 'formidable' ),
1650 __( 'Cuba', 'formidable' ),
1651 __( 'Curacao', 'formidable' ),
1652 __( 'Cyprus', 'formidable' ),
1653 __( 'Czech Republic', 'formidable' ),
1654 __( 'Denmark', 'formidable' ),
1655 __( 'Djibouti', 'formidable' ),
1656 __( 'Dominica', 'formidable' ),
1657 __( 'Dominican Republic', 'formidable' ),
1658 __( 'East Timor', 'formidable' ),
1659 __( 'Ecuador', 'formidable' ),
1660 __( 'Egypt', 'formidable' ),
1661 __( 'El Salvador', 'formidable' ),
1662 __( 'Equatorial Guinea', 'formidable' ),
1663 __( 'Eritrea', 'formidable' ),
1664 __( 'Estonia', 'formidable' ),
1665 __( 'Ethiopia', 'formidable' ),
1666 __( 'Falkland Islands (Malvinas)', 'formidable' ),
1667 __( 'Faroe Islands', 'formidable' ),
1668 __( 'Fiji', 'formidable' ),
1669 __( 'Finland', 'formidable' ),
1670 __( 'France', 'formidable' ),
1671 __( 'French Guiana', 'formidable' ),
1672 __( 'French Polynesia', 'formidable' ),
1673 __( 'French Southern Territories', 'formidable' ),
1674 __( 'Gabon', 'formidable' ),
1675 __( 'Gambia', 'formidable' ),
1676 __( 'Georgia', 'formidable' ),
1677 __( 'Germany', 'formidable' ),
1678 __( 'Ghana', 'formidable' ),
1679 __( 'Gibraltar', 'formidable' ),
1680 __( 'Greece', 'formidable' ),
1681 __( 'Greenland', 'formidable' ),
1682 __( 'Grenada', 'formidable' ),
1683 __( 'Guadeloupe', 'formidable' ),
1684 __( 'Guam', 'formidable' ),
1685 __( 'Guatemala', 'formidable' ),
1686 __( 'Guernsey', 'formidable' ),
1687 __( 'Guinea', 'formidable' ),
1688 __( 'Guinea-Bissau', 'formidable' ),
1689 __( 'Guyana', 'formidable' ),
1690 __( 'Haiti', 'formidable' ),
1691 __( 'Heard Island and McDonald Islands', 'formidable' ),
1692 __( 'Holy See', 'formidable' ),
1693 __( 'Honduras', 'formidable' ),
1694 __( 'Hong Kong', 'formidable' ),
1695 __( 'Hungary', 'formidable' ),
1696 __( 'Iceland', 'formidable' ),
1697 __( 'India', 'formidable' ),
1698 __( 'Indonesia', 'formidable' ),
1699 __( 'Iran', 'formidable' ),
1700 __( 'Iraq', 'formidable' ),
1701 __( 'Ireland', 'formidable' ),
1702 __( 'Israel', 'formidable' ),
1703 __( 'Isle of Man', 'formidable' ),
1704 __( 'Italy', 'formidable' ),
1705 __( 'Jamaica', 'formidable' ),
1706 __( 'Japan', 'formidable' ),
1707 __( 'Jersey', 'formidable' ),
1708 __( 'Jordan', 'formidable' ),
1709 __( 'Kazakhstan', 'formidable' ),
1710 __( 'Kenya', 'formidable' ),
1711 __( 'Kiribati', 'formidable' ),
1712 __( 'North Korea', 'formidable' ),
1713 __( 'South Korea', 'formidable' ),
1714 __( 'Kosovo', 'formidable' ),
1715 __( 'Kuwait', 'formidable' ),
1716 __( 'Kyrgyzstan', 'formidable' ),
1717 __( 'Laos', 'formidable' ),
1718 __( 'Latvia', 'formidable' ),
1719 __( 'Lebanon', 'formidable' ),
1720 __( 'Lesotho', 'formidable' ),
1721 __( 'Liberia', 'formidable' ),
1722 __( 'Libya', 'formidable' ),
1723 __( 'Liechtenstein', 'formidable' ),
1724 __( 'Lithuania', 'formidable' ),
1725 __( 'Luxembourg', 'formidable' ),
1726 __( 'Macao', 'formidable' ),
1727 __( 'Macedonia', 'formidable' ),
1728 __( 'Madagascar', 'formidable' ),
1729 __( 'Malawi', 'formidable' ),
1730 __( 'Malaysia', 'formidable' ),
1731 __( 'Maldives', 'formidable' ),
1732 __( 'Mali', 'formidable' ),
1733 __( 'Malta', 'formidable' ),
1734 __( 'Marshall Islands', 'formidable' ),
1735 __( 'Martinique', 'formidable' ),
1736 __( 'Mauritania', 'formidable' ),
1737 __( 'Mauritius', 'formidable' ),
1738 __( 'Mayotte', 'formidable' ),
1739 __( 'Mexico', 'formidable' ),
1740 __( 'Micronesia', 'formidable' ),
1741 __( 'Moldova', 'formidable' ),
1742 __( 'Monaco', 'formidable' ),
1743 __( 'Mongolia', 'formidable' ),
1744 __( 'Montenegro', 'formidable' ),
1745 __( 'Montserrat', 'formidable' ),
1746 __( 'Morocco', 'formidable' ),
1747 __( 'Mozambique', 'formidable' ),
1748 __( 'Myanmar', 'formidable' ),
1749 __( 'Namibia', 'formidable' ),
1750 __( 'Nauru', 'formidable' ),
1751 __( 'Nepal', 'formidable' ),
1752 __( 'Netherlands', 'formidable' ),
1753 __( 'New Caledonia', 'formidable' ),
1754 __( 'New Zealand', 'formidable' ),
1755 __( 'Nicaragua', 'formidable' ),
1756 __( 'Niger', 'formidable' ),
1757 __( 'Nigeria', 'formidable' ),
1758 __( 'Niue', 'formidable' ),
1759 __( 'Norfolk Island', 'formidable' ),
1760 __( 'Northern Mariana Islands', 'formidable' ),
1761 __( 'Norway', 'formidable' ),
1762 __( 'Oman', 'formidable' ),
1763 __( 'Pakistan', 'formidable' ),
1764 __( 'Palau', 'formidable' ),
1765 __( 'Palestine', 'formidable' ),
1766 __( 'Panama', 'formidable' ),
1767 __( 'Papua New Guinea', 'formidable' ),
1768 __( 'Paraguay', 'formidable' ),
1769 __( 'Peru', 'formidable' ),
1770 __( 'Philippines', 'formidable' ),
1771 __( 'Pitcairn', 'formidable' ),
1772 __( 'Poland', 'formidable' ),
1773 __( 'Portugal', 'formidable' ),
1774 __( 'Puerto Rico', 'formidable' ),
1775 __( 'Qatar', 'formidable' ),
1776 __( 'Reunion', 'formidable' ),
1777 __( 'Romania', 'formidable' ),
1778 __( 'Russia', 'formidable' ),
1779 __( 'Rwanda', 'formidable' ),
1780 __( 'Saint Barthelemy', 'formidable' ),
1781 __( 'Saint Helena, Ascension and Tristan da Cunha', 'formidable' ),
1782 __( 'Saint Kitts and Nevis', 'formidable' ),
1783 __( 'Saint Lucia', 'formidable' ),
1784 __( 'Saint Martin (French part)', 'formidable' ),
1785 __( 'Saint Pierre and Miquelon', 'formidable' ),
1786 __( 'Saint Vincent and the Grenadines', 'formidable' ),
1787 __( 'Samoa', 'formidable' ),
1788 __( 'San Marino', 'formidable' ),
1789 __( 'Sao Tome and Principe', 'formidable' ),
1790 __( 'Saudi Arabia', 'formidable' ),
1791 __( 'Senegal', 'formidable' ),
1792 __( 'Serbia', 'formidable' ),
1793 __( 'Seychelles', 'formidable' ),
1794 __( 'Sierra Leone', 'formidable' ),
1795 __( 'Singapore', 'formidable' ),
1796 __( 'Sint Maarten (Dutch part)', 'formidable' ),
1797 __( 'Slovakia', 'formidable' ),
1798 __( 'Slovenia', 'formidable' ),
1799 __( 'Solomon Islands', 'formidable' ),
1800 __( 'Somalia', 'formidable' ),
1801 __( 'South Africa', 'formidable' ),
1802 __( 'South Georgia and the South Sandwich Islands', 'formidable' ),
1803 __( 'South Sudan', 'formidable' ),
1804 __( 'Spain', 'formidable' ),
1805 __( 'Sri Lanka', 'formidable' ),
1806 __( 'Sudan', 'formidable' ),
1807 __( 'Suriname', 'formidable' ),
1808 __( 'Svalbard and Jan Mayen', 'formidable' ),
1809 __( 'Swaziland', 'formidable' ),
1810 __( 'Sweden', 'formidable' ),
1811 __( 'Switzerland', 'formidable' ),
1812 __( 'Syria', 'formidable' ),
1813 __( 'Taiwan', 'formidable' ),
1814 __( 'Tajikistan', 'formidable' ),
1815 __( 'Tanzania', 'formidable' ),
1816 __( 'Thailand', 'formidable' ),
1817 __( 'Timor-Leste', 'formidable' ),
1818 __( 'Togo', 'formidable' ),
1819 __( 'Tokelau', 'formidable' ),
1820 __( 'Tonga', 'formidable' ),
1821 __( 'Trinidad and Tobago', 'formidable' ),
1822 __( 'Tunisia', 'formidable' ),
1823 __( 'Turkey', 'formidable' ),
1824 __( 'Turkmenistan', 'formidable' ),
1825 __( 'Turks and Caicos Islands', 'formidable' ),
1826 __( 'Tuvalu', 'formidable' ),
1827 __( 'Uganda', 'formidable' ),
1828 __( 'Ukraine', 'formidable' ),
1829 __( 'United Arab Emirates', 'formidable' ),
1830 __( 'United Kingdom', 'formidable' ),
1831 __( 'United States', 'formidable' ),
1832 __( 'United States Minor Outlying Islands', 'formidable' ),
1833 __( 'Uruguay', 'formidable' ),
1834 __( 'Uzbekistan', 'formidable' ),
1835 __( 'Vanuatu', 'formidable' ),
1836 __( 'Vatican City', 'formidable' ),
1837 __( 'Venezuela', 'formidable' ),
1838 __( 'Vietnam', 'formidable' ),
1839 __( 'Virgin Islands, British', 'formidable' ),
1840 __( 'Virgin Islands, U.S.', 'formidable' ),
1841 __( 'Wallis and Futuna', 'formidable' ),
1842 __( 'Western Sahara', 'formidable' ),
1843 __( 'Yemen', 'formidable' ),
1844 __( 'Zambia', 'formidable' ),
1845 __( 'Zimbabwe', 'formidable' ),
1846 );
1847
1848 sort( $countries, SORT_LOCALE_STRING );
1849 return apply_filters( 'frm_countries', $countries );
1850 }
1851
1852 /**
1853 * Gets bulk prefilled options.
1854 *
1855 * @since 5.0.04 Add `$include_class` param.
1856 *
1857 * @param array $prepop Bulk options.
1858 * @param array|false $include_class Include the class in the bulk options.
1859 */
1860 public static function get_bulk_prefilled_opts( array &$prepop, $include_class = false ) {
1861 // Countries.
1862 $countries = self::get_countries();
1863 if ( $include_class ) {
1864 $countries['class'] = 'frm-countries-opts';
1865 }
1866
1867 $prepop[ __( 'Countries', 'formidable' ) ] = $countries;
1868
1869 // State abv.
1870 $states = self::get_us_states();
1871 $state_abv = array_keys( $states );
1872 sort( $state_abv );
1873 if ( $include_class ) {
1874 $state_abv['class'] = 'frm-state-abv-opts';
1875 }
1876
1877 $prepop[ __( 'U.S. State Abbreviations', 'formidable' ) ] = $state_abv;
1878
1879 // States.
1880 $states = array_values( $states );
1881 sort( $states );
1882 if ( $include_class ) {
1883 $states['class'] = 'frm-states-opts';
1884 }
1885
1886 $prepop[ __( 'U.S. States', 'formidable' ) ] = $states;
1887 unset( $state_abv, $states );
1888
1889 // Age.
1890 $ages = array(
1891 __( 'Under 18', 'formidable' ),
1892 __( '18-24', 'formidable' ),
1893 __( '25-34', 'formidable' ),
1894 __( '35-44', 'formidable' ),
1895 __( '45-54', 'formidable' ),
1896 __( '55-64', 'formidable' ),
1897 __( '65 or Above', 'formidable' ),
1898 __( 'Prefer Not to Answer', 'formidable' ),
1899 );
1900 if ( $include_class ) {
1901 $ages['class'] = 'frm-age-opts';
1902 }
1903
1904 $prepop[ __( 'Age', 'formidable' ) ] = $ages;
1905
1906 // Satisfaction.
1907 $satisfaction = array(
1908 __( 'Very Unsatisfied', 'formidable' ),
1909 __( 'Unsatisfied', 'formidable' ),
1910 __( 'Neutral', 'formidable' ),
1911 __( 'Satisfied', 'formidable' ),
1912 __( 'Very Satisfied', 'formidable' ),
1913 __( 'N/A', 'formidable' ),
1914 );
1915 if ( $include_class ) {
1916 $satisfaction['class'] = 'frm-satisfaction-opts';
1917 }
1918
1919 $prepop[ __( 'Satisfaction', 'formidable' ) ] = $satisfaction;
1920
1921 // Importance.
1922 $importance = array(
1923 __( 'Not at all Important', 'formidable' ),
1924 __( 'Somewhat Important', 'formidable' ),
1925 __( 'Neutral', 'formidable' ),
1926 __( 'Important', 'formidable' ),
1927 __( 'Very Important', 'formidable' ),
1928 __( 'N/A', 'formidable' ),
1929 );
1930 if ( $include_class ) {
1931 $importance['class'] = 'frm-importance-opts';
1932 }
1933
1934 $prepop[ __( 'Importance', 'formidable' ) ] = $importance;
1935
1936 // Agreement.
1937 $agreement = array(
1938 __( 'Strongly Disagree', 'formidable' ),
1939 __( 'Disagree', 'formidable' ),
1940 __( 'Neutral', 'formidable' ),
1941 __( 'Agree', 'formidable' ),
1942 __( 'Strongly Agree', 'formidable' ),
1943 __( 'N/A', 'formidable' ),
1944 );
1945 if ( $include_class ) {
1946 $agreement['class'] = 'frm-agreement-opts';
1947 }
1948
1949 $prepop[ __( 'Agreement', 'formidable' ) ] = $agreement;
1950
1951 // Likely.
1952 $likely = array(
1953 __( 'Extremely Unlikely', 'formidable' ),
1954 __( 'Unlikely', 'formidable' ),
1955 __( 'Neutral', 'formidable' ),
1956 __( 'Likely', 'formidable' ),
1957 __( 'Extremely Likely', 'formidable' ),
1958 __( 'N/A', 'formidable' ),
1959 );
1960 if ( $include_class ) {
1961 $likely['class'] = 'frm-likely-opts';
1962 }
1963
1964 $prepop[ __( 'Likely', 'formidable' ) ] = $likely;
1965
1966 $prepop = apply_filters( 'frm_bulk_field_choices', $prepop );
1967 }
1968
1969 /**
1970 * Display a field value selector
1971 *
1972 * @since 2.03.05
1973 *
1974 * @param int $selector_field_id
1975 * @param array $selector_args
1976 */
1977 public static function display_field_value_selector( $selector_field_id, $selector_args ) {
1978 $field_value_selector = FrmFieldFactory::create_field_value_selector( $selector_field_id, $selector_args );
1979 $field_value_selector->display();
1980 }
1981
1982 /**
1983 * Convert a field object to a flat array
1984 *
1985 * @since 2.03.05
1986 *
1987 * @param object $field
1988 *
1989 * @return array
1990 */
1991 public static function convert_field_object_to_flat_array( $field ) {
1992 $field_options = $field->field_options;
1993 $field_array = get_object_vars( $field );
1994 unset( $field_array['field_options'] );
1995
1996 return $field_array + $field_options;
1997 }
1998
1999 /**
2000 * @since 4.04
2001 *
2002 * @param array $args
2003 * @return void
2004 */
2005 public static function show_add_field_buttons( $args ) {
2006 $field_key = $args['field_key'];
2007 $field_type = $args['field_type'];
2008 $field_label = FrmAppHelper::icon_by_class( FrmFormsHelper::get_field_link_icon( $field_type ), array( 'echo' => false ) );
2009 $field_name = FrmFormsHelper::get_field_link_name( $field_type );
2010 $field_label .= ' <span>' . $field_name . '</span>';
2011
2012 if ( ! empty( $field_type['is_new'] ) ) {
2013 ob_start();
2014 FrmAppHelper::show_pill_text();
2015 $field_label .= ob_get_clean();
2016 }
2017
2018 // If the individual field isn't allowed, disable it.
2019 $run_filter = true;
2020 $single_no_allow = ' ';
2021 $install_data = '';
2022 $requires = '';
2023 $link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
2024 $has_show_upgrade_class = strpos( $field_type['icon'], ' frm_show_upgrade' );
2025 $show_upgrade = $has_show_upgrade_class || false !== strpos( $args['no_allow_class'], 'frm_show_upgrade' );
2026
2027 if ( $has_show_upgrade_class ) {
2028 $single_no_allow .= 'frm_show_upgrade';
2029 $field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
2030 $run_filter = false;
2031 if ( isset( $field_type['addon'] ) ) {
2032 $upgrading = FrmAddonsController::install_link( $field_type['addon'] );
2033 if ( isset( $upgrading['url'] ) ) {
2034 $install_data = json_encode( $upgrading );
2035 }
2036 $requires = FrmFormsHelper::get_plan_required( $upgrading );
2037 } elseif ( isset( $field_type['require'] ) ) {
2038 $requires = $field_type['require'];
2039 }
2040 }
2041
2042 $upgrade_label = '';
2043 $upgrade_message = '';
2044 if ( $show_upgrade ) {
2045 /* translators: %s: Field name */
2046 $upgrade_label = sprintf( esc_html__( '%s fields', 'formidable' ), $field_name );
2047
2048 if ( isset( $field_type['message'] ) ) {
2049 $upgrade_message = FrmAppHelper::kses( $field_type['message'], array( 'a', 'img' ) );
2050 }
2051 }
2052
2053 $li_params = array(
2054 'class' => 'frmbutton frm6 ' . $args['no_allow_class'] . $single_no_allow . ' frm_t' . str_replace( '|', '-', $field_key ),
2055 'id' => $field_key,
2056 'data-upgrade' => $upgrade_label,
2057 'data-link' => $link,
2058 'data-medium' => 'builder',
2059 'data-oneclick' => $install_data,
2060 'data-content' => $field_key,
2061 'data-requires' => $requires,
2062 );
2063
2064 if ( ! empty( $field_type['hide'] ) ) {
2065 $li_params['class'] .= ' frm_hidden';
2066 }
2067
2068 if ( ! empty( $field_type['upsell_image'] ) ) {
2069 $li_params['data-upsell-image'] = $field_type['upsell_image'];
2070 }
2071
2072 if ( $upgrade_message ) {
2073 $li_params['data-message'] = $upgrade_message;
2074 }
2075 ?>
2076 <li <?php FrmAppHelper::array_to_html_params( $li_params, true ); ?>>
2077 <?php
2078 if ( $run_filter ) {
2079 $field_label = apply_filters( 'frmpro_field_links', $field_label, $args['id'], $field_key );
2080 }
2081 echo FrmAppHelper::kses( $field_label, array( 'a', 'i', 'span', 'use', 'svg' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2082 ?>
2083 </li>
2084 <?php
2085 }
2086
2087 /**
2088 * Shows Display format option.
2089 *
2090 * @since 5.0.04
2091 *
2092 * @param array $field Field data.
2093 */
2094 public static function show_radio_display_format( $field ) {
2095 $options = self::get_display_format_options( $field );
2096
2097 $args = self::get_display_format_args( $field, $options );
2098
2099 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/radio-display-format.php';
2100 }
2101
2102 /**
2103 * Creates an array that contains variables used for display format options setting.
2104 *
2105 * @since 6.3.2
2106 *
2107 * @param array $field The field.
2108 *
2109 * @return array
2110 */
2111 public static function get_display_format_options( $field ) {
2112 $options = array(
2113 '0' => array(
2114 'text' => __( 'Simple', 'formidable' ),
2115 'svg' => 'frm_simple_radio',
2116 ),
2117 '1' => array(
2118 'text' => __( 'Images', 'formidable' ),
2119 'svg' => 'frm_image_as_option',
2120 'addon' => 'pro',
2121 'upgrade' => __( 'Image Options', 'formidable' ),
2122 '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" />',
2123 'content' => 'image-options',
2124 ),
2125 'buttons' => array(
2126 'text' => __( 'Buttons', 'formidable' ),
2127 'svg' => 'frm_button_as_option',
2128 'addon' => 'surveys',
2129 'upgrade' => __( 'Button Options', 'formidable' ),
2130 'message' => __( 'Show buttons for radio buttons or check boxes. This is ideal for polls, surveys, segmenting questionnaires and more.', 'formidable' ),
2131 'content' => 'button-options',
2132 ),
2133 );
2134
2135 /**
2136 * Allows modifying the options of Display format setting of Radio field.
2137 *
2138 * @since 5.0.04
2139 *
2140 * @param array $options Options.
2141 * @param array $field
2142 */
2143 $options = apply_filters( 'frm_' . $field['type'] . '_display_format_options', $options, $field );
2144
2145 return $options;
2146 }
2147
2148 /**
2149 * Gets display format arguments to pass to the images_dropdown() method.
2150 *
2151 * @since 5.0.04
2152 *
2153 * @param array $field Field data.
2154 * @param array $options Options array.
2155 * @return array
2156 */
2157 public static function get_display_format_args( $field, $options ) {
2158 $args = array(
2159 'selected' => '0',
2160 'options' => array(),
2161 'name' => 'field_options[image_options_' . $field['id'] . ']',
2162 'input_attrs' => array(
2163 'class' => 'frm_toggle_image_options',
2164 ),
2165 );
2166
2167 self::fill_image_setting_options( $options, $args );
2168
2169 /**
2170 * Allows modifying the arguments of Display format setting of Radio field.
2171 *
2172 * @since 5.0.04
2173 *
2174 * @param array $args Arguments.
2175 * @param array $method_args The arguments from the method. Contains `field`, `options`.
2176 */
2177 return apply_filters( 'frm_' . $field['type'] . '_display_format_args', $args, compact( 'field', 'options' ) );
2178 }
2179
2180 /**
2181 * @since 5.0.04
2182 */
2183 private static function fill_image_setting_options( $options, &$args ) {
2184 foreach ( $options as $key => $option ) {
2185 $args['options'][ $key ] = $option;
2186
2187 if ( ! empty( $option['addon'] ) ) {
2188 $args['options'][ $key ]['custom_attrs'] = self::fill_image_setting_addon_link( $option );
2189 }
2190
2191 unset( $args['options'][ $key ]['addon'] );
2192 $fill = array( 'upgrade', 'message', 'content' );
2193 foreach ( $fill as $f ) {
2194 unset( $args['options'][ $key ][ $f ], $f );
2195 }
2196 }
2197 }
2198
2199 /**
2200 * @since 5.0.04
2201 *
2202 * @return array
2203 */
2204 private static function fill_image_setting_addon_link( $option ) {
2205 $custom_attrs = array(
2206 'class' => 'frm_noallow frm_show_upgrade',
2207 'data-medium' => 'builder',
2208 );
2209
2210 // translators: Add-on name.
2211 $custom_attrs['data-upgrade'] = sprintf( __( 'Formidable %s', 'formidable' ), ucwords( $option['addon'] ) );
2212
2213 $fill = array( 'upgrade', 'message', 'content' );
2214 foreach ( $fill as $f ) {
2215 if ( isset( $option[ $f ] ) ) {
2216 $custom_attrs[ 'data-' . $f ] = $option[ $f ];
2217 }
2218 }
2219
2220 if ( 'pro' === $option['addon'] ) {
2221 return $custom_attrs;
2222 }
2223
2224 $upgrading = FrmAddonsController::install_link( $option['addon'] );
2225 if ( isset( $upgrading['url'] ) ) {
2226 $install_data = wp_json_encode( $upgrading );
2227 } else {
2228 $install_data = '';
2229 }
2230
2231 $custom_attrs['data-oneclick'] = $install_data;
2232 $custom_attrs['data-requires'] = FrmFormsHelper::get_plan_required( $upgrading );
2233
2234 return $custom_attrs;
2235 }
2236
2237 /**
2238 * Maybe adjust a field value based on type.
2239 * Some types require unserializing an array.
2240 * These types are defined by a array_allowed property on their field model class.
2241 *
2242 * @since 6.2
2243 *
2244 * @param mixed $value
2245 * @param string $field_type
2246 * @return void
2247 */
2248 public static function prepare_field_value( &$value, $field_type ) {
2249 $field_object = FrmFieldFactory::get_field_type( $field_type );
2250 $value = $field_object->maybe_decode_value( $value );
2251 }
2252
2253 /**
2254 * @since 6.8
2255 *
2256 * @param int|string $form_id
2257 * @param array $field_ids If this is not empty, the results will be filtered by field id.
2258 * @return array
2259 */
2260 public static function get_draft_field_results( $form_id, $field_ids = array() ) {
2261 if ( FrmAppHelper::pro_is_installed() ) {
2262 $child_form_ids = FrmDb::get_col( 'frm_forms', array( 'parent_form_id' => $form_id ) );
2263 $form_ids = array_merge( array( $form_id ), $child_form_ids );
2264 } else {
2265 $form_ids = array( $form_id );
2266 }
2267
2268 $where = array(
2269 'form_id' => $form_ids,
2270 // Do a soft check for fields that look like drafts only.
2271 'field_options LIKE' => 's:5:"draft";i:1;',
2272 );
2273
2274 if ( $field_ids ) {
2275 $where['id'] = $field_ids;
2276 }
2277
2278 $rows = FrmDb::get_results( 'frm_fields', $where, 'id, field_options' );
2279
2280 return array_filter(
2281 $rows,
2282 function ( $row ) {
2283 FrmAppHelper::unserialize_or_decode( $row->field_options );
2284 return is_array( $row->field_options ) && ! empty( $row->field_options['draft'] );
2285 }
2286 );
2287 }
2288
2289 /**
2290 * This is called when loading the form builder.
2291 * Any unsaved draft fields get added to a hidden draft_fields input on load.
2292 *
2293 * @since 6.8
2294 *
2295 * @param int|string $form_id
2296 * @return array
2297 */
2298 public static function get_all_draft_field_ids( $form_id ) {
2299 $draft_field_rows = self::get_draft_field_results( $form_id );
2300 return wp_list_pluck( $draft_field_rows, 'id' );
2301 }
2302 }
2303