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

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