PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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
← All changes | classes/helpers/FrmFieldsHelper.php +699 -199 6.25.1 → trunk View file →
@@ -11,11 +11,16 @@
11 11 * @var bool|null
12 12 */
13 13 private static $context_is_safe_to_load_field_options_from_request_data;
14 14
15 + /**
16 + * @param string $type
17 + * @param int|string $form_id
18 + *
19 + * @return array
20 + */
15 21 public static function setup_new_vars( $type = '', $form_id = '' ) {
16 -
17 - if ( strpos( $type, '|' ) ) {
22 + if ( str_contains( $type, '|' ) ) {
18 23 list( $type, $setting ) = explode( '|', $type );
19 24 }
20 25
21 26 $values = self::get_default_field( $type );
@@ -47,18 +52,34 @@
47 52
48 53 return $values;
49 54 }
50 55
56 + /**
57 + * @param array $field
58 + * @param string $plus
59 + *
60 + * @return string
61 + */
51 62 public static function get_html_id( $field, $plus = '' ) {
52 63 return apply_filters( 'frm_field_html_id', 'field_' . $field['field_key'] . $plus, $field );
53 64 }
54 65
66 + /**
67 + * @param object $field
68 + * @param bool $doing_ajax
69 + *
70 + * @return array
71 + */
55 72 public static function setup_edit_vars( $field, $doing_ajax = false ) {
56 73 $values = self::field_object_to_array( $field );
57 -
58 74 return apply_filters( 'frm_setup_edit_field_vars', $values, array( 'doing_ajax' => $doing_ajax ) );
59 75 }
60 76
77 + /**
78 + * @param object $field
79 + *
80 + * @return array
81 + */
61 82 public static function field_object_to_array( $field ) {
62 83 $values = (array) $field;
63 84
64 85 self::fill_field_array( $field, $values );
@@ -67,8 +88,14 @@
67 88
68 89 return $values;
69 90 }
70 91
92 + /**
93 + * @param object $field
94 + * @param array $field_array
95 + *
96 + * @return void
97 + */
71 98 private static function fill_field_array( $field, array &$field_array ) {
72 99 $field_array['options'] = $field->options;
73 100 $field_array['value'] = $field->default_value;
74 101
@@ -77,11 +104,17 @@
77 104 $field_array = array_merge( (array) $field->field_options, $field_array );
78 105 }
79 106
80 107 /**
81 - * Prepare field while creating a new entry
108 + * Prepare field while creating a new entry.
82 109 *
83 110 * @since 3.0
111 + *
112 + * @param array $field_array Field values array, passed by reference.
113 + * @param stdClass $field Field object.
114 + * @param array $args Additional arguments.
115 + *
116 + * @return void
84 117 */
85 118 public static function prepare_new_front_field( &$field_array, $field, $args = array() ) {
86 119 $args['action'] = 'new';
87 120 self::prepare_front_field( $field_array, $field, $args );
@@ -87,11 +120,18 @@
87 120 self::prepare_front_field( $field_array, $field, $args );
88 121 }
89 122
90 123 /**
91 - * Prepare field while editing an entry
124 + * Prepare field while editing an entry.
92 125 *
93 126 * @since 3.0
127 + *
128 + * @param array $field_array Field values array, passed by reference.
129 + * @param array|stdClass $field Field object or array.
130 + * @param int $entry_id Entry ID.
131 + * @param array $args Additional arguments.
132 + *
133 + * @return void
94 134 */
95 135 public static function prepare_edit_front_field( &$field_array, $field, $entry_id = 0, $args = array() ) {
96 136 $args['entry_id'] = $entry_id;
97 137 $args['action'] = 'edit';
@@ -105,8 +145,9 @@
105 145 *
106 146 * @param array $field_array
107 147 * @param stdClass $field
108 148 * @param array $args
149 + *
109 150 * @return void
110 151 */
111 152 private static function prepare_front_field( &$field_array, $field, $args ) {
112 153 self::fill_default_field_opts( $field, $field_array );
@@ -124,16 +165,18 @@
124 165 * @param int|string $entry_id
125 166 * @param array $args
126 167 */
127 168 $field_array = apply_filters( 'frm_setup_edit_fields_vars', $field_array, $field, $args['entry_id'], $args );
128 - } else {
129 - /**
130 - * @param array $field_array
131 - * @param stdClass $field
132 - * @param array $args
133 - */
134 - $field_array = apply_filters( 'frm_setup_new_fields_vars', $field_array, $field, $args );
169 +
170 + return;
135 171 }
172 +
173 + /**
174 + * @param array $field_array
175 + * @param stdClass $field
176 + * @param array $args
177 + */
178 + $field_array = apply_filters( 'frm_setup_new_fields_vars', $field_array, $field, $args );
136 179 }
137 180
138 181 /**
139 182 * @since 3.0
@@ -143,9 +186,8 @@
143 186 * @return array
144 187 */
145 188 public static function get_default_field_options( $type ) {
146 189 $field_type = FrmFieldFactory::get_field_type( $type );
147 -
148 190 return $field_type->get_default_field_options();
149 191 }
150 192
151 193 /**
@@ -152,8 +194,10 @@
152 194 * @since 3.0
153 195 *
154 196 * @param object $field
155 197 * @param array $values
198 + *
199 + * @return void
156 200 */
157 201 private static function fill_default_field_opts( $field, array &$values ) {
158 202 $check_post = self::context_is_safe_to_load_field_options_from_request_data();
159 203 $defaults = self::get_default_field_options_from_field( $field, $values );
@@ -197,8 +241,9 @@
197 241 return false;
198 242 }
199 243
200 244 $action = FrmAppHelper::get_post_param( 'action', '', 'sanitize_title' );
245 +
201 246 if ( 'frm_forms_preview' === $action ) {
202 247 // Never trigger when previewing.
203 248 return false;
204 249 }
@@ -209,8 +254,9 @@
209 254 return wp_verify_nonce( $nonce, 'frm_save_form_nonce' );
210 255 }
211 256
212 257 $action = FrmAppHelper::get_post_param( 'frm_action', '', 'sanitize_title' );
258 +
213 259 if ( 'update_settings' === $action ) {
214 260 $nonce = FrmAppHelper::get_post_param( 'process_form', '', 'sanitize_text_field' );
215 261 return wp_verify_nonce( $nonce, 'process_form_nonce' );
216 262 }
@@ -228,10 +274,13 @@
228 274 * @since 3.0
229 275 *
230 276 * @param object $field
231 277 * @param array $field_array
278 + *
279 + * @return void
232 280 */
233 281 private static function fill_cleared_strings( $field, array &$field_array ) {
282 + // phpcs:ignore Universal.Operators.StrictComparisons
234 283 if ( '' == $field_array['blank'] && '1' === $field_array['required'] ) {
235 284 $field_array['blank'] = self::default_blank_msg();
236 285 }
237 286
@@ -243,8 +292,9 @@
243 292 $field_array['invalid'] = self::default_invalid_msg();
244 293 }
245 294 }
246 295
296 + // phpcs:ignore Universal.Operators.StrictComparisons
247 297 if ( '' == $field_array['custom_html'] ) {
248 298 $field_array['custom_html'] = self::get_default_html( $field->type );
249 299 }
250 300 }
@@ -266,10 +316,9 @@
266 316 */
267 317 public static function default_unique_msg() {
268 318 $frm_settings = FrmAppHelper::get_settings();
269 319 $unique_message = $frm_settings->unique_msg;
270 - $unique_message = str_replace( 'This value', '[field_name]', $unique_message );
271 - return $unique_message;
320 + return str_replace( 'This value', '[field_name]', $unique_message );
272 321 }
273 322
274 323 /**
275 324 * @since 6.8.3
@@ -278,10 +327,9 @@
278 327 */
279 328 public static function default_blank_msg() {
280 329 $frm_settings = FrmAppHelper::get_settings();
281 330 $blank_message = $frm_settings->blank_msg;
282 - $blank_message = str_replace( 'This field', '[field_name]', $blank_message );
283 - return $blank_message;
331 + return str_replace( 'This field', '[field_name]', $blank_message );
284 332 }
285 333
286 334 /**
287 335 * When loading settings for a field, check the $_POST data and possibly use that instead of the DB value.
@@ -289,8 +337,10 @@
289 337 * @since 3.0
290 338 *
291 339 * @param string $setting
292 340 * @param mixed $value
341 + *
342 + * @return void
293 343 */
294 344 private static function get_posted_field_setting( $setting, &$value ) {
295 345 if ( ! isset( $_POST['field_options'][ $setting ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
296 346 return;
@@ -295,20 +345,20 @@
295 345 if ( ! isset( $_POST['field_options'][ $setting ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
296 346 return;
297 347 }
298 348
299 - if ( strpos( $setting, 'html' ) !== false ) {
300 - $value = wp_unslash( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
349 + if ( str_contains( $setting, 'html' ) ) {
350 + $value = wp_unslash( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing, SlevomatCodingStandard.Files.LineLength.LineTooLong
301 351
302 352 // Conditionally strip script tags if the user sending $_POST data is not allowed to use unfiltered HTML.
303 353 if ( ! FrmAppHelper::allow_unfiltered_html() ) {
304 354 $value = FrmAppHelper::kses( $value, 'all' );
305 355 }
306 - } elseif ( strpos( $setting, 'format_' ) === 0 ) {
356 + } elseif ( str_starts_with( $setting, 'format_' ) ) {
307 357 // TODO: Remove stripslashes on output, and use on input only.
308 - $value = sanitize_text_field( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Missing
358 + $value = sanitize_text_field( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Missing, SlevomatCodingStandard.Files.LineLength.LineTooLong
309 359 } else {
310 - $value = wp_unslash( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
360 + $value = wp_unslash( $_POST['field_options'][ $setting ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing, SlevomatCodingStandard.Files.LineLength.LineTooLong
311 361 FrmAppHelper::sanitize_value( 'wp_kses_post', $value );
312 362 }
313 363 }
314 364
@@ -322,13 +372,11 @@
322 372 */
323 373 public static function get_default_field_options_from_field( $field, $values = array() ) {
324 374 $field_type = self::get_original_field( $field );
325 375 $opts = $field_type->get_default_field_options();
376 + $opts = apply_filters( 'frm_default_field_opts', $opts, $values, $field );
326 377
327 - $opts = apply_filters( 'frm_default_field_opts', $opts, $values, $field );
328 - $opts = apply_filters( 'frm_default_' . $field->type . '_field_opts', $opts, $values, $field );
329 -
330 - return $opts;
378 + return apply_filters( 'frm_default_' . $field->type . '_field_opts', $opts, $values, $field );
331 379 }
332 380
333 381 /**
334 382 * @since 3.0
@@ -338,9 +386,10 @@
338 386 * @return FrmFieldType
339 387 */
340 388 private static function get_original_field( $field ) {
341 389 $original_type = FrmField::get_option( $field, 'original_type' );
342 - if ( ! empty( $original_type ) && $field->type != $original_type ) {
390 +
391 + if ( $original_type && $field->type !== $original_type ) {
343 392 $field->type = $original_type;
344 393 }
345 394
346 395 return FrmFieldFactory::get_field_object( $field );
@@ -351,8 +400,10 @@
351 400 *
352 401 * @param array $field_array
353 402 * @param object $field
354 403 * @param array $atts
404 + *
405 + * @return void
355 406 */
356 407 private static function prepare_field_options_for_display( &$field_array, $field, $atts ) {
357 408 $field_obj = FrmFieldFactory::get_field_object( $field );
358 409 $field_array = $field_obj->prepare_front_field( $field_array, $atts );
@@ -366,12 +417,19 @@
366 417 * @return array
367 418 */
368 419 public static function get_default_field( $type ) {
369 420 $field_type = FrmFieldFactory::get_field_type( $type );
370 -
371 421 return $field_type->get_new_field_defaults();
372 422 }
373 423
424 + /**
425 + * @param array $values
426 + * @param object $field
427 + * @param int|string $form_id
428 + * @param string $new_key
429 + *
430 + * @return void
431 + */
374 432 public static function fill_field( &$values, $field, $form_id, $new_key = '' ) {
375 433 global $wpdb;
376 434
377 435 $values['field_key'] = FrmAppHelper::get_unique_key( $new_key, $wpdb->prefix . 'frm_fields', 'field_key' );
@@ -393,11 +451,10 @@
393 451 * @return string
394 452 */
395 453 public static function get_error_msg( $field, $error ) {
396 454 $frm_settings = FrmAppHelper::get_settings();
397 -
398 - $conf_msg = __( 'The entered values do not match', 'formidable' );
399 - $defaults = array(
455 + $conf_msg = __( 'The entered values do not match', 'formidable' );
456 + $defaults = array(
400 457 'unique_msg' => array(
401 458 'full' => self::default_unique_msg(),
402 459 /* translators: %s: Field name */
403 460 'part' => sprintf( __( '%s must be unique', 'formidable' ), '[field_name]' ),
@@ -416,15 +473,21 @@
416 473 'part' => $conf_msg,
417 474 ),
418 475 );
419 476
477 + /**
478 + * @since 6.28
479 + *
480 + * @param array $defaults
481 + * @param array|object $field
482 + */
483 + $defaults = apply_filters( 'frm_default_field_validation_messages', $defaults, $field );
484 +
420 485 $msg = FrmField::get_option( $field, $error );
421 - $msg = empty( $msg ) ? $defaults[ $error ]['part'] : $msg;
486 + $msg = $msg ? $msg : $defaults[ $error ]['part'];
422 487 $msg = do_shortcode( $msg );
423 488
424 - $msg = self::maybe_replace_substrings_with_field_name( $msg, $error, $field );
425 -
426 - return $msg;
489 + return self::maybe_replace_substrings_with_field_name( $msg, $error, $field );
427 490 }
428 491
429 492 /**
430 493 * @since 6.8.3
@@ -431,8 +494,10 @@
431 494 *
432 495 * @param string $msg
433 496 * @param string $error
434 497 * @param array|object $field
498 + *
499 + * @return string
435 500 */
436 501 private static function maybe_replace_substrings_with_field_name( $msg, $error, $field ) {
437 502 $field_name = is_array( $field ) ? $field['name'] : $field->name;
438 503 $field_name = FrmAppHelper::maybe_kses( $field_name );
@@ -439,17 +504,12 @@
439 504 $substrings = self::get_substrings_to_replace_with_field_name( $field_name, compact( 'msg', 'error', 'field' ) );
440 505
441 506 // Use the "This value"/"This field" placeholder strings if field name is empty.
442 507 if ( ! $field_name ) {
443 - if ( 'unique_msg' === $error ) {
444 - $field_name = __( 'This value', 'formidable' );
445 - } else {
446 - $field_name = __( 'This field', 'formidable' );
447 - }
508 + $field_name = 'unique_msg' === $error ? __( 'This value', 'formidable' ) : __( 'This field', 'formidable' );
448 509 }
449 510
450 - $msg = str_replace( $substrings, $field_name, $msg );
451 - return $msg;
511 + return str_replace( $substrings, $field_name, $msg );
452 512 }
453 513
454 514 /**
455 515 * @since 6.8.3
@@ -461,12 +521,14 @@
461 521 * @type string $msg The current error message before the substrings are replaced.
462 522 * @type string $error A key including 'unique_msg', 'invalid', 'blank', or 'conf_msg'.
463 523 * @type array|object $field The field with the error.
464 524 * }
525 + *
465 526 * @return array
466 527 */
467 528 private static function get_substrings_to_replace_with_field_name( $field_name, $filter_args ) {
468 529 $substrings = array( '[field_name]' );
530 +
469 531 if ( $field_name ) {
470 532 array_push( $substrings, 'This value', 'This field' );
471 533 }
472 534
@@ -486,19 +548,32 @@
486 548
487 549 return $substrings;
488 550 }
489 551
552 + /**
553 + * @param int|string $form_id
554 + * @param array $error
555 + *
556 + * @return array
557 + */
490 558 public static function get_form_fields( $form_id, $error = array() ) {
491 559 $fields = FrmField::get_all_for_form( $form_id );
492 560
561 + FrmFieldName::track_first_name_field( $fields );
562 +
493 563 return apply_filters( 'frm_get_paged_fields', $fields, $form_id, $error );
494 564 }
495 565
566 + /**
567 + * @param string $type
568 + *
569 + * @return string
570 + */
496 571 public static function get_default_html( $type = 'text' ) {
497 572 $field = FrmFieldFactory::get_field_type( $type );
498 573 $default_html = $field->default_html();
499 574
500 - // these hooks are here for reverse compatibility since 3.0
575 + // These hooks are here for reverse compatibility since 3.0
501 576 if ( ! apply_filters( 'frm_normal_field_type_html', true, $type ) ) {
502 577 $default_html = apply_filters( 'frm_other_custom_html', '', $type );
503 578 }
504 579
@@ -509,11 +584,17 @@
509 584 * @param array $fields
510 585 * @param array $errors
511 586 * @param object $form
512 587 * @param object $form_action
588 + *
589 + * @return void
513 590 */
514 591 public static function show_fields( $fields, $errors, $form, $form_action ) {
515 592 foreach ( $fields as $field ) {
593 + if ( ! is_array( $field ) ) {
594 + continue;
595 + }
596 +
516 597 $field_obj = FrmFieldFactory::get_field_type( $field['type'], $field );
517 598 $field_obj->show_field( compact( 'errors', 'form', 'form_action' ) );
518 599 }
519 600 }
@@ -522,17 +603,23 @@
522 603 * @since 3.0
523 604 *
524 605 * @param array $atts
525 606 * @param array|string $value
607 + *
608 + * @return void
526 609 */
527 610 public static function run_wpautop( $atts, &$value ) {
528 611 $autop = $atts['wpautop'] ?? true;
529 - if ( apply_filters( 'frm_use_wpautop', $autop ) ) {
530 - if ( is_array( $value ) ) {
531 - $value = implode( "\n", $value );
532 - }
533 - $value = wpautop( $value );
612 +
613 + if ( ! apply_filters( 'frm_use_wpautop', $autop ) ) {
614 + return;
534 615 }
616 +
617 + if ( is_array( $value ) ) {
618 + $value = implode( "\n", $value );
619 + }
620 +
621 + $value = wpautop( $value );
535 622 }
536 623
537 624 /**
538 625 * Get the class to use for the label position
@@ -537,13 +624,19 @@
537 624 /**
538 625 * Get the class to use for the label position
539 626 *
540 627 * @since 2.05
628 + *
629 + * @param string $position
630 + * @param array $field
631 + * @param bool|object|string $form
632 + *
633 + * @return string
541 634 */
542 - public static function &label_position( $position, $field, $form ) {
543 - if ( $position && $position != '' ) {
635 + public static function label_position( $position, $field, $form ) {
636 + if ( $position ) {
544 637 if ( $position === 'inside' && ! self::is_placeholder_field_type( $field['type'] ) ) {
545 - $position = 'top';
638 + return 'top';
546 639 }
547 640
548 641 return $position;
549 642 }
@@ -548,8 +641,9 @@
548 641 return $position;
549 642 }
550 643
551 644 $position = FrmStylesController::get_style_val( 'position', $form );
645 +
552 646 if ( $position === 'none' ) {
553 647 $position = 'top';
554 648 } elseif ( $position === 'no_label' ) {
555 649 $position = 'none';
@@ -557,11 +651,9 @@
557 651 $position = 'top';
558 652 }
559 653
560 654 $position = apply_filters( 'frm_html_label_position', $position, $field, $form );
561 - $position = ! empty( $position ) ? $position : 'top';
562 -
563 - return $position;
655 + return $position ? $position : 'top';
564 656 }
565 657
566 658 /**
567 659 * Check if this field type allows placeholders
@@ -566,9 +658,11 @@
566 658 /**
567 659 * Check if this field type allows placeholders
568 660 *
569 661 * @since 2.05
662 + *
570 663 * @param string $type
664 + *
571 665 * @return bool
572 666 */
573 667 public static function is_placeholder_field_type( $type ) {
574 668 return ! in_array( $type, array( 'radio', 'checkbox', 'hidden', 'file' ), true );
@@ -573,11 +667,19 @@
573 667 public static function is_placeholder_field_type( $type ) {
574 668 return ! in_array( $type, array( 'radio', 'checkbox', 'hidden', 'file' ), true );
575 669 }
576 670
671 + /**
672 + * @param array $field
673 + * @param int|string $opt_key
674 + * @param string $type
675 + *
676 + * @return string
677 + */
577 678 public static function get_checkbox_id( $field, $opt_key, $type = 'checkbox' ) {
578 679 $id = $field['id'];
579 - if ( isset( $field['in_section'] ) && $field['in_section'] && ! FrmAppHelper::is_admin_page( 'formidable' ) ) {
680 +
681 + if ( ! empty( $field['in_section'] ) && ! FrmAppHelper::is_admin_page( 'formidable' ) ) {
580 682 $id .= '-' . $field['in_section'];
581 683 }
582 684
583 685 return 'frm_' . $type . '_' . $id . '-' . $opt_key;
@@ -582,8 +684,13 @@
582 684
583 685 return 'frm_' . $type . '_' . $id . '-' . $opt_key;
584 686 }
585 687
688 + /**
689 + * @param array $field
690 + *
691 + * @return void
692 + */
586 693 public static function show_single_option( $field ) {
587 694 self::hidden_field_option( $field );
588 695
589 696 if ( ! is_array( $field['options'] ) ) {
@@ -589,21 +696,20 @@
589 696 if ( ! is_array( $field['options'] ) ) {
590 697 return;
591 698 }
592 699
593 - $base_name = 'default_value_' . $field['id'];
594 - $html_id = $field['html_id'] ?? self::get_html_id( $field );
595 -
700 + $base_name = 'default_value_' . $field['id'];
701 + $html_id = $field['html_id'] ?? self::get_html_id( $field );
596 702 $default_type = self::get_default_value_type( $field );
597 703 $options_count = count( $field['options'] );
598 704
599 705 foreach ( $field['options'] as $opt_key => $opt ) {
600 - $field_val = self::get_value_from_array( $opt, $opt_key, $field );
601 - $opt = self::get_label_from_array( $opt, $opt_key, $field );
602 -
706 + $field_val = self::get_value_from_array( $opt, $opt_key, $field );
707 + $opt = self::get_label_from_array( $opt, $opt_key, $field );
603 708 $field_name = $base_name . ( $default_type === 'checkbox' ? '[' . $opt_key . ']' : '' );
604 709
605 - $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'] ) ) ) );
710 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict, Universal.Operators.StrictComparisons, SlevomatCodingStandard.Files.LineLength.LineTooLong
711 + $checked = isset( $field['default_value'] ) && ( is_array( $field['default_value'] ) ? in_array( $field_val, $field['default_value'] ) : $field['default_value'] == $field_val );
606 712
607 713 // If this is an "Other" option, get the HTML for it.
608 714 if ( self::is_other_opt( $opt_key ) ) {
609 715 if ( FrmAppHelper::pro_is_installed() ) {
@@ -620,26 +726,29 @@
620 726 /**
621 727 * Include hidden row for javascript to duplicate.
622 728 *
623 729 * @since 4.0
730 + *
624 731 * @param array $field
732 + *
733 + * @return void
625 734 */
626 735 private static function hidden_field_option( $field ) {
627 736 // Don't duplicate during an ajax add option.
628 737 $ajax_action = FrmAppHelper::get_param( 'action', '', 'post', 'sanitize_text_field' );
738 +
629 739 if ( $ajax_action === 'frm_add_field_option' ) {
630 740 return;
631 741 }
632 742
633 - $opt_key = '000';
634 - $field_val = __( 'New Option', 'formidable' );
635 - $opt = __( 'New Option', 'formidable' );
636 - $checked = false;
637 - $field_name = 'default_value_' . $field['id'];
638 - $html_id = $field['html_id'] ?? self::get_html_id( $field );
639 -
743 + $opt_key = '000';
744 + $field_val = __( 'New Option', 'formidable' );
745 + $opt = __( 'New Option', 'formidable' );
746 + $checked = false;
747 + $field_name = 'default_value_' . $field['id'];
748 + $html_id = $field['html_id'] ?? self::get_html_id( $field );
640 749 $default_type = self::get_default_value_type( $field );
641 - $field_name .= ( $default_type === 'checkbox' ? '[' . $opt_key . ']' : '' );
750 + $field_name .= $default_type === 'checkbox' ? '[' . $opt_key . ']' : '';
642 751
643 752 require FrmAppHelper::plugin_path() . '/classes/views/frm-fields/single-option.php';
644 753 }
645 754
@@ -646,27 +755,39 @@
646 755 /**
647 756 * @since 4.0
648 757 *
649 758 * @param array $field
759 + *
650 760 * @return string radio or checkbox
651 761 */
652 762 private static function get_default_value_type( $field ) {
653 - $default_type = $field['type'];
654 763 if ( $field['type'] === 'select' ) {
655 - $default_type = FrmField::is_multiple_select( $field ) ? 'checkbox' : 'radio';
764 + return FrmField::is_multiple_select( $field ) ? 'checkbox' : 'radio';
656 765 }
657 - return $default_type;
766 + return $field['type'];
658 767 }
659 768
769 + /**
770 + * @param array|string $opt
771 + * @param int|string $opt_key
772 + * @param array $field
773 + *
774 + * @return mixed
775 + */
660 776 public static function get_value_from_array( $opt, $opt_key, $field ) {
661 777 $opt = apply_filters( 'frm_field_value_saved', $opt, $opt_key, $field );
662 -
663 778 return FrmFieldsController::check_value( $opt, $opt_key, $field );
664 779 }
665 780
781 + /**
782 + * @param array|string $opt
783 + * @param int|string $opt_key
784 + * @param array $field
785 + *
786 + * @return string
787 + */
666 788 public static function get_label_from_array( $opt, $opt_key, $field ) {
667 789 $opt = apply_filters( 'frm_field_label_seen', $opt, $opt_key, $field );
668 -
669 790 return FrmFieldsController::check_label( $opt );
670 791 }
671 792
672 793 /**
@@ -675,8 +796,10 @@
675 796 * @since 4.0
676 797 * @since 6.4.1 Added `inside_class` in the arguments.
677 798 *
678 799 * @param array $args The arguments.
800 + *
801 + * @return void
679 802 */
680 803 public static function inline_modal( $args ) {
681 804 $defaults = array(
682 805 'id' => '',
@@ -694,22 +817,29 @@
694 817 }
695 818
696 819 /**
697 820 * @since 4.0
821 + *
822 + * @return void
698 823 */
699 824 public static function smart_values() {
700 825 $continue = apply_filters( 'frm_smart_values_box', true );
701 - if ( $continue === true ) {
702 - $upgrade_link = array(
703 - 'medium' => 'builder',
704 - 'content' => 'smart-tags',
705 - );
706 - include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/smart-values.php';
826 +
827 + if ( $continue !== true ) {
828 + return;
707 829 }
830 +
831 + $upgrade_link = array(
832 + 'medium' => 'builder',
833 + 'content' => 'smart-tags',
834 + );
835 + include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/smart-values.php';
708 836 }
709 837
710 838 /**
711 839 * @since 4.0
840 + *
841 + * @return void
712 842 */
713 843 public static function input_mask() {
714 844 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/input-mask-info.php';
715 845 }
@@ -715,8 +845,10 @@
715 845 }
716 846
717 847 /**
718 848 * @since 4.0
849 + *
850 + * @return void
719 851 */
720 852 public static function layout_classes() {
721 853 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/layout-classes.php';
722 854 }
@@ -727,25 +859,30 @@
727 859 * @return string
728 860 */
729 861 public static function get_term_link( $tax_id ) {
730 862 $tax = get_taxonomy( $tax_id );
863 +
731 864 if ( ! $tax ) {
732 865 return '';
733 866 }
734 867
735 - $link = sprintf(
868 + return sprintf(
736 869 /* translators: %1$s: Start HTML link, %2$s: Content type label, %3$s: Content type, %4$s: End HTML link */
737 870 esc_html__( 'Options are dynamically created from your %1$s%2$s: %3$s%4$s', 'formidable' ),
738 871 '<a href="' . esc_url( admin_url( 'edit-tags.php?taxonomy=' . $tax->name ) ) . '" target="_blank">',
739 872 esc_html__( 'taxonomy', 'formidable' ),
740 - empty( $tax->labels->name ) ? esc_html__( 'Categories', 'formidable' ) : $tax->labels->name,
873 + ! empty( $tax->labels->name ) ? $tax->labels->name : esc_html__( 'Categories', 'formidable' ),
741 874 '</a>'
742 875 );
743 - unset( $tax );
744 -
745 - return $link;
746 876 }
747 877
878 + /**
879 + * @param array|string $observed_value
880 + * @param string $cond
881 + * @param array|string $hide_opt
882 + *
883 + * @return bool
884 + */
748 885 public static function value_meets_condition( $observed_value, $cond, $hide_opt ) {
749 886 $hide_opt = self::get_value_for_comparison( $hide_opt );
750 887 $observed_value = self::get_value_for_comparison( $observed_value );
751 888
@@ -753,12 +890,13 @@
753 890 return self::array_value_condition( $observed_value, $cond, $hide_opt );
754 891 }
755 892
756 893 $m = false;
894 +
757 895 if ( $cond === '==' ) {
758 - $m = $observed_value == $hide_opt;
896 + $m = $observed_value == $hide_opt; // phpcs:ignore Universal.Operators.StrictComparisons
759 897 } elseif ( $cond === '!=' ) {
760 - $m = $observed_value != $hide_opt;
898 + $m = $observed_value != $hide_opt; // phpcs:ignore Universal.Operators.StrictComparisons
761 899 } elseif ( $cond === '>' ) {
762 900 $m = $observed_value > $hide_opt;
763 901 } elseif ( $cond === '>=' ) {
764 902 $m = $observed_value >= $hide_opt;
@@ -767,20 +905,16 @@
767 905 } elseif ( $cond === '<=' ) {
768 906 $m = $observed_value <= $hide_opt;
769 907 } elseif ( $cond === 'LIKE' || $cond === 'not LIKE' ) {
770 908 $m = stripos( $observed_value, $hide_opt );
771 - if ( $cond === 'not LIKE' ) {
772 - $m = $m === false;
773 - } else {
774 - $m = $m !== false;
775 - }
909 + $m = $cond === 'not LIKE' ? $m === false : $m !== false;
776 910 } elseif ( $cond === '%LIKE' ) {
777 - // ends with
911 + // Ends with
778 912 $length = strlen( $hide_opt );
779 913 $substr = substr( $observed_value, strlen( $observed_value ) - $length );
780 914 $m = 0 === strcasecmp( $substr, $hide_opt );
781 915 } elseif ( 'LIKE%' === $cond ) {
782 - // starts with
916 + // Starts with
783 917 $length = strlen( $hide_opt );
784 918 $substr = substr( $observed_value, 0, $length );
785 919 $m = 0 === strcasecmp( $substr, $hide_opt );
786 920 }//end if
@@ -791,8 +925,12 @@
791 925 /**
792 926 * Trim and sanitize the values
793 927 *
794 928 * @since 2.05
929 + *
930 + * @param array|string $value
931 + *
932 + * @return array|string
795 933 */
796 934 private static function get_value_for_comparison( $value ) {
797 935 // Remove white space from hide_opt
798 936 if ( ! is_array( $value ) ) {
@@ -803,28 +941,37 @@
803 941
804 942 return $value;
805 943 }
806 944
945 + /**
946 + * @param array $observed_value
947 + * @param string $cond
948 + * @param array|string $hide_opt
949 + *
950 + * @return bool
951 + */
807 952 public static function array_value_condition( $observed_value, $cond, $hide_opt ) {
808 953 $m = false;
954 +
809 955 if ( $cond === '==' ) {
810 956 if ( is_array( $hide_opt ) ) {
811 957 $m = array_intersect( $hide_opt, $observed_value );
812 - $m = ! empty( $m );
958 + $m = $m !== array();
813 959 } else {
960 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
814 961 $m = in_array( $hide_opt, $observed_value );
815 962 }
816 963 } elseif ( $cond === '!=' ) {
964 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
817 965 $m = ! in_array( $hide_opt, $observed_value );
818 966 } elseif ( $cond === '>' ) {
819 - $min = min( $observed_value );
820 - $m = $min > $hide_opt;
967 + $m = min( $observed_value ) > $hide_opt;
821 968 } elseif ( $cond === '<' ) {
822 - $max = max( $observed_value );
823 - $m = $max < $hide_opt;
969 + $m = max( $observed_value ) < $hide_opt;
824 970 } elseif ( $cond === 'LIKE' || $cond === 'not LIKE' ) {
825 971 foreach ( $observed_value as $ob ) {
826 972 $m = strpos( $ob, $hide_opt );
973 +
827 974 if ( $m !== false ) {
828 975 $m = true;
829 976 break;
830 977 }
@@ -833,9 +980,9 @@
833 980 if ( $cond === 'not LIKE' ) {
834 981 $m = $m === false;
835 982 }
836 983 } elseif ( $cond === '%LIKE' ) {
837 - // ends with
984 + // Ends with
838 985 foreach ( $observed_value as $ob ) {
839 986 if ( $hide_opt === substr( $ob, strlen( $ob ) - strlen( $hide_opt ) ) ) {
840 987 $m = true;
841 988 break;
@@ -841,11 +988,11 @@
841 988 break;
842 989 }
843 990 }
844 991 } elseif ( $cond === 'LIKE%' ) {
845 - // starts with
992 + // Starts with
846 993 foreach ( $observed_value as $ob ) {
847 - if ( $hide_opt === substr( $ob, 0, strlen( $hide_opt ) ) ) {
994 + if ( str_starts_with( $ob, $hide_opt ) ) {
848 995 $m = true;
849 996 break;
850 997 }
851 998 }
@@ -857,22 +1004,32 @@
857 1004 /**
858 1005 * Replace a few basic shortcodes and field ids
859 1006 *
860 1007 * @since 2.0
1008 + *
1009 + * @param string $value
1010 + * @param object $form
1011 + * @param object $entry
1012 + *
861 1013 * @return string
862 1014 */
863 1015 public static function basic_replace_shortcodes( $value, $form, $entry ) {
864 - if ( strpos( $value, '[sitename]' ) !== false ) {
1016 + if ( str_contains( $value, '[sitename]' ) ) {
865 1017 $new_value = wp_specialchars_decode( FrmAppHelper::site_name(), ENT_QUOTES );
866 1018 $value = str_replace( '[sitename]', $new_value, $value );
867 1019 }
868 1020
869 1021 $value = apply_filters( 'frm_content', $value, $form, $entry );
870 - $value = do_shortcode( $value );
871 1022
872 - return $value;
1023 + return do_shortcode( $value );
873 1024 }
874 1025
1026 + /**
1027 + * @param string $content
1028 + * @param int|string $form_id
1029 + *
1030 + * @return array
1031 + */
875 1032 public static function get_shortcodes( $content, $form_id ) {
876 1033 if ( FrmAppHelper::pro_is_installed() ) {
877 1034 return FrmProDisplaysHelper::get_shortcodes( $content, $form_id );
878 1035 }
@@ -890,8 +1047,13 @@
890 1047
891 1048 return $matches;
892 1049 }
893 1050
1051 + /**
1052 + * @param array $fields
1053 + *
1054 + * @return string
1055 + */
894 1056 public static function allowed_shortcodes( $fields = array() ) {
895 1057 $tagregexp = array(
896 1058 'editlink',
897 1059 'id',
@@ -914,16 +1076,21 @@
914 1076 $tagregexp[] = $field->id;
915 1077 $tagregexp[] = $field->field_key;
916 1078 }
917 1079
918 - $tagregexp = implode( '|', $tagregexp );
919 -
920 - return $tagregexp;
1080 + return implode( '|', $tagregexp );
921 1081 }
922 1082
1083 + /**
1084 + * @param string $content
1085 + * @param false|object $entry
1086 + * @param array $shortcodes
1087 + *
1088 + * @return string
1089 + */
923 1090 public static function replace_content_shortcodes( $content, $entry, $shortcodes ) {
924 1091 foreach ( $shortcodes[0] as $short_key => $tag ) {
925 - if ( empty( $tag ) ) {
1092 + if ( ! $tag ) {
926 1093 continue;
927 1094 }
928 1095
929 1096 $atts = FrmShortcodeHelper::get_shortcode_attribute_array( $shortcodes[3][ $short_key ] );
@@ -947,21 +1114,25 @@
947 1114
948 1115 /**
949 1116 * @param string $replace_with
950 1117 * @param array $atts
1118 + *
951 1119 * @return string
952 1120 */
953 1121 private static function trigger_shortcode_atts( $replace_with, $atts ) {
954 1122 $supported_atts = array( 'remove_accents', 'sanitize', 'sanitize_url' );
955 1123 $included_atts = array_intersect( $supported_atts, array_keys( $atts ) );
1124 +
956 1125 foreach ( $included_atts as $included_att ) {
957 1126 if ( '0' === $atts[ $included_att ] ) {
958 1127 // Skip any option that uses 0 so sanitize_url=0 does not encode.
959 1128 continue;
960 1129 }
1130 +
961 1131 $function = 'atts_' . $included_att;
962 - $replace_with = self::$function( $replace_with, $atts );
1132 + $replace_with = self::$function( $replace_with );
963 1133 }
1134 +
964 1135 return $replace_with;
965 1136 }
966 1137
967 1138 /**
@@ -978,8 +1149,9 @@
978 1149 }
979 1150
980 1151 /**
981 1152 * @param string $replace_with
1153 + *
982 1154 * @return string
983 1155 */
984 1156 private static function atts_sanitize( $replace_with ) {
985 1157 return sanitize_title_with_dashes( $replace_with );
@@ -986,8 +1158,9 @@
986 1158 }
987 1159
988 1160 /**
989 1161 * @param string $replace_with
1162 + *
990 1163 * @return string
991 1164 */
992 1165 private static function atts_sanitize_url( $replace_with ) {
993 1166 return urlencode( $replace_with );
@@ -999,8 +1172,9 @@
999 1172 * @since 3.01.02
1000 1173 *
1001 1174 * @param array $atts Includes entry object.
1002 1175 * @param string|null $value
1176 + *
1003 1177 * @return void
1004 1178 */
1005 1179 public static function sanitize_embedded_shortcodes( $atts, &$value ) {
1006 1180 if ( is_null( $value ) ) {
@@ -1008,8 +1182,9 @@
1008 1182 }
1009 1183
1010 1184 $atts['value'] = $value;
1011 1185 $should_sanitize = apply_filters( 'frm_sanitize_shortcodes', true, $atts );
1186 +
1012 1187 if ( $should_sanitize ) {
1013 1188 $value = str_replace( '[', '&#91;', $value );
1014 1189 }
1015 1190 }
@@ -1077,9 +1252,10 @@
1077 1252 * @return string|null
1078 1253 */
1079 1254 private static function get_field_shortcode_value( $atts ) {
1080 1255 $field = FrmField::getOne( $atts['tag'] );
1081 - if ( empty( $field ) ) {
1256 +
1257 + if ( ! $field ) {
1082 1258 return null;
1083 1259 }
1084 1260
1085 1261 if ( isset( $atts['show'] ) && $atts['show'] === 'field_label' ) {
@@ -1088,14 +1264,16 @@
1088 1264 $replace_with = $field->description;
1089 1265 } else {
1090 1266 $replace_with = FrmEntryMeta::get_meta_value( $atts['entry'], $field->id );
1091 1267 $string_value = $replace_with;
1268 +
1092 1269 if ( is_array( $replace_with ) ) {
1093 1270 $sep = $atts['sep'] ?? ', ';
1094 1271 $string_value = FrmAppHelper::safe_implode( $sep, $replace_with );
1095 1272 }
1096 1273
1097 - if ( empty( $string_value ) && $string_value != '0' ) {
1274 + // phpcs:ignore Universal.Operators.StrictComparisons
1275 + if ( ! $string_value && $string_value != '0' ) {
1098 1276 $replace_with = '';
1099 1277 } else {
1100 1278 $atts['entry_id'] = $atts['entry']->id;
1101 1279 $atts['entry_key'] = $atts['entry']->item_key;
@@ -1100,9 +1278,9 @@
1100 1278 $atts['entry_id'] = $atts['entry']->id;
1101 1279 $atts['entry_key'] = $atts['entry']->item_key;
1102 1280 $replace_with = self::get_display_value( $replace_with, $field, $atts );
1103 1281 }
1104 - }
1282 + }//end if
1105 1283
1106 1284 return $replace_with;
1107 1285 }
1108 1286
@@ -1109,8 +1287,13 @@
1109 1287 /**
1110 1288 * Get the value to replace a few standard shortcodes
1111 1289 *
1112 1290 * @since 2.0
1291 + *
1292 + * @param string $tag
1293 + * @param array $atts
1294 + * @param bool $return_array
1295 + *
1113 1296 * @return string
1114 1297 */
1115 1298 public static function dynamic_default_values( $tag, $atts = array(), $return_array = false ) {
1116 1299 $new_value = '';
@@ -1145,8 +1328,12 @@
1145 1328 /**
1146 1329 * Process the [get] shortcode
1147 1330 *
1148 1331 * @since 2.0
1332 + *
1333 + * @param array $atts
1334 + * @param bool $return_array
1335 + *
1149 1336 * @return array|string
1150 1337 */
1151 1338 public static function process_get_shortcode( $atts, $return_array = false ) {
1152 1339 if ( ! isset( $atts['param'] ) ) {
@@ -1152,9 +1339,9 @@
1152 1339 if ( ! isset( $atts['param'] ) ) {
1153 1340 return '';
1154 1341 }
1155 1342
1156 - if ( strpos( $atts['param'], '&#91;' ) ) {
1343 + if ( str_contains( $atts['param'], '&#91;' ) ) {
1157 1344 $atts['param'] = str_replace( '&#91;', '[', $atts['param'] );
1158 1345 $atts['param'] = str_replace( '&#93;', ']', $atts['param'] );
1159 1346 }
1160 1347
@@ -1160,8 +1347,9 @@
1160 1347
1161 1348 $new_value = FrmAppHelper::get_param( $atts['param'], '', 'get', 'sanitize_text_field' );
1162 1349 $new_value = FrmAppHelper::get_query_var( $new_value, $atts['param'] );
1163 1350
1351 + // phpcs:ignore Universal.Operators.StrictComparisons
1164 1352 if ( $new_value == '' ) {
1165 1353 if ( ! isset( $atts['prev_val'] ) ) {
1166 1354 $atts['prev_val'] = '';
1167 1355 }
@@ -1169,19 +1357,24 @@
1169 1357 $new_value = $atts['default'] ?? $atts['prev_val'];
1170 1358 }
1171 1359
1172 1360 if ( is_array( $new_value ) && ! $return_array ) {
1173 - $new_value = implode( ', ', $new_value );
1361 + return implode( ', ', $new_value );
1174 1362 }
1175 1363
1176 1364 return $new_value;
1177 1365 }
1178 1366
1367 + /**
1368 + * @param mixed $value
1369 + * @param object $field
1370 + * @param array $atts
1371 + *
1372 + * @return mixed
1373 + */
1179 1374 public static function get_display_value( $value, $field, $atts = array() ) {
1180 -
1181 1375 $value = apply_filters( 'frm_get_' . $field->type . '_display_value', $value, $field, $atts );
1182 1376 $value = apply_filters( 'frm_get_display_value', $value, $field, $atts );
1183 -
1184 1377 $value = self::get_unfiltered_display_value( compact( 'value', 'field', 'atts' ) );
1185 1378
1186 1379 return apply_filters( 'frm_display_value', $value, $field, $atts );
1187 1380 }
@@ -1187,8 +1380,10 @@
1187 1380 }
1188 1381
1189 1382 /**
1190 1383 * @param array $atts Includes value, field, and atts.
1384 + *
1385 + * @return mixed
1191 1386 */
1192 1387 public static function get_unfiltered_display_value( $atts ) {
1193 1388 $value = $atts['value'];
1194 1389 $field = $atts['field'];
@@ -1207,8 +1402,12 @@
1207 1402 * Get a value from the user profile from the user ID
1208 1403 *
1209 1404 * @since 3.0
1210 1405 *
1406 + * @param int|string $user_id
1407 + * @param string $user_info
1408 + * @param array $args
1409 + *
1211 1410 * @return string
1212 1411 */
1213 1412 public static function get_user_display_name( $user_id, $user_info = 'display_name', $args = array() ) {
1214 1413 $defaults = array(
@@ -1217,9 +1416,8 @@
1217 1416 'size' => 96,
1218 1417 );
1219 1418
1220 1419 $args = wp_parse_args( $args, $defaults );
1221 -
1222 1420 $user = get_userdata( $user_id );
1223 1421 $info = '';
1224 1422
1225 1423 if ( $user ) {
@@ -1230,15 +1428,15 @@
1230 1428 } else {
1231 1429 $info = $user->$user_info ?? '';
1232 1430 }
1233 1431
1234 - if ( 'display_name' === $user_info && empty( $info ) && ! $args['blank'] ) {
1432 + if ( 'display_name' === $user_info && ! $info && ! $args['blank'] ) {
1235 1433 $info = $user->user_login;
1236 1434 }
1237 1435 }
1238 1436
1239 1437 if ( $args['link'] ) {
1240 - $info = '<a href="' . esc_url( admin_url( 'user-edit.php?user_id=' . $user_id ) ) . '">' . $info . '</a>';
1438 + return '<a href="' . esc_url( admin_url( 'user-edit.php?user_id=' . $user_id ) ) . '">' . $info . '</a>';
1241 1439 }
1242 1440
1243 1441 return $info;
1244 1442 }
@@ -1244,8 +1442,9 @@
1244 1442 }
1245 1443
1246 1444 /**
1247 1445 * @param string $type
1446 + *
1248 1447 * @return array
1249 1448 */
1250 1449 public static function get_field_types( $type ) {
1251 1450 $single_input = self::single_input_fields();
@@ -1260,11 +1459,9 @@
1260 1459 } elseif ( isset( $field_selection[ $type ] ) ) {
1261 1460 $field_types[ $type ] = $field_selection[ $type ];
1262 1461 }
1263 1462
1264 - $field_types = apply_filters( 'frm_switch_field_types', $field_types, compact( 'type', 'field_selection' ) );
1265 -
1266 - return $field_types;
1463 + return apply_filters( 'frm_switch_field_types', $field_types, compact( 'type', 'field_selection' ) );
1267 1464 }
1268 1465
1269 1466 /**
1270 1467 * Get a list of all fields that use a single value input.
@@ -1269,8 +1466,10 @@
1269 1466 /**
1270 1467 * Get a list of all fields that use a single value input.
1271 1468 *
1272 1469 * @since 4.0
1470 + *
1471 + * @return array
1273 1472 */
1274 1473 public static function single_input_fields() {
1275 1474 $fields = array(
1276 1475 'text',
@@ -1293,8 +1492,9 @@
1293 1492 /**
1294 1493 * @param string[] $inputs
1295 1494 * @param array $fields
1296 1495 * @param array $field_types
1496 + *
1297 1497 * @return void
1298 1498 */
1299 1499 private static function field_types_for_input( $inputs, $fields, &$field_types ) {
1300 1500 foreach ( $inputs as $input ) {
@@ -1315,9 +1515,9 @@
1315 1515 *
1316 1516 * @return bool Returns true if current field option is an "Other" option
1317 1517 */
1318 1518 public static function is_other_opt( $opt_key ) {
1319 - return $opt_key && strpos( $opt_key, 'other_' ) === 0;
1519 + return $opt_key && str_starts_with( $opt_key, 'other_' );
1320 1520 }
1321 1521
1322 1522 /**
1323 1523 * Get value that belongs in "Other" text box
@@ -1324,18 +1524,19 @@
1324 1524 *
1325 1525 * @since 2.0.6
1326 1526 *
1327 1527 * @param array $args
1528 + *
1529 + * @return string
1328 1530 */
1329 - public static function get_other_val( $args ) {
1330 - $defaults = array(
1531 + public static function get_other_val( $args ) { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
1532 + $defaults = array(
1331 1533 'opt_key' => 0,
1332 1534 'field' => array(),
1333 1535 'parent' => false,
1334 1536 'pointer' => false,
1335 1537 );
1336 - $args = wp_parse_args( $args, $defaults );
1337 -
1538 + $args = wp_parse_args( $args, $defaults );
1338 1539 $opt_key = $args['opt_key'];
1339 1540 $field = $args['field'];
1340 1541 $parent = $args['parent'];
1341 1542 $pointer = $args['pointer'];
@@ -1341,9 +1542,9 @@
1341 1542 $pointer = $args['pointer'];
1342 1543 $other_val = '';
1343 1544
1344 1545 // If option is an "other" option and there is a value set for this field,
1345 - // check if the value belongs in the current "Other" option text field
1546 + // Check if the value belongs in the current "Other" option text field
1346 1547 if ( ! self::is_other_opt( $opt_key ) || ! FrmField::is_option_true( $field, 'value' ) ) {
1347 1548 return $other_val;
1348 1549 }
1349 1550
@@ -1350,12 +1551,12 @@
1350 1551 // Check posted vals before checking saved values
1351 1552 // For fields inside repeating sections - note, don't check if $pointer is true because it will often be zero
1352 1553 if ( $parent && isset( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1353 1554 if ( FrmField::is_field_with_multiple_values( $field ) ) {
1555 + $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 ] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing, SlevomatCodingStandard.Files.LineLength.LineTooLong
1556 + } else {
1354 1557 // phpcs:ignore WordPress.Security.NonceVerification.Missing
1355 - $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 ] ) ) : '';
1356 - } else {
1357 - $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1558 + $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta'][ $parent ][ $pointer ]['other'][ $field['id'] ] ) );
1358 1559 }
1359 1560
1360 1561 return $other_val;
1361 1562 }
@@ -1363,9 +1564,9 @@
1363 1564 if ( isset( $field['id'] ) && isset( $_POST['item_meta']['other'][ $field['id'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1364 1565 // For normal fields
1365 1566
1366 1567 if ( FrmField::is_field_with_multiple_values( $field ) ) {
1367 - // phpcs:ignore WordPress.Security.NonceVerification.Missing
1568 + // phpcs:ignore WordPress.Security.NonceVerification.Missing, SlevomatCodingStandard.Files.LineLength.LineTooLong
1368 1569 $other_val = isset( $_POST['item_meta']['other'][ $field['id'] ][ $opt_key ] ) ? sanitize_text_field( wp_unslash( $_POST['item_meta']['other'][ $field['id'] ][ $opt_key ] ) ) : '';
1369 1570 } else {
1370 1571 $other_val = sanitize_text_field( wp_unslash( $_POST['item_meta']['other'][ $field['id'] ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
1371 1572 }
@@ -1376,8 +1577,9 @@
1376 1577 // For checkboxes
1377 1578 if ( $field['type'] === 'checkbox' && is_array( $field['value'] ) ) {
1378 1579 // Check if there is an "other" val in saved value and make sure the
1379 1580 // "other" val is not equal to the Other checkbox option
1581 + // phpcs:ignore Universal.Operators.StrictComparisons
1380 1582 if ( isset( $field['value'][ $opt_key ] ) && $field['options'][ $opt_key ] != $field['value'][ $opt_key ] ) {
1381 1583 $other_val = $field['value'][ $opt_key ];
1382 1584 }
1383 1585 } else {
@@ -1386,15 +1588,18 @@
1386 1588 * Check if saved value equals any of the options. If not, set it as the other value.
1387 1589 */
1388 1590 foreach ( $field['options'] as $opt_val ) {
1389 1591 $temp_val = is_array( $opt_val ) ? $opt_val['value'] : $opt_val;
1592 +
1390 1593 // Multi-select dropdowns - key is not preserved
1391 1594 if ( is_array( $field['value'] ) ) {
1595 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
1392 1596 $o_key = array_search( $temp_val, $field['value'] );
1597 +
1393 1598 if ( isset( $field['value'][ $o_key ] ) ) {
1394 1599 unset( $field['value'][ $o_key ], $o_key );
1395 1600 }
1396 - } elseif ( $temp_val == $field['value'] ) {
1601 + } elseif ( $temp_val == $field['value'] ) { // phpcs:ignore Universal.Operators.StrictComparisons
1397 1602 // For radio and regular dropdowns
1398 1603 return '';
1399 1604 } else {
1400 1605 $other_val = $field['value'];
@@ -1400,10 +1605,11 @@
1400 1605 $other_val = $field['value'];
1401 1606 }
1402 1607 unset( $opt_val, $temp_val );
1403 1608 }
1609 +
1404 1610 // For multi-select dropdowns only
1405 - if ( is_array( $field['value'] ) && ! empty( $field['value'] ) ) {
1611 + if ( is_array( $field['value'] ) && $field['value'] ) {
1406 1612 $other_val = reset( $field['value'] );
1407 1613 }
1408 1614 }//end if
1409 1615
@@ -1419,9 +1625,9 @@
1419 1625 * @param array $args Should include field, opt_key and field name.
1420 1626 * @param bool $other_opt
1421 1627 * @param string $checked
1422 1628 *
1423 - * @return array $other_args
1629 + * @return array Other args.
1424 1630 */
1425 1631 public static function prepare_other_input( $args, &$other_opt, &$checked ) {
1426 1632 $other_args = array(
1427 1633 'name' => '',
@@ -1456,10 +1662,13 @@
1456 1662 }
1457 1663
1458 1664 /**
1459 1665 * @since 2.0.6
1666 + *
1460 1667 * @param array $args
1461 1668 * @param array $other_args
1669 + *
1670 + * @return void
1462 1671 */
1463 1672 private static function set_other_name( $args, &$other_args ) {
1464 1673 // Set up name for other field
1465 1674 $other_args['name'] = str_replace( '[]', '', $args['field_name'] );
@@ -1476,10 +1685,13 @@
1476 1685 /**
1477 1686 * Find the parent and pointer, and get text for "other" text field
1478 1687 *
1479 1688 * @since 2.0.6
1689 + *
1480 1690 * @param array $args
1481 1691 * @param array $other_args
1692 + *
1693 + * @return void
1482 1694 */
1483 1695 private static function set_other_value( $args, &$other_args ) {
1484 1696 $parent = '';
1485 1697 $pointer = '';
@@ -1507,9 +1719,12 @@
1507 1719 /**
1508 1720 * If this field includes an other option, show it
1509 1721 *
1510 1722 * @since 2.0.6
1723 + *
1511 1724 * @param array $args
1725 + *
1726 + * @return void
1512 1727 */
1513 1728 public static function include_other_input( $args ) {
1514 1729 if ( ! $args['other_opt'] ) {
1515 1730 return;
@@ -1515,12 +1730,14 @@
1515 1730 return;
1516 1731 }
1517 1732
1518 1733 $classes = array( 'frm_other_input' );
1519 - if ( ! $args['checked'] || trim( $args['checked'] ) == '' ) {
1520 - // hide the field if the other option is not selected
1734 +
1735 + if ( ! $args['checked'] || trim( $args['checked'] ) === '' ) {
1736 + // Hide the field if the other option is not selected
1521 1737 $classes[] = 'frm_pos_none';
1522 1738 }
1739 +
1523 1740 if ( $args['field']['type'] === 'select' && ! empty( $args['field']['multiple'] ) ) {
1524 1741 $classes[] = 'frm_other_full';
1525 1742 }
1526 1743
@@ -1528,8 +1745,9 @@
1528 1745 $other_id = self::get_other_field_html_id( $args['field']['type'], $args['html_id'], $args['opt_key'] );
1529 1746
1530 1747 $label = $args['opt_label'] ?? $args['field']['name'];
1531 1748
1749 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
1532 1750 echo '<label for="' . esc_attr( $other_id ) . '" class="frm_screen_reader frm_hidden">' .
1533 1751 esc_html( $label ) .
1534 1752 '</label>' .
1535 1753 '<input type="text" id="' . esc_attr( $other_id ) . '" class="' . esc_attr( implode( ' ', $classes ) ) . '" ' .
@@ -1534,8 +1752,9 @@
1534 1752 '</label>' .
1535 1753 '<input type="text" id="' . esc_attr( $other_id ) . '" class="' . esc_attr( implode( ' ', $classes ) ) . '" ' .
1536 1754 ( $args['read_only'] ? ' readonly="readonly" disabled="disabled"' : '' ) .
1537 1755 ' name="' . esc_attr( $args['name'] ) . '" value="' . esc_attr( $args['value'] ) . '" />';
1756 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
1538 1757 }
1539 1758
1540 1759 /**
1541 1760 * Get the HTML id for an "Other" text field
@@ -1546,9 +1765,9 @@
1546 1765 * @param string $type Field type.
1547 1766 * @param string $html_id
1548 1767 * @param bool|string $opt_key
1549 1768 *
1550 - * @return string $other_id
1769 + * @return string Other ID.
1551 1770 */
1552 1771 public static function get_other_field_html_id( $type, $html_id, $opt_key = false ) {
1553 1772 $other_id = $html_id;
1554 1773
@@ -1560,17 +1779,21 @@
1560 1779 if ( $opt_key !== false ) {
1561 1780 $other_id .= '-' . $opt_key;
1562 1781 }
1563 1782
1564 - $other_id .= '-otext';
1565 -
1566 - return $other_id;
1783 + return $other_id . '-otext';
1567 1784 }
1568 1785
1786 + /**
1787 + * @param array|string $val
1788 + *
1789 + * @return array|string
1790 + */
1569 1791 public static function switch_field_ids( $val ) {
1570 1792 global $frm_duplicate_ids;
1571 1793 $replace = array();
1572 1794 $replace_with = array();
1795 +
1573 1796 foreach ( (array) $frm_duplicate_ids as $old => $new ) {
1574 1797 $replace[] = '[if ' . $old . ']';
1575 1798 $replace_with[] = '[if ' . $new . ']';
1576 1799 $replace[] = '[if ' . $old . ' ';
@@ -1597,22 +1820,26 @@
1597 1820 $replace[] = '_field":"' . $old . '","';
1598 1821 $replace_with[] = '_field":"' . $new . '","';
1599 1822 unset( $old, $new );
1600 1823 }//end foreach
1601 - if ( is_array( $val ) ) {
1602 - foreach ( $val as $k => $v ) {
1603 - if ( is_string( $v ) ) {
1604 - if ( 'custom_html' === $k ) {
1605 - $val[ $k ] = self::switch_ids_except_strings( $replace, $replace_with, array( '[if description]', '[description]', '[/if description]' ), $v );
1606 - unset( $k, $v );
1607 - continue;
1608 - }
1609 - $val[ $k ] = str_replace( $replace, $replace_with, $v );
1610 - unset( $k, $v );
1611 - }
1824 +
1825 + if ( ! is_array( $val ) ) {
1826 + return str_replace( $replace, $replace_with, $val );
1827 + }
1828 +
1829 + foreach ( $val as $k => $v ) {
1830 + if ( ! is_string( $v ) ) {
1831 + continue;
1612 1832 }
1613 - } else {
1614 - $val = str_replace( $replace, $replace_with, $val );
1833 +
1834 + if ( 'custom_html' === $k ) {
1835 + $val[ $k ] = self::switch_ids_except_strings( $replace, $replace_with, array( '[if description]', '[description]', '[/if description]' ), $v );
1836 + unset( $k, $v );
1837 + continue;
1838 + }
1839 +
1840 + $val[ $k ] = str_replace( $replace, $replace_with, $v );
1841 + unset( $k, $v );
1615 1842 }
1616 1843
1617 1844 return $val;
1618 1845 }
@@ -1631,8 +1858,9 @@
1631 1858 */
1632 1859 private static function switch_ids_except_strings( $replace, $replace_with, $exceptions, $value ) {
1633 1860 foreach ( $exceptions as $exception ) {
1634 1861 $index = array_search( $exception, $replace, true );
1862 +
1635 1863 if ( false === $index ) {
1636 1864 continue;
1637 1865 }
1638 1866 unset( $replace[ $index ] );
@@ -1637,14 +1865,16 @@
1637 1865 }
1638 1866 unset( $replace[ $index ] );
1639 1867 unset( $replace_with[ $index ] );
1640 1868 }
1641 - $value = str_replace( $replace, $replace_with, $value );
1642 - return $value;
1869 +
1870 + return str_replace( $replace, $replace_with, $value );
1643 1871 }
1644 1872
1645 1873 /**
1646 1874 * @since 4.0
1875 + *
1876 + * @return void
1647 1877 */
1648 1878 public static function bulk_options_overlay() {
1649 1879 $prepop = array();
1650 1880 self::get_bulk_prefilled_opts( $prepop, true );
@@ -1651,8 +1881,11 @@
1651 1881
1652 1882 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/bulk-options-overlay.php';
1653 1883 }
1654 1884
1885 + /**
1886 + * @return array
1887 + */
1655 1888 public static function get_us_states() {
1656 1889 $states = array(
1657 1890 'AL' => 'Alabama',
1658 1891 'AK' => 'Alaska',
@@ -1709,8 +1942,11 @@
1709 1942
1710 1943 return apply_filters( 'frm_us_states', $states );
1711 1944 }
1712 1945
1946 + /**
1947 + * @return array
1948 + */
1713 1949 public static function get_countries() {
1714 1950 $countries = array(
1715 1951 __( 'Afghanistan', 'formidable' ),
1716 1952 __( 'Aland Islands', 'formidable' ),
@@ -1975,12 +2211,15 @@
1975 2211 * @since 5.0.04 Add `$include_class` param.
1976 2212 *
1977 2213 * @param array $prepop Bulk options.
1978 2214 * @param array|false $include_class Include the class in the bulk options.
2215 + *
2216 + * @return void
1979 2217 */
1980 2218 public static function get_bulk_prefilled_opts( array &$prepop, $include_class = false ) {
1981 2219 // Countries.
1982 2220 $countries = self::get_countries();
2221 +
1983 2222 if ( $include_class ) {
1984 2223 $countries['class'] = 'frm-countries-opts';
1985 2224 }
1986 2225
@@ -1989,8 +2228,9 @@
1989 2228 // State abv.
1990 2229 $states = self::get_us_states();
1991 2230 $state_abv = array_keys( $states );
1992 2231 sort( $state_abv );
2232 +
1993 2233 if ( $include_class ) {
1994 2234 $state_abv['class'] = 'frm-state-abv-opts';
1995 2235 }
1996 2236
@@ -1998,8 +2238,9 @@
1998 2238
1999 2239 // States.
2000 2240 $states = array_values( $states );
2001 2241 sort( $states );
2242 +
2002 2243 if ( $include_class ) {
2003 2244 $states['class'] = 'frm-states-opts';
2004 2245 }
2005 2246
@@ -2016,8 +2257,9 @@
2016 2257 __( '55-64', 'formidable' ),
2017 2258 __( '65 or Above', 'formidable' ),
2018 2259 __( 'Prefer Not to Answer', 'formidable' ),
2019 2260 );
2261 +
2020 2262 if ( $include_class ) {
2021 2263 $ages['class'] = 'frm-age-opts';
2022 2264 }
2023 2265
@@ -2031,8 +2273,9 @@
2031 2273 __( 'Satisfied', 'formidable' ),
2032 2274 __( 'Very Satisfied', 'formidable' ),
2033 2275 __( 'N/A', 'formidable' ),
2034 2276 );
2277 +
2035 2278 if ( $include_class ) {
2036 2279 $satisfaction['class'] = 'frm-satisfaction-opts';
2037 2280 }
2038 2281
@@ -2046,8 +2289,9 @@
2046 2289 __( 'Important', 'formidable' ),
2047 2290 __( 'Very Important', 'formidable' ),
2048 2291 __( 'N/A', 'formidable' ),
2049 2292 );
2293 +
2050 2294 if ( $include_class ) {
2051 2295 $importance['class'] = 'frm-importance-opts';
2052 2296 }
2053 2297
@@ -2061,8 +2305,9 @@
2061 2305 __( 'Agree', 'formidable' ),
2062 2306 __( 'Strongly Agree', 'formidable' ),
2063 2307 __( 'N/A', 'formidable' ),
2064 2308 );
2309 +
2065 2310 if ( $include_class ) {
2066 2311 $agreement['class'] = 'frm-agreement-opts';
2067 2312 }
2068 2313
@@ -2076,8 +2321,9 @@
2076 2321 __( 'Likely', 'formidable' ),
2077 2322 __( 'Extremely Likely', 'formidable' ),
2078 2323 __( 'N/A', 'formidable' ),
2079 2324 );
2325 +
2080 2326 if ( $include_class ) {
2081 2327 $likely['class'] = 'frm-likely-opts';
2082 2328 }
2083 2329
@@ -2092,8 +2338,10 @@
2092 2338 * @since 2.03.05
2093 2339 *
2094 2340 * @param int $selector_field_id
2095 2341 * @param array $selector_args
2342 + *
2343 + * @return void
2096 2344 */
2097 2345 public static function display_field_value_selector( $selector_field_id, $selector_args ) {
2098 2346 $field_value_selector = FrmFieldFactory::create_field_value_selector( $selector_field_id, $selector_args );
2099 2347 $field_value_selector->display();
@@ -2116,11 +2364,43 @@
2116 2364 return $field_array + $field_options;
2117 2365 }
2118 2366
2119 2367 /**
2368 + * Shows add field link.
2369 + *
2370 + * @since 6.30
2371 + *
2372 + * @param array $field_type See file `classes/views/frm-forms/add_field_links.php`.
2373 + *
2374 + * @return void
2375 + */
2376 + public static function show_add_field_link( $field_type ) {
2377 + $field_label = FrmFormsHelper::get_field_link_name( $field_type );
2378 + $classes = 'frmbutton frm6 frm_t' . $field_type['key'];
2379 +
2380 + if ( ! empty( $field_type['hide'] ) ) {
2381 + $classes .= ' frm_hidden';
2382 + }
2383 + ?>
2384 +<li class="<?php echo esc_attr( $classes ); ?>" id="<?php echo esc_attr( $field_type['key'] ); ?>">
2385 + <a href="#" class="frm_add_field" title="<?php echo esc_attr( $field_label ); ?>" role="button" aria-label="<?php echo esc_attr( $field_label ); ?>">
2386 + <?php FrmAppHelper::icon_by_class( FrmFormsHelper::get_field_link_icon( $field_type ) ); ?>
2387 + <span><?php echo esc_html( $field_label ); ?></span>
2388 + <?php
2389 + if ( 'credit_card' === $field_type['key'] && ! FrmTransLiteAppHelper::payments_table_exists() ) {
2390 + FrmAppHelper::show_pill_text();
2391 + }
2392 + ?>
2393 + </a>
2394 +</li>
2395 + <?php
2396 + }
2397 +
2398 + /**
2120 2399 * @since 4.04
2121 2400 *
2122 2401 * @param array $args
2402 + *
2123 2403 * @return void
2124 2404 */
2125 2405 public static function show_add_field_buttons( $args ) {
2126 2406 $field_key = $args['field_key'];
@@ -2135,33 +2415,25 @@
2135 2415 $field_label .= ob_get_clean();
2136 2416 }
2137 2417
2138 2418 // If the individual field isn't allowed, disable it.
2139 - $run_filter = true;
2140 - $single_no_allow = ' ';
2141 - $install_data = '';
2142 - $requires = '';
2143 - $link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
2144 - $has_show_upgrade_class = isset( $field_type['icon'] ) && strpos( $field_type['icon'], ' frm_show_upgrade' );
2145 - $show_upgrade = $has_show_upgrade_class || false !== strpos( $args['no_allow_class'], 'frm_show_upgrade' );
2419 + $link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
2146 2420
2147 - if ( $has_show_upgrade_class ) {
2148 - $single_no_allow .= 'frm_show_upgrade';
2149 - $field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
2150 - $run_filter = false;
2151 - if ( isset( $field_type['addon'] ) ) {
2152 - $upgrading = FrmAddonsController::install_link( $field_type['addon'] );
2153 - if ( isset( $upgrading['url'] ) ) {
2154 - $install_data = json_encode( $upgrading );
2155 - }
2156 - $requires = FrmFormsHelper::get_plan_required( $upgrading );
2157 - } elseif ( isset( $field_type['require'] ) ) {
2158 - $requires = $field_type['require'];
2159 - }
2160 - }
2421 + list(
2422 + $run_filter,
2423 + $single_no_allow,
2424 + $install_data,
2425 + $requires,
2426 + $has_show_upgrade_class,
2427 + $has_show_update_class,
2428 + $upgrading,
2429 + $update_addon_name
2430 + ) = self::get_field_upgrade_state( $field_type );
2161 2431
2432 + $show_upgrade = $has_show_upgrade_class || $has_show_update_class || str_contains( $args['no_allow_class'], 'frm_show_upgrade' );
2162 2433 $upgrade_label = '';
2163 2434 $upgrade_message = '';
2435 +
2164 2436 if ( $show_upgrade ) {
2165 2437 /* translators: %s: Field name */
2166 2438 $upgrade_label = sprintf( esc_html__( '%s fields', 'formidable' ), $field_name );
2167 2439
@@ -2184,15 +2456,41 @@
2184 2456 if ( ! empty( $field_type['hide'] ) ) {
2185 2457 $li_params['class'] .= ' frm_hidden';
2186 2458 }
2187 2459
2460 + if ( ! $show_upgrade && ! empty( $field_type['limit'] ) ) {
2461 + $li_params = self::update_params_with_limit_data( $li_params, $args['id'], $field_key, $field_type['limit'] );
2462 + }
2463 +
2188 2464 if ( ! empty( $field_type['upsell_image'] ) ) {
2189 2465 $li_params['data-upsell-image'] = $field_type['upsell_image'];
2190 2466 }
2191 2467
2192 - if ( $upgrade_message ) {
2468 + if ( ! empty( $field_type['learn-more'] ) ) {
2469 + $li_params['data-learn-more'] = FrmAppHelper::get_doc_url(
2470 + $field_type['learn-more'],
2471 + 'form-builder-add-fields',
2472 + str_contains( $field_type['learn-more'], '/' )
2473 + );
2474 + }
2475 +
2476 + if ( $has_show_update_class ) {
2477 + $li_params['data-message'] = sprintf(
2478 + // translators: %1$s: Add-on name, %2$s: Field type name.
2479 + esc_html__( 'You need a newer version of %1$s for %2$s fields.', 'formidable' ),
2480 + $update_addon_name,
2481 + $field_name
2482 + );
2483 + } elseif ( isset( $upgrading['url'] ) ) {
2484 + $li_params['data-message'] = sprintf(
2485 + // translators: %s: Field name
2486 + esc_html__( 'You already have access to %s fields, you\'ll just need to activate to start using them.', 'formidable' ),
2487 + $field_name
2488 + );
2489 + } elseif ( $upgrade_message ) {
2193 2490 $li_params['data-message'] = $upgrade_message;
2194 2491 }
2492 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
2195 2493 ?>
2196 2494 <li <?php FrmAppHelper::array_to_html_params( $li_params, true ); ?>>
2197 2495 <?php
2198 2496 if ( $run_filter ) {
@@ -2197,26 +2495,130 @@
2197 2495 <?php
2198 2496 if ( $run_filter ) {
2199 2497 $field_label = apply_filters( 'frmpro_field_links', $field_label, $args['id'], $field_key );
2200 2498 }
2499 +
2201 2500 FrmAppHelper::kses_echo( $field_label, array( 'a', 'i', 'span', 'use', 'svg' ) );
2202 2501 ?>
2203 2502 </li>
2204 2503 <?php
2504 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
2205 2505 }
2206 2506
2207 2507 /**
2508 + * Parse the upgrade and update flags from a field type's icon class.
2509 + *
2510 + * @since 6.29
2511 + *
2512 + * @param array $field_type Field type configuration, modified in place to strip icon flag classes.
2513 + *
2514 + * @return array Upgrade and update state values for the field button, in positional order.
2515 + */
2516 + private static function get_field_upgrade_state( &$field_type ) {
2517 + $single_no_allow = ' ';
2518 + $run_filter = true;
2519 + $has_show_upgrade_class = false;
2520 + $has_show_update_class = false;
2521 + $install_data = '';
2522 + $requires = '';
2523 + $upgrading = array();
2524 + $update_addon_name = '';
2525 +
2526 + if ( isset( $field_type['icon'] ) ) {
2527 + $has_show_upgrade_class = str_contains( $field_type['icon'], ' frm_show_upgrade' );
2528 + $has_show_update_class = str_contains( $field_type['icon'], ' frm_show_update' );
2529 + }
2530 +
2531 + if ( $has_show_upgrade_class ) {
2532 + $single_no_allow .= 'frm_show_upgrade';
2533 + $field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
2534 + $run_filter = false;
2535 +
2536 + if ( isset( $field_type['addon'] ) ) {
2537 + $upgrading = FrmAddonsController::install_link( $field_type['addon'] );
2538 +
2539 + if ( isset( $upgrading['url'] ) ) {
2540 + $install_data = json_encode( $upgrading );
2541 + }
2542 +
2543 + $requires = FrmFormsHelper::get_plan_required( $upgrading );
2544 + } elseif ( isset( $field_type['require'] ) ) {
2545 + $requires = $field_type['require'];
2546 + }
2547 + }
2548 +
2549 + if ( $has_show_update_class ) {
2550 + $single_no_allow .= ' frm_show_update';
2551 + $field_type['icon'] = str_replace( ' frm_show_update', '', $field_type['icon'] );
2552 + $run_filter = false;
2553 + $addon_slug = $field_type['addon'] ?? 'pro';
2554 +
2555 + if ( 'pro' === $addon_slug ) {
2556 + $update_addon_name = __( 'Formidable Pro', 'formidable' );
2557 + } else {
2558 + $addon_data = FrmAddonsController::get_addon( $addon_slug );
2559 + $update_addon_name = $addon_data && ! empty( $addon_data['title'] ) ? $addon_data['title'] : ucfirst( $addon_slug );
2560 + }
2561 +
2562 + $install_data = FrmAddonsController::get_update_install_data( $addon_slug );
2563 + }
2564 +
2565 + return array(
2566 + $run_filter,
2567 + $single_no_allow,
2568 + $install_data,
2569 + $requires,
2570 + $has_show_upgrade_class,
2571 + $has_show_update_class,
2572 + $upgrading,
2573 + $update_addon_name,
2574 + );
2575 + }
2576 +
2577 + /**
2578 + * Updates the params with limit data (the data-limit attribute, and possibly the frm_at_limit class).
2579 + * Some field types are limited to a certain number per form, including coupon fields.
2580 + *
2581 + * @since 6.27
2582 + *
2583 + * @param array $li_params The params.
2584 + * @param int $form_id The form ID.
2585 + * @param string $field_type The field type.
2586 + * @param int $limit The limit.
2587 + *
2588 + * @return array The updated params.
2589 + */
2590 + private static function update_params_with_limit_data( $li_params, $form_id, $field_type, $limit ) {
2591 + $fields_in_form = FrmDb::get_count(
2592 + 'frm_fields',
2593 + array(
2594 + 'form_id' => $form_id,
2595 + 'type' => $field_type,
2596 + )
2597 + );
2598 +
2599 + if ( $fields_in_form >= $limit ) {
2600 + $li_params['class'] .= ' frm_at_limit';
2601 + }
2602 +
2603 + $li_params['data-limit'] = $limit;
2604 +
2605 + return $li_params;
2606 + }
2607 +
2608 + /**
2208 2609 * Shows Display format option.
2209 2610 *
2210 2611 * @since 5.0.04
2211 2612 *
2212 2613 * @param array $field Field data.
2614 + *
2615 + * @return void
2213 2616 */
2214 2617 public static function show_radio_display_format( $field ) {
2215 2618 $options = self::get_display_format_options( $field );
2619 + $args = self::get_display_format_args( $field, $options );
2216 2620
2217 - $args = self::get_display_format_args( $field, $options );
2218 -
2219 2621 include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/radio-display-format.php';
2220 2622 }
2221 2623
2222 2624 /**
@@ -2238,9 +2640,9 @@
2238 2640 'text' => __( 'Images', 'formidable' ),
2239 2641 'svg' => 'frm_image_as_option',
2240 2642 'addon' => 'pro',
2241 2643 'upgrade' => __( 'Image Options', 'formidable' ),
2242 - '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" />',
2644 + '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" />', // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
2243 2645 'content' => 'image-options',
2244 2646 ),
2245 2647 'buttons' => array(
2246 2648 'text' => __( 'Buttons', 'formidable' ),
@@ -2251,8 +2653,12 @@
2251 2653 'content' => 'button-options',
2252 2654 ),
2253 2655 );
2254 2656
2657 + if ( 'product' === FrmField::get_field_type( $field ) ) {
2658 + unset( $options['buttons'] );
2659 + }
2660 +
2255 2661 /**
2256 2662 * Allows modifying the options of Display format setting of Radio field.
2257 2663 *
2258 2664 * @since 5.0.04
@@ -2259,11 +2665,9 @@
2259 2665 *
2260 2666 * @param array $options Options.
2261 2667 * @param array $field
2262 2668 */
2263 - $options = apply_filters( 'frm_' . $field['type'] . '_display_format_options', $options, $field );
2264 -
2265 - return $options;
2669 + return apply_filters( 'frm_' . $field['type'] . '_display_format_options', $options, $field );
2266 2670 }
2267 2671
2268 2672 /**
2269 2673 * Gets display format arguments to pass to the images_dropdown() method.
@@ -2271,8 +2675,9 @@
2271 2675 * @since 5.0.04
2272 2676 *
2273 2677 * @param array $field Field data.
2274 2678 * @param array $options Options array.
2679 + *
2275 2680 * @return array
2276 2681 */
2277 2682 public static function get_display_format_args( $field, $options ) {
2278 2683 $args = array(
@@ -2298,8 +2703,13 @@
2298 2703 }
2299 2704
2300 2705 /**
2301 2706 * @since 5.0.04
2707 + *
2708 + * @param array $options Options.
2709 + * @param array $args Arguments.
2710 + *
2711 + * @return void
2302 2712 */
2303 2713 private static function fill_image_setting_options( $options, &$args ) {
2304 2714 foreach ( $options as $key => $option ) {
2305 2715 $args['options'][ $key ] = $option;
@@ -2309,8 +2719,9 @@
2309 2719 }
2310 2720
2311 2721 unset( $args['options'][ $key ]['addon'] );
2312 2722 $fill = array( 'upgrade', 'message', 'content' );
2723 +
2313 2724 foreach ( $fill as $f ) {
2314 2725 unset( $args['options'][ $key ][ $f ], $f );
2315 2726 }
2316 2727 }
@@ -2318,8 +2729,10 @@
2318 2729
2319 2730 /**
2320 2731 * @since 5.0.04
2321 2732 *
2733 + * @param array $option Option.
2734 + *
2322 2735 * @return array
2323 2736 */
2324 2737 private static function fill_image_setting_addon_link( $option ) {
2325 2738 $custom_attrs = array(
@@ -2330,8 +2743,9 @@
2330 2743 // translators: Add-on name.
2331 2744 $custom_attrs['data-upgrade'] = sprintf( __( 'Formidable %s', 'formidable' ), ucwords( $option['addon'] ) );
2332 2745
2333 2746 $fill = array( 'upgrade', 'message', 'content' );
2747 +
2334 2748 foreach ( $fill as $f ) {
2335 2749 if ( isset( $option[ $f ] ) ) {
2336 2750 $custom_attrs[ 'data-' . $f ] = $option[ $f ];
2337 2751 }
@@ -2341,15 +2755,10 @@
2341 2755 return $custom_attrs;
2342 2756 }
2343 2757
2344 2758 $upgrading = FrmAddonsController::install_link( $option['addon'] );
2345 - if ( isset( $upgrading['url'] ) ) {
2346 - $install_data = wp_json_encode( $upgrading );
2347 - } else {
2348 - $install_data = '';
2349 - }
2350 2759
2351 - $custom_attrs['data-oneclick'] = $install_data;
2760 + $custom_attrs['data-oneclick'] = isset( $upgrading['url'] ) ? wp_json_encode( $upgrading ) : '';
2352 2761 $custom_attrs['data-requires'] = FrmFormsHelper::get_plan_required( $upgrading );
2353 2762
2354 2763 return $custom_attrs;
2355 2764 }
@@ -2362,8 +2771,9 @@
2362 2771 * @since 6.2
2363 2772 *
2364 2773 * @param mixed $value
2365 2774 * @param string $field_type
2775 + *
2366 2776 * @return void
2367 2777 */
2368 2778 public static function prepare_field_value( &$value, $field_type ) {
2369 2779 $field_object = FrmFieldFactory::get_field_type( $field_type );
@@ -2374,8 +2784,9 @@
2374 2784 * @since 6.8
2375 2785 *
2376 2786 * @param int|string $form_id
2377 2787 * @param array $field_ids If this is not empty, the results will be filtered by field id.
2788 + *
2378 2789 * @return array
2379 2790 */
2380 2791 public static function get_draft_field_results( $form_id, $field_ids = array() ) {
2381 2792 if ( FrmAppHelper::pro_is_installed() ) {
@@ -2412,8 +2823,9 @@
2412 2823 *
2413 2824 * @since 6.8
2414 2825 *
2415 2826 * @param int|string $form_id
2827 + *
2416 2828 * @return array
2417 2829 */
2418 2830 public static function get_all_draft_field_ids( $form_id ) {
2419 2831 $draft_field_rows = self::get_draft_field_results( $form_id );
@@ -2426,13 +2838,19 @@
2426 2838 * @since 6.24
2427 2839 *
2428 2840 * @param array $args Field arguments.
2429 2841 * @param bool $should_hide_bulk_edit Whether to hide bulk edit.
2842 + *
2843 + * @return void
2430 2844 */
2431 2845 public static function render_ai_generate_options_button( $args, $should_hide_bulk_edit = false ) {
2432 - $attributes = array( 'class' => self::get_ai_generate_options_button_class() );
2846 + $attributes = array(
2847 + 'type' => 'button',
2848 + );
2433 2849
2434 - if ( ! empty( $should_hide_bulk_edit ) ) {
2850 + $attributes['class'] = ! empty( $args['class'] ) ? $args['class'] : self::get_ai_generate_options_button_class();
2851 +
2852 + if ( $should_hide_bulk_edit ) {
2435 2853 $attributes['class'] .= ' frm-force-hidden';
2436 2854 }
2437 2855
2438 2856 $data = FrmAppHelper::get_upgrade_data_params(
@@ -2438,9 +2856,9 @@
2438 2856 $data = FrmAppHelper::get_upgrade_data_params(
2439 2857 'ai',
2440 2858 array(
2441 2859 'requires' => 'Business',
2442 - 'upgrade' => __( 'Generate options with AI', 'formidable' ),
2860 + 'upgrade' => $args['upgrade_text'] ?? __( 'Generate options with AI', 'formidable' ),
2443 2861 'medium' => 'builder',
2444 2862 'content' => 'generate-options-with-ai',
2445 2863 ),
2446 2864 true
@@ -2447,21 +2865,22 @@
2447 2865 );
2448 2866
2449 2867 if ( in_array( FrmAddonsController::license_type(), array( 'elite', 'business' ), true ) && 'active' === $data['plugin-status'] ) {
2450 2868 // Backwards compatibility "@since 6.24".
2451 - if ( ! method_exists( 'FrmAIAppController', 'get_ai_generated_options_summary' ) ) {
2869 + if ( method_exists( 'FrmAIAppController', 'get_ai_generated_options_summary' ) ) {
2870 + $attributes['class'] .= ' frm-ai-generate-options-modal-trigger';
2871 + $attributes['data-fid'] = $args['likert_id'] ?? $args['field']['id'];
2872 + } else {
2452 2873 $data = array(
2453 2874 'modal-title' => __( 'Generate options with AI', 'formidable' ),
2454 2875 'modal-content' => __( 'Update the Formidable AI add-on to the last version to use this feature.', 'formidable' ),
2455 2876 );
2456 - } else {
2457 - $attributes['class'] .= ' frm-ai-generate-options-modal-trigger';
2458 - $attributes['data-fid'] = $args['likert_id'] ?? $args['field']['id'];
2459 2877 }
2460 2878 }
2461 2879
2462 2880 if ( empty( $attributes['data-fid'] ) ) {
2463 2881 unset( $data['plugin-status'] );
2882 +
2464 2883 foreach ( $data as $key => $value ) {
2465 2884 $attributes[ 'data-' . $key ] = $value;
2466 2885 }
2467 2886 }
@@ -2495,6 +2914,87 @@
2495 2914 'frm-mt-xs',
2496 2915 'frm-mb-12',
2497 2916 )
2498 2917 );
2918 + }
2919 +
2920 + /**
2921 + * Checks if the field choice should be hidden due to choice limit being reached.
2922 + *
2923 + * @since 6.28
2924 + *
2925 + * @param string $choice_key
2926 + * @param array $field
2927 + *
2928 + * @return bool
2929 + */
2930 + public static function should_hide_field_choice( $choice_key, $field ) {
2931 + /**
2932 + * @since 6.28
2933 + *
2934 + * @param bool $hide_field_choice
2935 + * @param string $choice_key
2936 + * @param array $field
2937 + */
2938 + return (bool) apply_filters( 'frm_hide_field_choice', false, $choice_key, $field );
2939 + }
2940 +
2941 + /**
2942 + * @since 6.28
2943 + *
2944 + * @param array $field
2945 + *
2946 + * @return bool
2947 + */
2948 + public static function should_skip_rendering_choices_for_field( $field ) {
2949 + /**
2950 + * @since 6.28
2951 + *
2952 + * @param bool $skip_rendering_options_for_field
2953 + * @param array $field
2954 + */
2955 + return (bool) apply_filters( 'frm_should_skip_rendering_choices_for_field', false, $field );
2956 + }
2957 +
2958 + /**
2959 + * Determine if 'disabled' attribute should be echoed in a field choice's HTML.
2960 + *
2961 + * @since 6.28
2962 + *
2963 + * @param string $choice_key
2964 + * @param bool $is_selected_choice
2965 + * @param array $field
2966 + *
2967 + * @return bool
2968 + */
2969 + public static function should_disable_choice( $choice_key, $is_selected_choice, $field ) {
2970 + /**
2971 + * @since 6.28
2972 + *
2973 + * @param bool $echo_disabled_attribute
2974 + * @param string $choice_key
2975 + * @param bool $is_selected_choice
2976 + * @param array $field
2977 + */
2978 + return (bool) apply_filters( 'frm_disable_choice', false, $choice_key, $is_selected_choice, $field );
2979 + }
2980 +
2981 + /**
2982 + * @since 6.28
2983 + *
2984 + * @param array $field
2985 + * @param string $choice_key
2986 + *
2987 + * @return void
2988 + */
2989 + public static function after_choice_input( $field, $choice_key ) {
2990 + /**
2991 + * Allows adding content after checkbox, radio button, or dropdown fields.
2992 + *
2993 + * @since 6.28
2994 + *
2995 + * @param array $field The field data.
2996 + * @param string $choice_key The option key.
2997 + */
2998 + do_action( 'frm_after_choice_input', $field, $choice_key );
2499 2999 }
2500 3000 }