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

2,359 lines 69.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class 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( __METHOD__, '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 'default-email',
850 'default-from-email',
851 'post[-|_]id',
852 'created[-|_]at',
853 'updated[-|_]at',
854 'updated[-|_]by',
855 'parent[-|_]id',
856 );
857
858 foreach ( $fields as $field ) {
859 $tagregexp[] = $field->id;
860 $tagregexp[] = $field->field_key;
861 }
862
863 $tagregexp = implode( '|', $tagregexp );
864
865 return $tagregexp;
866 }
867
868 public static function replace_content_shortcodes( $content, $entry, $shortcodes ) {
869 foreach ( $shortcodes[0] as $short_key => $tag ) {
870 if ( empty( $tag ) ) {
871 continue;
872 }
873
874 $atts = FrmShortcodeHelper::get_shortcode_attribute_array( $shortcodes[3][ $short_key ] );
875 $tag = FrmShortcodeHelper::get_shortcode_tag( $shortcodes, $short_key );
876
877 $atts['entry'] = $entry;
878 $atts['tag'] = $tag;
879 $replace_with = self::get_value_for_shortcode( $atts );
880
881 if ( $replace_with !== null ) {
882 $replace_with = self::trigger_shortcode_atts( $replace_with, $atts );
883 self::sanitize_embedded_shortcodes( compact( 'entry' ), $replace_with );
884 $content = str_replace( $shortcodes[0][ $short_key ], $replace_with, $content );
885 }
886
887 unset( $atts, $replace_with );
888 }
889
890 return $content;
891 }
892
893 /**
894 * @param string $replace_with
895 * @param array $atts
896 * @return string
897 */
898 private static function trigger_shortcode_atts( $replace_with, $atts ) {
899 $supported_atts = array( 'remove_accents', 'sanitize', 'sanitize_url' );
900 $included_atts = array_intersect( $supported_atts, array_keys( $atts ) );
901 foreach ( $included_atts as $included_att ) {
902 if ( '0' === $atts[ $included_att ] ) {
903 // Skip any option that uses 0 so sanitize_url=0 does not encode.
904 continue;
905 }
906 $function = 'atts_' . $included_att;
907 $replace_with = self::$function( $replace_with, $atts );
908 }
909 return $replace_with;
910 }
911
912 /**
913 * Converts all accent characters to ASCII characters.
914 *
915 * @since 6.3.1
916 *
917 * @param string $replace_with The text to remove accents from.
918 *
919 * @return string
920 */
921 public static function atts_remove_accents( $replace_with ) {
922 return remove_accents( $replace_with );
923 }
924
925 /**
926 * @param string $replace_with
927 * @return string
928 */
929 private static function atts_sanitize( $replace_with ) {
930 return sanitize_title_with_dashes( $replace_with );
931 }
932
933 /**
934 * @param string $replace_with
935 * @return string
936 */
937 private static function atts_sanitize_url( $replace_with ) {
938 return urlencode( $replace_with );
939 }
940
941 /**
942 * Prevent shortcodes in fields from being processed
943 *
944 * @since 3.01.02
945 *
946 * @param array $atts Includes entry object.
947 * @param string $value
948 */
949 public static function sanitize_embedded_shortcodes( $atts, &$value ) {
950 $atts['value'] = $value;
951 $should_sanitize = apply_filters( 'frm_sanitize_shortcodes', true, $atts );
952 if ( $should_sanitize ) {
953 $value = str_replace( '[', '&#91;', $value );
954 }
955 }
956
957 /**
958 * @since 3.0
959 *
960 * @param array $atts
961 *
962 * @return string
963 */
964 private static function get_value_for_shortcode( $atts ) {
965 $clean_tag = str_replace( '-', '_', $atts['tag'] );
966
967 $shortcode_values = array(
968 'id' => $atts['entry']->id,
969 'key' => $atts['entry']->item_key,
970 'ip' => $atts['entry']->ip,
971 );
972
973 $dynamic_default = array( 'admin_email', 'siteurl', 'frmurl', 'sitename', 'get', 'default-email', 'default-from-email' );
974
975 if ( isset( $shortcode_values[ $atts['tag'] ] ) ) {
976 $replace_with = $shortcode_values[ $atts['tag'] ];
977 } elseif ( in_array( $atts['tag'], $dynamic_default, true ) ) {
978 $replace_with = self::dynamic_default_values( $atts['tag'], $atts );
979 } elseif ( $clean_tag === 'user_agent' ) {
980 $description = $atts['entry']->description;
981 $replace_with = FrmEntriesHelper::get_browser( $description['browser'] );
982 } elseif ( $clean_tag === 'created_at' || $clean_tag === 'updated_at' ) {
983 $atts['tag'] = $clean_tag;
984 $replace_with = self::get_entry_timestamp( $atts );
985 } elseif ( $clean_tag === 'created_by' || $clean_tag === 'updated_by' ) {
986 $replace_with = self::get_display_value( $atts['entry']->{$clean_tag}, (object) array( 'type' => 'user_id' ), $atts );
987 } else {
988 $replace_with = self::get_field_shortcode_value( $atts );
989 }
990
991 return $replace_with;
992 }
993
994 /**
995 * @since 3.0
996 *
997 * @param array $atts
998 *
999 * @return string
1000 */
1001 private static function get_entry_timestamp( $atts ) {
1002 if ( isset( $atts['format'] ) ) {
1003 $time_format = ' ';
1004 } else {
1005 $atts['format'] = get_option( 'date_format' );
1006 $time_format = '';
1007 }
1008
1009 return FrmAppHelper::get_formatted_time( $atts['entry']->{$atts['tag']}, $atts['format'], $time_format );
1010 }
1011
1012 /**
1013 * @since 3.0
1014 *
1015 * @param array $atts
1016 *
1017 * @return string|null
1018 */
1019 private static function get_field_shortcode_value( $atts ) {
1020 $field = FrmField::getOne( $atts['tag'] );
1021 if ( empty( $field ) ) {
1022 return null;
1023 }
1024
1025 if ( isset( $atts['show'] ) && $atts['show'] === 'field_label' ) {
1026 $replace_with = $field->name;
1027 } elseif ( isset( $atts['show'] ) && $atts['show'] === 'description' ) {
1028 $replace_with = $field->description;
1029 } else {
1030 $replace_with = FrmEntryMeta::get_meta_value( $atts['entry'], $field->id );
1031 $string_value = $replace_with;
1032 if ( is_array( $replace_with ) ) {
1033 $sep = isset( $atts['sep'] ) ? $atts['sep'] : ', ';
1034 $string_value = implode( $sep, $replace_with );
1035 }
1036
1037 if ( empty( $string_value ) && $string_value != '0' ) {
1038 $replace_with = '';
1039 } else {
1040 $atts['entry_id'] = $atts['entry']->id;
1041 $atts['entry_key'] = $atts['entry']->item_key;
1042 $replace_with = self::get_display_value( $replace_with, $field, $atts );
1043 }
1044 }
1045
1046 return $replace_with;
1047 }
1048
1049 /**
1050 * Get the value to replace a few standard shortcodes
1051 *
1052 * @since 2.0
1053 * @return string
1054 */
1055 public static function dynamic_default_values( $tag, $atts = array(), $return_array = false ) {
1056 $new_value = '';
1057 switch ( $tag ) {
1058 case 'admin_email':
1059 $new_value = get_option( 'admin_email' );
1060 break;
1061 case 'default-email':
1062 $frm_settings = FrmAppHelper::get_settings();
1063 $new_value = ! empty( $frm_settings->default_email ) && is_email( $frm_settings->default_email ) ? $frm_settings->default_email : get_option( 'admin_email' );
1064 break;
1065 case 'default-from-email':
1066 $frm_settings = FrmAppHelper::get_settings();
1067 $new_value = ! empty( $frm_settings->from_email ) && is_email( $frm_settings->from_email ) ? $frm_settings->from_email : get_option( 'admin_email' );
1068 break;
1069 case 'siteurl':
1070 $new_value = FrmAppHelper::site_url();
1071 break;
1072 case 'frmurl':
1073 $new_value = FrmAppHelper::plugin_url();
1074 break;
1075 case 'sitename':
1076 $new_value = FrmAppHelper::site_name();
1077 break;
1078 case 'get':
1079 $new_value = self::process_get_shortcode( $atts, $return_array );
1080 }//end switch
1081
1082 return $new_value;
1083 }
1084
1085 /**
1086 * Process the [get] shortcode
1087 *
1088 * @since 2.0
1089 * @return array|string
1090 */
1091 public static function process_get_shortcode( $atts, $return_array = false ) {
1092 if ( ! isset( $atts['param'] ) ) {
1093 return '';
1094 }
1095
1096 if ( strpos( $atts['param'], '&#91;' ) ) {
1097 $atts['param'] = str_replace( '&#91;', '[', $atts['param'] );
1098 $atts['param'] = str_replace( '&#93;', ']', $atts['param'] );
1099 }
1100
1101 $new_value = FrmAppHelper::get_param( $atts['param'], '', 'get', 'sanitize_text_field' );
1102 $new_value = FrmAppHelper::get_query_var( $new_value, $atts['param'] );
1103
1104 if ( $new_value == '' ) {
1105 if ( ! isset( $atts['prev_val'] ) ) {
1106 $atts['prev_val'] = '';
1107 }
1108
1109 $new_value = isset( $atts['default'] ) ? $atts['default'] : $atts['prev_val'];
1110 }
1111
1112 if ( is_array( $new_value ) && ! $return_array ) {
1113 $new_value = implode( ', ', $new_value );
1114 }
1115
1116 return $new_value;
1117 }
1118
1119 public static function get_display_value( $value, $field, $atts = array() ) {
1120
1121 $value = apply_filters( 'frm_get_' . $field->type . '_display_value', $value, $field, $atts );
1122 $value = apply_filters( 'frm_get_display_value', $value, $field, $atts );
1123
1124 $value = self::get_unfiltered_display_value( compact( 'value', 'field', 'atts' ) );
1125
1126 return apply_filters( 'frm_display_value', $value, $field, $atts );
1127 }
1128
1129 /**
1130 * @param array $atts Includes value, field, and atts.
1131 */
1132 public static function get_unfiltered_display_value( $atts ) {
1133 $value = $atts['value'];
1134 $field = $atts['field'];
1135 $atts = isset( $atts['atts'] ) ? $atts['atts'] : $atts;
1136
1137 if ( is_array( $field ) ) {
1138 $field = $field['id'];
1139 }
1140
1141 $field_obj = FrmFieldFactory::get_field_object( $field );
1142
1143 return $field_obj->get_display_value( $value, $atts );
1144 }
1145
1146 /**
1147 * Get a value from the user profile from the user ID
1148 *
1149 * @since 3.0
1150 *
1151 * @return string
1152 */
1153 public static function get_user_display_name( $user_id, $user_info = 'display_name', $args = array() ) {
1154 $defaults = array(
1155 'blank' => false,
1156 'link' => false,
1157 'size' => 96,
1158 );
1159
1160 $args = wp_parse_args( $args, $defaults );
1161
1162 $user = get_userdata( $user_id );
1163 $info = '';
1164
1165 if ( $user ) {
1166 if ( $user_info === 'avatar' ) {
1167 $info = get_avatar( $user_id, $args['size'] );
1168 } elseif ( $user_info === 'author_link' ) {
1169 $info = get_author_posts_url( $user_id );
1170 } else {
1171 $info = isset( $user->$user_info ) ? $user->$user_info : '';
1172 }
1173
1174 if ( 'display_name' === $user_info && empty( $info ) && ! $args['blank'] ) {
1175 $info = $user->user_login;
1176 }
1177 }
1178
1179 if ( $args['link'] ) {
1180 $info = '<a href="' . esc_url( admin_url( 'user-edit.php?user_id=' . $user_id ) ) . '">' . $info . '</a>';
1181 }
1182
1183 return $info;
1184 }
1185
1186 /**
1187 * @param string $type
1188 * @return array
1189 */
1190 public static function get_field_types( $type ) {
1191 $single_input = self::single_input_fields();
1192 $multiple_input = array( 'radio', 'checkbox', 'select', 'scale', 'star', 'lookup' );
1193 $field_selection = FrmField::all_field_selection();
1194 $field_types = array();
1195
1196 if ( in_array( $type, $single_input, true ) ) {
1197 self::field_types_for_input( $single_input, $field_selection, $field_types );
1198 } elseif ( in_array( $type, $multiple_input, true ) ) {
1199 self::field_types_for_input( $multiple_input, $field_selection, $field_types );
1200 } elseif ( isset( $field_selection[ $type ] ) ) {
1201 $field_types[ $type ] = $field_selection[ $type ];
1202 }
1203
1204 $field_types = apply_filters( 'frm_switch_field_types', $field_types, compact( 'type', 'field_selection' ) );
1205
1206 return $field_types;
1207 }
1208
1209 /**
1210 * Get a list of all fields that use a single value input.
1211 *
1212 * @since 4.0
1213 */
1214 public static function single_input_fields() {
1215 $fields = array(
1216 'text',
1217 'textarea',
1218 'rte',
1219 'number',
1220 'email',
1221 'url',
1222 'date',
1223 'phone',
1224 'hidden',
1225 'time',
1226 'tag',
1227 'password',
1228 );
1229 return apply_filters( 'frm_single_input_fields', $fields );
1230 }
1231
1232 /**
1233 * @param string[] $inputs
1234 * @param array $fields
1235 * @param array $field_types
1236 * @return void
1237 */
1238 private static function field_types_for_input( $inputs, $fields, &$field_types ) {
1239 foreach ( $inputs as $input ) {
1240 // This may not be set if a field type was removed using the frm_available_fields or frm_pro_available_fields filters.
1241 if ( array_key_exists( $input, $fields ) ) {
1242 $field_types[ $input ] = $fields[ $input ];
1243 }
1244 unset( $input );
1245 }
1246 }
1247
1248 /**
1249 * Check if current field option is an "other" option
1250 *
1251 * @since 2.0.6
1252 *
1253 * @param string $opt_key
1254 *
1255 * @return bool Returns true if current field option is an "Other" option
1256 */
1257 public static function is_other_opt( $opt_key ) {
1258 return $opt_key && strpos( $opt_key, 'other_' ) === 0;
1259 }
1260
1261 /**
1262 * Get value that belongs in "Other" text box
1263 *
1264 * @since 2.0.6
1265 *
1266 * @param array $args
1267 */
1268 public static function get_other_val( $args ) {
1269 $defaults = array(
1270 'opt_key' => 0,
1271 'field' => array(),
1272 'parent' => false,
1273 'pointer' => false,
1274 );
1275 $args = wp_parse_args( $args, $defaults );
1276
1277 $opt_key = $args['opt_key'];
1278 $field = $args['field'];
1279 $parent = $args['parent'];
1280 $pointer = $args['pointer'];
1281 $other_val = '';
1282
1283 // If option is an "other" option and there is a value set for this field,
1284 // check if the value belongs in the current "Other" option text field
1285 if ( ! self::is_other_opt( $opt_key ) || ! FrmField::is_option_true( $field, 'value' ) ) {
1286 return $other_val;
1287 }
1288
1289 // Check posted vals before checking saved values
1290 // For fields inside repeating sections - note, don't check if $pointer is true because it will often be zero
1291 if ( $parent && isset( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1292 if ( FrmField::is_field_with_multiple_values( $field ) ) {
1293 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1294 $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 ] ) ) : '';
1295 } else {
1296 $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1297 }
1298
1299 return $other_val;
1300 }
1301
1302 if ( isset( $field['id'] ) && isset( $_POST['item_meta']['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1303 // For normal fields
1304
1305 if ( FrmField::is_field_with_multiple_values( $field ) ) {
1306 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1307 $other_val = isset( $_POST['item_meta']['other'][ $field['id'] ][ $opt_key ] ) ? sanitize_text_field( wp_unslash( $_POST['item_meta']['other'][ $field['id'] ][ $opt_key ] ) ) : '';
1308 } else {
1309 $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta']['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1310 }
1311
1312 return $other_val;
1313 }//end if
1314
1315 // For checkboxes
1316 if ( $field['type'] === 'checkbox' && is_array( $field['value'] ) ) {
1317 // Check if there is an "other" val in saved value and make sure the
1318 // "other" val is not equal to the Other checkbox option
1319 if ( isset( $field['value'][ $opt_key ] ) && $field['options'][ $opt_key ] != $field['value'][ $opt_key ] ) {
1320 $other_val = $field['value'][ $opt_key ];
1321 }
1322 } else {
1323 /**
1324 * For radio buttons and dropdowns
1325 * Check if saved value equals any of the options. If not, set it as the other value.
1326 */
1327 foreach ( $field['options'] as $opt_key => $opt_val ) {
1328 $temp_val = is_array( $opt_val ) ? $opt_val['value'] : $opt_val;
1329 // Multi-select dropdowns - key is not preserved
1330 if ( is_array( $field['value'] ) ) {
1331 $o_key = array_search( $temp_val, $field['value'] );
1332 if ( isset( $field['value'][ $o_key ] ) ) {
1333 unset( $field['value'][ $o_key ], $o_key );
1334 }
1335 } elseif ( $temp_val == $field['value'] ) {
1336 // For radio and regular dropdowns
1337 return '';
1338 } else {
1339 $other_val = $field['value'];
1340 }
1341 unset( $opt_key, $opt_val, $temp_val );
1342 }
1343 // For multi-select dropdowns only
1344 if ( is_array( $field['value'] ) && ! empty( $field['value'] ) ) {
1345 $other_val = reset( $field['value'] );
1346 }
1347 }//end if
1348
1349 return $other_val;
1350 }
1351
1352 /**
1353 * Check if there is a saved value for the "Other" text field. If so, set it as the $other_val.
1354 * Intended for front-end use
1355 *
1356 * @since 2.0.6
1357 *
1358 * @param array $args Should include field, opt_key and field name.
1359 * @param bool $other_opt
1360 * @param string $checked
1361 *
1362 * @return array $other_args
1363 */
1364 public static function prepare_other_input( $args, &$other_opt, &$checked ) {
1365 $other_args = array(
1366 'name' => '',
1367 'value' => '',
1368 );
1369
1370 // Check if this is an "Other" option.
1371 if ( ! self::is_other_opt( $args['opt_key'] ) ) {
1372 return $other_args;
1373 }
1374
1375 $other_opt = true;
1376
1377 self::set_other_name( $args, $other_args );
1378 self::set_other_value( $args, $other_args );
1379
1380 if ( '' !== $other_args['value'] ) {
1381 $checked = 'checked="checked" ';
1382 }
1383
1384 // If 'other' is selected as one of the default values for a checkbox field, 'checked' attribute should be on.
1385 if ( ! $checked &&
1386 $args['field']['type'] === 'checkbox' &&
1387 is_array( $args['field']['value'] ) &&
1388 isset( $args['field_val'] ) &&
1389 in_array( $args['field_val'], $args['field']['value'], true )
1390 ) {
1391 $checked = 'checked="checked" ';
1392 }
1393
1394 return $other_args;
1395 }
1396
1397 /**
1398 * @since 2.0.6
1399 * @param array $args
1400 * @param array $other_args
1401 */
1402 private static function set_other_name( $args, &$other_args ) {
1403 // Set up name for other field
1404 $other_args['name'] = str_replace( '[]', '', $args['field_name'] );
1405 $other_args['name'] = preg_replace( '/\[' . $args['field']['id'] . '\]$/', '', $other_args['name'] );
1406 $other_args['name'] = $other_args['name'] . '[other][' . $args['field']['id'] . ']';
1407
1408 // Converts item_meta[field_id] => item_meta[other][field_id] and
1409 // item_meta[parent][0][field_id] => item_meta[parent][0][other][field_id]
1410 if ( FrmField::is_field_with_multiple_values( $args['field'] ) ) {
1411 $other_args['name'] .= '[' . $args['opt_key'] . ']';
1412 }
1413 }
1414
1415 /**
1416 * Find the parent and pointer, and get text for "other" text field
1417 *
1418 * @since 2.0.6
1419 * @param array $args
1420 * @param array $other_args
1421 */
1422 private static function set_other_value( $args, &$other_args ) {
1423 $parent = '';
1424 $pointer = '';
1425
1426 // Check for parent ID and pointer
1427 $temp_array = explode( '[', $args['field_name'] );
1428
1429 // Count should only be greater than 3 if inside of a repeating section
1430 if ( count( $temp_array ) > 3 ) {
1431 $parent = str_replace( ']', '', $temp_array[1] );
1432 $pointer = str_replace( ']', '', $temp_array[2] );
1433 }
1434
1435 // Get text for "other" text field
1436 $other_args['value'] = self::get_other_val(
1437 array(
1438 'opt_key' => $args['opt_key'],
1439 'field' => $args['field'],
1440 'parent' => $parent,
1441 'pointer' => $pointer,
1442 )
1443 );
1444 }
1445
1446 /**
1447 * If this field includes an other option, show it
1448 *
1449 * @since 2.0.6
1450 * @param array $args
1451 */
1452 public static function include_other_input( $args ) {
1453 if ( ! $args['other_opt'] ) {
1454 return;
1455 }
1456
1457 $classes = array( 'frm_other_input' );
1458 if ( ! $args['checked'] || trim( $args['checked'] ) == '' ) {
1459 // hide the field if the other option is not selected
1460 $classes[] = 'frm_pos_none';
1461 }
1462 if ( $args['field']['type'] === 'select' && $args['field']['multiple'] ) {
1463 $classes[] = 'frm_other_full';
1464 }
1465
1466 // Set up HTML ID for Other field
1467 $other_id = self::get_other_field_html_id( $args['field']['type'], $args['html_id'], $args['opt_key'] );
1468
1469 $label = isset( $args['opt_label'] ) ? $args['opt_label'] : $args['field']['name'];
1470
1471 echo '<label for="' . esc_attr( $other_id ) . '" class="frm_screen_reader frm_hidden">' .
1472 esc_html( $label ) .
1473 '</label>' .
1474 '<input type="text" id="' . esc_attr( $other_id ) . '" class="' . esc_attr( implode( ' ', $classes ) ) . '" ' .
1475 ( $args['read_only'] ? ' readonly="readonly" disabled="disabled"' : '' ) .
1476 ' name="' . esc_attr( $args['name'] ) . '" value="' . esc_attr( $args['value'] ) . '" />';
1477 }
1478
1479 /**
1480 * Get the HTML id for an "Other" text field
1481 * Note: This does not affect fields in repeating sections
1482 *
1483 * @since 2.0.08
1484 *
1485 * @param string $type Field type.
1486 * @param string $html_id
1487 * @param bool|string $opt_key
1488 *
1489 * @return string $other_id
1490 */
1491 public static function get_other_field_html_id( $type, $html_id, $opt_key = false ) {
1492 $other_id = $html_id;
1493
1494 // If hidden radio field, add an opt key of 0
1495 if ( $type === 'radio' && $opt_key === false ) {
1496 $opt_key = 0;
1497 }
1498
1499 if ( $opt_key !== false ) {
1500 $other_id .= '-' . $opt_key;
1501 }
1502
1503 $other_id .= '-otext';
1504
1505 return $other_id;
1506 }
1507
1508 public static function switch_field_ids( $val ) {
1509 global $frm_duplicate_ids;
1510 $replace = array();
1511 $replace_with = array();
1512 foreach ( (array) $frm_duplicate_ids as $old => $new ) {
1513 $replace[] = '[if ' . $old . ']';
1514 $replace_with[] = '[if ' . $new . ']';
1515 $replace[] = '[if ' . $old . ' ';
1516 $replace_with[] = '[if ' . $new . ' ';
1517 $replace[] = '[/if ' . $old . ']';
1518 $replace_with[] = '[/if ' . $new . ']';
1519 $replace[] = '[\/if ' . $old . ']';
1520 $replace_with[] = '[\/if ' . $new . ']';
1521 $replace[] = '[foreach ' . $old . ']';
1522 $replace_with[] = '[foreach ' . $new . ']';
1523 $replace[] = '[/foreach ' . $old . ']';
1524 $replace_with[] = '[/foreach ' . $new . ']';
1525 $replace[] = '[\/foreach ' . $old . ']';
1526 $replace_with[] = '[\/foreach ' . $new . ']';
1527 $replace[] = '[' . $old . ']';
1528 $replace_with[] = '[' . $new . ']';
1529 $replace[] = '[' . $old . ' ';
1530 $replace_with[] = '[' . $new . ' ';
1531 $replace[] = 'field_id="' . $old . '"';
1532 $replace_with[] = 'field_id="' . $new . '"';
1533 $replace[] = 'field_id=\"' . $old . '\"';
1534 $replace_with[] = 'field_id=\"' . $new . '\"';
1535 unset( $old, $new );
1536 }//end foreach
1537 if ( is_array( $val ) ) {
1538 foreach ( $val as $k => $v ) {
1539 if ( is_string( $v ) ) {
1540 if ( 'custom_html' === $k ) {
1541 $val[ $k ] = self::switch_ids_except_strings( $replace, $replace_with, array( '[if description]', '[description]', '[/if description]' ), $v );
1542 unset( $k, $v );
1543 continue;
1544 }
1545 $val[ $k ] = str_replace( $replace, $replace_with, $v );
1546 unset( $k, $v );
1547 }
1548 }
1549 } else {
1550 $val = str_replace( $replace, $replace_with, $val );
1551 }
1552
1553 return $val;
1554 }
1555
1556 /**
1557 * Removes exception strings from replacement arrays and replaces the rest in the provided value string.
1558 *
1559 * @since 6.14
1560 *
1561 * @param array $replace Values to be replaced.
1562 * @param array $replace_with Replacement values.
1563 * @param array $exceptions Array of strings to skip.
1564 * @param string $value Value to be updated.
1565 *
1566 * @return string
1567 */
1568 private static function switch_ids_except_strings( $replace, $replace_with, $exceptions, $value ) {
1569 foreach ( $exceptions as $exception ) {
1570 $index = array_search( $exception, $replace, true );
1571 if ( false === $index ) {
1572 continue;
1573 }
1574 unset( $replace[ $index ] );
1575 unset( $replace_with[ $index ] );
1576 }
1577 $value = str_replace( $replace, $replace_with, $value );
1578 return $value;
1579 }
1580
1581 /**
1582 * @since 4.0
1583 */
1584 public static function bulk_options_overlay() {
1585 $prepop = array();
1586 self::get_bulk_prefilled_opts( $prepop, true );
1587
1588 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/bulk-options-overlay.php';
1589 }
1590
1591 public static function get_us_states() {
1592 $states = array(
1593 'AL' => 'Alabama',
1594 'AK' => 'Alaska',
1595 'AR' => 'Arkansas',
1596 'AZ' => 'Arizona',
1597 'CA' => 'California',
1598 'CO' => 'Colorado',
1599 'CT' => 'Connecticut',
1600 'DE' => 'Delaware',
1601 'DC' => 'District of Columbia',
1602 'FL' => 'Florida',
1603 'GA' => 'Georgia',
1604 'HI' => 'Hawaii',
1605 'ID' => 'Idaho',
1606 'IL' => 'Illinois',
1607 'IN' => 'Indiana',
1608 'IA' => 'Iowa',
1609 'KS' => 'Kansas',
1610 'KY' => 'Kentucky',
1611 'LA' => 'Louisiana',
1612 'ME' => 'Maine',
1613 'MD' => 'Maryland',
1614 'MA' => 'Massachusetts',
1615 'MI' => 'Michigan',
1616 'MN' => 'Minnesota',
1617 'MS' => 'Mississippi',
1618 'MO' => 'Missouri',
1619 'MT' => 'Montana',
1620 'NE' => 'Nebraska',
1621 'NV' => 'Nevada',
1622 'NH' => 'New Hampshire',
1623 'NJ' => 'New Jersey',
1624 'NM' => 'New Mexico',
1625 'NY' => 'New York',
1626 'NC' => 'North Carolina',
1627 'ND' => 'North Dakota',
1628 'OH' => 'Ohio',
1629 'OK' => 'Oklahoma',
1630 'OR' => 'Oregon',
1631 'PA' => 'Pennsylvania',
1632 'RI' => 'Rhode Island',
1633 'SC' => 'South Carolina',
1634 'SD' => 'South Dakota',
1635 'TN' => 'Tennessee',
1636 'TX' => 'Texas',
1637 'UT' => 'Utah',
1638 'VT' => 'Vermont',
1639 'VA' => 'Virginia',
1640 'WA' => 'Washington',
1641 'WV' => 'West Virginia',
1642 'WI' => 'Wisconsin',
1643 'WY' => 'Wyoming',
1644 );
1645
1646 return apply_filters( 'frm_us_states', $states );
1647 }
1648
1649 public static function get_countries() {
1650 $countries = array(
1651 __( 'Afghanistan', 'formidable' ),
1652 __( 'Aland Islands', 'formidable' ),
1653 __( 'Albania', 'formidable' ),
1654 __( 'Algeria', 'formidable' ),
1655 __( 'American Samoa', 'formidable' ),
1656 __( 'Andorra', 'formidable' ),
1657 __( 'Angola', 'formidable' ),
1658 __( 'Anguilla', 'formidable' ),
1659 __( 'Antarctica', 'formidable' ),
1660 __( 'Antigua and Barbuda', 'formidable' ),
1661 __( 'Argentina', 'formidable' ),
1662 __( 'Armenia', 'formidable' ),
1663 __( 'Aruba', 'formidable' ),
1664 __( 'Australia', 'formidable' ),
1665 __( 'Austria', 'formidable' ),
1666 __( 'Azerbaijan', 'formidable' ),
1667 __( 'Bahamas', 'formidable' ),
1668 __( 'Bahrain', 'formidable' ),
1669 __( 'Bangladesh', 'formidable' ),
1670 __( 'Barbados', 'formidable' ),
1671 __( 'Belarus', 'formidable' ),
1672 __( 'Belgium', 'formidable' ),
1673 __( 'Belize', 'formidable' ),
1674 __( 'Benin', 'formidable' ),
1675 __( 'Bermuda', 'formidable' ),
1676 __( 'Bhutan', 'formidable' ),
1677 __( 'Bolivia', 'formidable' ),
1678 __( 'Bonaire, Sint Eustatius and Saba', 'formidable' ),
1679 __( 'Bosnia and Herzegovina', 'formidable' ),
1680 __( 'Botswana', 'formidable' ),
1681 __( 'Bouvet Island', 'formidable' ),
1682 __( 'Brazil', 'formidable' ),
1683 __( 'British Indian Ocean Territory', 'formidable' ),
1684 __( 'Brunei', 'formidable' ),
1685 __( 'Bulgaria', 'formidable' ),
1686 __( 'Burkina Faso', 'formidable' ),
1687 __( 'Burundi', 'formidable' ),
1688 __( 'Cambodia', 'formidable' ),
1689 __( 'Cameroon', 'formidable' ),
1690 __( 'Canada', 'formidable' ),
1691 __( 'Cape Verde', 'formidable' ),
1692 __( 'Cayman Islands', 'formidable' ),
1693 __( 'Central African Republic', 'formidable' ),
1694 __( 'Chad', 'formidable' ),
1695 __( 'Chile', 'formidable' ),
1696 __( 'China', 'formidable' ),
1697 __( 'Christmas Island', 'formidable' ),
1698 __( 'Cocos (Keeling) Islands', 'formidable' ),
1699 __( 'Colombia', 'formidable' ),
1700 __( 'Comoros', 'formidable' ),
1701 __( 'Congo', 'formidable' ),
1702 __( 'Cook Islands', 'formidable' ),
1703 __( 'Costa Rica', 'formidable' ),
1704 __( 'C&ocirc;te d\'Ivoire', 'formidable' ),
1705 __( 'Croatia', 'formidable' ),
1706 __( 'Cuba', 'formidable' ),
1707 __( 'Curacao', 'formidable' ),
1708 __( 'Cyprus', 'formidable' ),
1709 __( 'Czech Republic', 'formidable' ),
1710 __( 'Denmark', 'formidable' ),
1711 __( 'Djibouti', 'formidable' ),
1712 __( 'Dominica', 'formidable' ),
1713 __( 'Dominican Republic', 'formidable' ),
1714 __( 'East Timor', 'formidable' ),
1715 __( 'Ecuador', 'formidable' ),
1716 __( 'Egypt', 'formidable' ),
1717 __( 'El Salvador', 'formidable' ),
1718 __( 'Equatorial Guinea', 'formidable' ),
1719 __( 'Eritrea', 'formidable' ),
1720 __( 'Estonia', 'formidable' ),
1721 __( 'Ethiopia', 'formidable' ),
1722 __( 'Falkland Islands (Malvinas)', 'formidable' ),
1723 __( 'Faroe Islands', 'formidable' ),
1724 __( 'Fiji', 'formidable' ),
1725 __( 'Finland', 'formidable' ),
1726 __( 'France', 'formidable' ),
1727 __( 'French Guiana', 'formidable' ),
1728 __( 'French Polynesia', 'formidable' ),
1729 __( 'French Southern Territories', 'formidable' ),
1730 __( 'Gabon', 'formidable' ),
1731 __( 'Gambia', 'formidable' ),
1732 __( 'Georgia', 'formidable' ),
1733 __( 'Germany', 'formidable' ),
1734 __( 'Ghana', 'formidable' ),
1735 __( 'Gibraltar', 'formidable' ),
1736 __( 'Greece', 'formidable' ),
1737 __( 'Greenland', 'formidable' ),
1738 __( 'Grenada', 'formidable' ),
1739 __( 'Guadeloupe', 'formidable' ),
1740 __( 'Guam', 'formidable' ),
1741 __( 'Guatemala', 'formidable' ),
1742 __( 'Guernsey', 'formidable' ),
1743 __( 'Guinea', 'formidable' ),
1744 __( 'Guinea-Bissau', 'formidable' ),
1745 __( 'Guyana', 'formidable' ),
1746 __( 'Haiti', 'formidable' ),
1747 __( 'Heard Island and McDonald Islands', 'formidable' ),
1748 __( 'Holy See', 'formidable' ),
1749 __( 'Honduras', 'formidable' ),
1750 __( 'Hong Kong', 'formidable' ),
1751 __( 'Hungary', 'formidable' ),
1752 __( 'Iceland', 'formidable' ),
1753 __( 'India', 'formidable' ),
1754 __( 'Indonesia', 'formidable' ),
1755 __( 'Iran', 'formidable' ),
1756 __( 'Iraq', 'formidable' ),
1757 __( 'Ireland', 'formidable' ),
1758 __( 'Israel', 'formidable' ),
1759 __( 'Isle of Man', 'formidable' ),
1760 __( 'Italy', 'formidable' ),
1761 __( 'Jamaica', 'formidable' ),
1762 __( 'Japan', 'formidable' ),
1763 __( 'Jersey', 'formidable' ),
1764 __( 'Jordan', 'formidable' ),
1765 __( 'Kazakhstan', 'formidable' ),
1766 __( 'Kenya', 'formidable' ),
1767 __( 'Kiribati', 'formidable' ),
1768 __( 'North Korea', 'formidable' ),
1769 __( 'South Korea', 'formidable' ),
1770 __( 'Kosovo', 'formidable' ),
1771 __( 'Kuwait', 'formidable' ),
1772 __( 'Kyrgyzstan', 'formidable' ),
1773 __( 'Laos', 'formidable' ),
1774 __( 'Latvia', 'formidable' ),
1775 __( 'Lebanon', 'formidable' ),
1776 __( 'Lesotho', 'formidable' ),
1777 __( 'Liberia', 'formidable' ),
1778 __( 'Libya', 'formidable' ),
1779 __( 'Liechtenstein', 'formidable' ),
1780 __( 'Lithuania', 'formidable' ),
1781 __( 'Luxembourg', 'formidable' ),
1782 __( 'Macao', 'formidable' ),
1783 __( 'Macedonia', 'formidable' ),
1784 __( 'Madagascar', 'formidable' ),
1785 __( 'Malawi', 'formidable' ),
1786 __( 'Malaysia', 'formidable' ),
1787 __( 'Maldives', 'formidable' ),
1788 __( 'Mali', 'formidable' ),
1789 __( 'Malta', 'formidable' ),
1790 __( 'Marshall Islands', 'formidable' ),
1791 __( 'Martinique', 'formidable' ),
1792 __( 'Mauritania', 'formidable' ),
1793 __( 'Mauritius', 'formidable' ),
1794 __( 'Mayotte', 'formidable' ),
1795 __( 'Mexico', 'formidable' ),
1796 __( 'Micronesia', 'formidable' ),
1797 __( 'Moldova', 'formidable' ),
1798 __( 'Monaco', 'formidable' ),
1799 __( 'Mongolia', 'formidable' ),
1800 __( 'Montenegro', 'formidable' ),
1801 __( 'Montserrat', 'formidable' ),
1802 __( 'Morocco', 'formidable' ),
1803 __( 'Mozambique', 'formidable' ),
1804 __( 'Myanmar', 'formidable' ),
1805 __( 'Namibia', 'formidable' ),
1806 __( 'Nauru', 'formidable' ),
1807 __( 'Nepal', 'formidable' ),
1808 __( 'Netherlands', 'formidable' ),
1809 __( 'New Caledonia', 'formidable' ),
1810 __( 'New Zealand', 'formidable' ),
1811 __( 'Nicaragua', 'formidable' ),
1812 __( 'Niger', 'formidable' ),
1813 __( 'Nigeria', 'formidable' ),
1814 __( 'Niue', 'formidable' ),
1815 __( 'Norfolk Island', 'formidable' ),
1816 __( 'Northern Mariana Islands', 'formidable' ),
1817 __( 'Norway', 'formidable' ),
1818 __( 'Oman', 'formidable' ),
1819 __( 'Pakistan', 'formidable' ),
1820 __( 'Palau', 'formidable' ),
1821 __( 'Palestine', 'formidable' ),
1822 __( 'Panama', 'formidable' ),
1823 __( 'Papua New Guinea', 'formidable' ),
1824 __( 'Paraguay', 'formidable' ),
1825 __( 'Peru', 'formidable' ),
1826 __( 'Philippines', 'formidable' ),
1827 __( 'Pitcairn', 'formidable' ),
1828 __( 'Poland', 'formidable' ),
1829 __( 'Portugal', 'formidable' ),
1830 __( 'Puerto Rico', 'formidable' ),
1831 __( 'Qatar', 'formidable' ),
1832 __( 'Reunion', 'formidable' ),
1833 __( 'Romania', 'formidable' ),
1834 __( 'Russia', 'formidable' ),
1835 __( 'Rwanda', 'formidable' ),
1836 __( 'Saint Barthelemy', 'formidable' ),
1837 __( 'Saint Helena, Ascension and Tristan da Cunha', 'formidable' ),
1838 __( 'Saint Kitts and Nevis', 'formidable' ),
1839 __( 'Saint Lucia', 'formidable' ),
1840 __( 'Saint Martin (French part)', 'formidable' ),
1841 __( 'Saint Pierre and Miquelon', 'formidable' ),
1842 __( 'Saint Vincent and the Grenadines', 'formidable' ),
1843 __( 'Samoa', 'formidable' ),
1844 __( 'San Marino', 'formidable' ),
1845 __( 'Sao Tome and Principe', 'formidable' ),
1846 __( 'Saudi Arabia', 'formidable' ),
1847 __( 'Senegal', 'formidable' ),
1848 __( 'Serbia', 'formidable' ),
1849 __( 'Seychelles', 'formidable' ),
1850 __( 'Sierra Leone', 'formidable' ),
1851 __( 'Singapore', 'formidable' ),
1852 __( 'Sint Maarten (Dutch part)', 'formidable' ),
1853 __( 'Slovakia', 'formidable' ),
1854 __( 'Slovenia', 'formidable' ),
1855 __( 'Solomon Islands', 'formidable' ),
1856 __( 'Somalia', 'formidable' ),
1857 __( 'South Africa', 'formidable' ),
1858 __( 'South Georgia and the South Sandwich Islands', 'formidable' ),
1859 __( 'South Sudan', 'formidable' ),
1860 __( 'Spain', 'formidable' ),
1861 __( 'Sri Lanka', 'formidable' ),
1862 __( 'Sudan', 'formidable' ),
1863 __( 'Suriname', 'formidable' ),
1864 __( 'Svalbard and Jan Mayen', 'formidable' ),
1865 __( 'Swaziland', 'formidable' ),
1866 __( 'Sweden', 'formidable' ),
1867 __( 'Switzerland', 'formidable' ),
1868 __( 'Syria', 'formidable' ),
1869 __( 'Taiwan', 'formidable' ),
1870 __( 'Tajikistan', 'formidable' ),
1871 __( 'Tanzania', 'formidable' ),
1872 __( 'Thailand', 'formidable' ),
1873 __( 'Timor-Leste', 'formidable' ),
1874 __( 'Togo', 'formidable' ),
1875 __( 'Tokelau', 'formidable' ),
1876 __( 'Tonga', 'formidable' ),
1877 __( 'Trinidad and Tobago', 'formidable' ),
1878 __( 'Tunisia', 'formidable' ),
1879 __( 'Turkey', 'formidable' ),
1880 __( 'Turkmenistan', 'formidable' ),
1881 __( 'Turks and Caicos Islands', 'formidable' ),
1882 __( 'Tuvalu', 'formidable' ),
1883 __( 'Uganda', 'formidable' ),
1884 __( 'Ukraine', 'formidable' ),
1885 __( 'United Arab Emirates', 'formidable' ),
1886 __( 'United Kingdom', 'formidable' ),
1887 __( 'United States', 'formidable' ),
1888 __( 'United States Minor Outlying Islands', 'formidable' ),
1889 __( 'Uruguay', 'formidable' ),
1890 __( 'Uzbekistan', 'formidable' ),
1891 __( 'Vanuatu', 'formidable' ),
1892 __( 'Vatican City', 'formidable' ),
1893 __( 'Venezuela', 'formidable' ),
1894 __( 'Vietnam', 'formidable' ),
1895 __( 'Virgin Islands, British', 'formidable' ),
1896 __( 'Virgin Islands, U.S.', 'formidable' ),
1897 __( 'Wallis and Futuna', 'formidable' ),
1898 __( 'Western Sahara', 'formidable' ),
1899 __( 'Yemen', 'formidable' ),
1900 __( 'Zambia', 'formidable' ),
1901 __( 'Zimbabwe', 'formidable' ),
1902 );
1903
1904 sort( $countries, SORT_LOCALE_STRING );
1905 return apply_filters( 'frm_countries', $countries );
1906 }
1907
1908 /**
1909 * Gets bulk prefilled options.
1910 *
1911 * @since 5.0.04 Add `$include_class` param.
1912 *
1913 * @param array $prepop Bulk options.
1914 * @param array|false $include_class Include the class in the bulk options.
1915 */
1916 public static function get_bulk_prefilled_opts( array &$prepop, $include_class = false ) {
1917 // Countries.
1918 $countries = self::get_countries();
1919 if ( $include_class ) {
1920 $countries['class'] = 'frm-countries-opts';
1921 }
1922
1923 $prepop[ __( 'Countries', 'formidable' ) ] = $countries;
1924
1925 // State abv.
1926 $states = self::get_us_states();
1927 $state_abv = array_keys( $states );
1928 sort( $state_abv );
1929 if ( $include_class ) {
1930 $state_abv['class'] = 'frm-state-abv-opts';
1931 }
1932
1933 $prepop[ __( 'U.S. State Abbreviations', 'formidable' ) ] = $state_abv;
1934
1935 // States.
1936 $states = array_values( $states );
1937 sort( $states );
1938 if ( $include_class ) {
1939 $states['class'] = 'frm-states-opts';
1940 }
1941
1942 $prepop[ __( 'U.S. States', 'formidable' ) ] = $states;
1943 unset( $state_abv, $states );
1944
1945 // Age.
1946 $ages = array(
1947 __( 'Under 18', 'formidable' ),
1948 __( '18-24', 'formidable' ),
1949 __( '25-34', 'formidable' ),
1950 __( '35-44', 'formidable' ),
1951 __( '45-54', 'formidable' ),
1952 __( '55-64', 'formidable' ),
1953 __( '65 or Above', 'formidable' ),
1954 __( 'Prefer Not to Answer', 'formidable' ),
1955 );
1956 if ( $include_class ) {
1957 $ages['class'] = 'frm-age-opts';
1958 }
1959
1960 $prepop[ __( 'Age', 'formidable' ) ] = $ages;
1961
1962 // Satisfaction.
1963 $satisfaction = array(
1964 __( 'Very Unsatisfied', 'formidable' ),
1965 __( 'Unsatisfied', 'formidable' ),
1966 __( 'Neutral', 'formidable' ),
1967 __( 'Satisfied', 'formidable' ),
1968 __( 'Very Satisfied', 'formidable' ),
1969 __( 'N/A', 'formidable' ),
1970 );
1971 if ( $include_class ) {
1972 $satisfaction['class'] = 'frm-satisfaction-opts';
1973 }
1974
1975 $prepop[ __( 'Satisfaction', 'formidable' ) ] = $satisfaction;
1976
1977 // Importance.
1978 $importance = array(
1979 __( 'Not at all Important', 'formidable' ),
1980 __( 'Somewhat Important', 'formidable' ),
1981 __( 'Neutral', 'formidable' ),
1982 __( 'Important', 'formidable' ),
1983 __( 'Very Important', 'formidable' ),
1984 __( 'N/A', 'formidable' ),
1985 );
1986 if ( $include_class ) {
1987 $importance['class'] = 'frm-importance-opts';
1988 }
1989
1990 $prepop[ __( 'Importance', 'formidable' ) ] = $importance;
1991
1992 // Agreement.
1993 $agreement = array(
1994 __( 'Strongly Disagree', 'formidable' ),
1995 __( 'Disagree', 'formidable' ),
1996 __( 'Neutral', 'formidable' ),
1997 __( 'Agree', 'formidable' ),
1998 __( 'Strongly Agree', 'formidable' ),
1999 __( 'N/A', 'formidable' ),
2000 );
2001 if ( $include_class ) {
2002 $agreement['class'] = 'frm-agreement-opts';
2003 }
2004
2005 $prepop[ __( 'Agreement', 'formidable' ) ] = $agreement;
2006
2007 // Likely.
2008 $likely = array(
2009 __( 'Extremely Unlikely', 'formidable' ),
2010 __( 'Unlikely', 'formidable' ),
2011 __( 'Neutral', 'formidable' ),
2012 __( 'Likely', 'formidable' ),
2013 __( 'Extremely Likely', 'formidable' ),
2014 __( 'N/A', 'formidable' ),
2015 );
2016 if ( $include_class ) {
2017 $likely['class'] = 'frm-likely-opts';
2018 }
2019
2020 $prepop[ __( 'Likely', 'formidable' ) ] = $likely;
2021
2022 $prepop = apply_filters( 'frm_bulk_field_choices', $prepop );
2023 }
2024
2025 /**
2026 * Display a field value selector
2027 *
2028 * @since 2.03.05
2029 *
2030 * @param int $selector_field_id
2031 * @param array $selector_args
2032 */
2033 public static function display_field_value_selector( $selector_field_id, $selector_args ) {
2034 $field_value_selector = FrmFieldFactory::create_field_value_selector( $selector_field_id, $selector_args );
2035 $field_value_selector->display();
2036 }
2037
2038 /**
2039 * Convert a field object to a flat array
2040 *
2041 * @since 2.03.05
2042 *
2043 * @param object $field
2044 *
2045 * @return array
2046 */
2047 public static function convert_field_object_to_flat_array( $field ) {
2048 $field_options = $field->field_options;
2049 $field_array = get_object_vars( $field );
2050 unset( $field_array['field_options'] );
2051
2052 return $field_array + $field_options;
2053 }
2054
2055 /**
2056 * @since 4.04
2057 *
2058 * @param array $args
2059 * @return void
2060 */
2061 public static function show_add_field_buttons( $args ) {
2062 $field_key = $args['field_key'];
2063 $field_type = $args['field_type'];
2064 $field_label = FrmAppHelper::icon_by_class( FrmFormsHelper::get_field_link_icon( $field_type ), array( 'echo' => false ) );
2065 $field_name = FrmFormsHelper::get_field_link_name( $field_type );
2066 $field_label .= ' <span>' . $field_name . '</span>';
2067
2068 if ( ! empty( $field_type['is_new'] ) ) {
2069 ob_start();
2070 FrmAppHelper::show_pill_text();
2071 $field_label .= ob_get_clean();
2072 }
2073
2074 // If the individual field isn't allowed, disable it.
2075 $run_filter = true;
2076 $single_no_allow = ' ';
2077 $install_data = '';
2078 $requires = '';
2079 $link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
2080 $has_show_upgrade_class = strpos( $field_type['icon'], ' frm_show_upgrade' );
2081 $show_upgrade = $has_show_upgrade_class || false !== strpos( $args['no_allow_class'], 'frm_show_upgrade' );
2082
2083 if ( $has_show_upgrade_class ) {
2084 $single_no_allow .= 'frm_show_upgrade';
2085 $field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
2086 $run_filter = false;
2087 if ( isset( $field_type['addon'] ) ) {
2088 $upgrading = FrmAddonsController::install_link( $field_type['addon'] );
2089 if ( isset( $upgrading['url'] ) ) {
2090 $install_data = json_encode( $upgrading );
2091 }
2092 $requires = FrmFormsHelper::get_plan_required( $upgrading );
2093 } elseif ( isset( $field_type['require'] ) ) {
2094 $requires = $field_type['require'];
2095 }
2096 }
2097
2098 $upgrade_label = '';
2099 $upgrade_message = '';
2100 if ( $show_upgrade ) {
2101 /* translators: %s: Field name */
2102 $upgrade_label = sprintf( esc_html__( '%s fields', 'formidable' ), $field_name );
2103
2104 if ( isset( $field_type['message'] ) ) {
2105 $upgrade_message = FrmAppHelper::kses( $field_type['message'], array( 'a', 'img' ) );
2106 }
2107 }
2108
2109 $li_params = array(
2110 'class' => 'frmbutton frm6 ' . $args['no_allow_class'] . $single_no_allow . ' frm_t' . str_replace( '|', '-', $field_key ),
2111 'id' => $field_key,
2112 'data-upgrade' => $upgrade_label,
2113 'data-link' => $link,
2114 'data-medium' => 'builder',
2115 'data-oneclick' => $install_data,
2116 'data-content' => $field_key,
2117 'data-requires' => $requires,
2118 );
2119
2120 if ( ! empty( $field_type['hide'] ) ) {
2121 $li_params['class'] .= ' frm_hidden';
2122 }
2123
2124 if ( ! empty( $field_type['upsell_image'] ) ) {
2125 $li_params['data-upsell-image'] = $field_type['upsell_image'];
2126 }
2127
2128 if ( $upgrade_message ) {
2129 $li_params['data-message'] = $upgrade_message;
2130 }
2131 ?>
2132 <li <?php FrmAppHelper::array_to_html_params( $li_params, true ); ?>>
2133 <?php
2134 if ( $run_filter ) {
2135 $field_label = apply_filters( 'frmpro_field_links', $field_label, $args['id'], $field_key );
2136 }
2137 echo FrmAppHelper::kses( $field_label, array( 'a', 'i', 'span', 'use', 'svg' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
2138 ?>
2139 </li>
2140 <?php
2141 }
2142
2143 /**
2144 * Shows Display format option.
2145 *
2146 * @since 5.0.04
2147 *
2148 * @param array $field Field data.
2149 */
2150 public static function show_radio_display_format( $field ) {
2151 $options = self::get_display_format_options( $field );
2152
2153 $args = self::get_display_format_args( $field, $options );
2154
2155 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/radio-display-format.php';
2156 }
2157
2158 /**
2159 * Creates an array that contains variables used for display format options setting.
2160 *
2161 * @since 6.3.2
2162 *
2163 * @param array $field The field.
2164 *
2165 * @return array
2166 */
2167 public static function get_display_format_options( $field ) {
2168 $options = array(
2169 '0' => array(
2170 'text' => __( 'Simple', 'formidable' ),
2171 'svg' => 'frm_simple_radio',
2172 ),
2173 '1' => array(
2174 'text' => __( 'Images', 'formidable' ),
2175 'svg' => 'frm_image_as_option',
2176 'addon' => 'pro',
2177 'upgrade' => __( 'Image Options', 'formidable' ),
2178 '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" />',
2179 'content' => 'image-options',
2180 ),
2181 'buttons' => array(
2182 'text' => __( 'Buttons', 'formidable' ),
2183 'svg' => 'frm_button_as_option',
2184 'addon' => 'surveys',
2185 'upgrade' => __( 'Button Options', 'formidable' ),
2186 'message' => __( 'Show buttons for radio buttons or check boxes. This is ideal for polls, surveys, segmenting questionnaires and more.', 'formidable' ),
2187 'content' => 'button-options',
2188 ),
2189 );
2190
2191 /**
2192 * Allows modifying the options of Display format setting of Radio field.
2193 *
2194 * @since 5.0.04
2195 *
2196 * @param array $options Options.
2197 * @param array $field
2198 */
2199 $options = apply_filters( 'frm_' . $field['type'] . '_display_format_options', $options, $field );
2200
2201 return $options;
2202 }
2203
2204 /**
2205 * Gets display format arguments to pass to the images_dropdown() method.
2206 *
2207 * @since 5.0.04
2208 *
2209 * @param array $field Field data.
2210 * @param array $options Options array.
2211 * @return array
2212 */
2213 public static function get_display_format_args( $field, $options ) {
2214 $args = array(
2215 'selected' => '0',
2216 'options' => array(),
2217 'name' => 'field_options[image_options_' . $field['id'] . ']',
2218 'input_attrs' => array(
2219 'class' => 'frm_toggle_image_options',
2220 ),
2221 );
2222
2223 self::fill_image_setting_options( $options, $args );
2224
2225 /**
2226 * Allows modifying the arguments of Display format setting of Radio field.
2227 *
2228 * @since 5.0.04
2229 *
2230 * @param array $args Arguments.
2231 * @param array $method_args The arguments from the method. Contains `field`, `options`.
2232 */
2233 return apply_filters( 'frm_' . $field['type'] . '_display_format_args', $args, compact( 'field', 'options' ) );
2234 }
2235
2236 /**
2237 * @since 5.0.04
2238 */
2239 private static function fill_image_setting_options( $options, &$args ) {
2240 foreach ( $options as $key => $option ) {
2241 $args['options'][ $key ] = $option;
2242
2243 if ( ! empty( $option['addon'] ) ) {
2244 $args['options'][ $key ]['custom_attrs'] = self::fill_image_setting_addon_link( $option );
2245 }
2246
2247 unset( $args['options'][ $key ]['addon'] );
2248 $fill = array( 'upgrade', 'message', 'content' );
2249 foreach ( $fill as $f ) {
2250 unset( $args['options'][ $key ][ $f ], $f );
2251 }
2252 }
2253 }
2254
2255 /**
2256 * @since 5.0.04
2257 *
2258 * @return array
2259 */
2260 private static function fill_image_setting_addon_link( $option ) {
2261 $custom_attrs = array(
2262 'class' => 'frm_noallow frm_show_upgrade',
2263 'data-medium' => 'builder',
2264 );
2265
2266 // translators: Add-on name.
2267 $custom_attrs['data-upgrade'] = sprintf( __( 'Formidable %s', 'formidable' ), ucwords( $option['addon'] ) );
2268
2269 $fill = array( 'upgrade', 'message', 'content' );
2270 foreach ( $fill as $f ) {
2271 if ( isset( $option[ $f ] ) ) {
2272 $custom_attrs[ 'data-' . $f ] = $option[ $f ];
2273 }
2274 }
2275
2276 if ( 'pro' === $option['addon'] ) {
2277 return $custom_attrs;
2278 }
2279
2280 $upgrading = FrmAddonsController::install_link( $option['addon'] );
2281 if ( isset( $upgrading['url'] ) ) {
2282 $install_data = wp_json_encode( $upgrading );
2283 } else {
2284 $install_data = '';
2285 }
2286
2287 $custom_attrs['data-oneclick'] = $install_data;
2288 $custom_attrs['data-requires'] = FrmFormsHelper::get_plan_required( $upgrading );
2289
2290 return $custom_attrs;
2291 }
2292
2293 /**
2294 * Maybe adjust a field value based on type.
2295 * Some types require unserializing an array.
2296 * These types are defined by a array_allowed property on their field model class.
2297 *
2298 * @since 6.2
2299 *
2300 * @param mixed $value
2301 * @param string $field_type
2302 * @return void
2303 */
2304 public static function prepare_field_value( &$value, $field_type ) {
2305 $field_object = FrmFieldFactory::get_field_type( $field_type );
2306 $value = $field_object->maybe_decode_value( $value );
2307 }
2308
2309 /**
2310 * @since 6.8
2311 *
2312 * @param int|string $form_id
2313 * @param array $field_ids If this is not empty, the results will be filtered by field id.
2314 * @return array
2315 */
2316 public static function get_draft_field_results( $form_id, $field_ids = array() ) {
2317 if ( FrmAppHelper::pro_is_installed() ) {
2318 $child_form_ids = FrmDb::get_col( 'frm_forms', array( 'parent_form_id' => $form_id ) );
2319 $form_ids = array_merge( array( $form_id ), $child_form_ids );
2320 } else {
2321 $form_ids = array( $form_id );
2322 }
2323
2324 $where = array(
2325 'form_id' => $form_ids,
2326 // Do a soft check for fields that look like drafts only.
2327 'field_options LIKE' => 's:5:"draft";i:1;',
2328 );
2329
2330 if ( $field_ids ) {
2331 $where['id'] = $field_ids;
2332 }
2333
2334 $rows = FrmDb::get_results( 'frm_fields', $where, 'id, field_options' );
2335
2336 return array_filter(
2337 $rows,
2338 function ( $row ) {
2339 FrmAppHelper::unserialize_or_decode( $row->field_options );
2340 return is_array( $row->field_options ) && ! empty( $row->field_options['draft'] );
2341 }
2342 );
2343 }
2344
2345 /**
2346 * This is called when loading the form builder.
2347 * Any unsaved draft fields get added to a hidden draft_fields input on load.
2348 *
2349 * @since 6.8
2350 *
2351 * @param int|string $form_id
2352 * @return array
2353 */
2354 public static function get_all_draft_field_ids( $form_id ) {
2355 $draft_field_rows = self::get_draft_field_results( $form_id );
2356 return wp_list_pluck( $draft_field_rows, 'id' );
2357 }
2358 }
2359