PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.16.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.16.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/helpers/FrmAppHelper.php +816 -350 6.36.16.1 View file →
@@ -3,27 +3,47 @@
3 3 die( 'You are not allowed to call this page directly.' );
4 4 }
5 5
6 6 class FrmAppHelper {
7 - public static $db_version = 98; // Version of the database we are moving to.
8 - public static $pro_db_version = 37; //deprecated
9 - public static $font_version = 7;
7 + /**
8 + * Version of the database we are moving to.
9 + *
10 + * @var int
11 + */
12 + public static $db_version = 101;
10 13
11 14 /**
12 - * @var bool $added_gmt_offset_filter
15 + * Deprecated.
16 + *
17 + * @var int
13 18 */
19 + public static $pro_db_version = 37;
20 +
21 + /**
22 + * @var float
23 + */
24 + public static $font_version = 7;
25 +
26 + /**
27 + * @var bool
28 + */
14 29 private static $added_gmt_offset_filter = false;
15 30
16 31 /**
17 32 * @since 2.0
33 + *
34 + * @var string
18 35 */
19 - public static $plug_version = '6.3';
36 + public static $plug_version = '6.16.1';
20 37
21 38 /**
39 + * @var bool
40 + */
41 + private static $included_svg = false;
42 +
43 + /**
22 44 * @since 1.07.02
23 45 *
24 - * @param none
25 - *
26 46 * @return string The version of this plugin
27 47 */
28 48 public static function plugin_version() {
29 49 return self::$plug_version;
@@ -28,21 +48,33 @@
28 48 public static function plugin_version() {
29 49 return self::$plug_version;
30 50 }
31 51
52 + /**
53 + * @return string
54 + */
32 55 public static function plugin_folder() {
33 56 return basename( self::plugin_path() );
34 57 }
35 58
59 + /**
60 + * @return string
61 + */
36 62 public static function plugin_path() {
37 - return dirname( dirname( dirname( __FILE__ ) ) );
63 + return dirname( dirname( __DIR__ ) );
38 64 }
39 65
66 + /**
67 + * @return string
68 + */
40 69 public static function plugin_url() {
41 - // Prevously FRM_URL constant.
70 + // Previously FRM_URL constant.
42 71 return plugins_url( '', self::plugin_path() . '/formidable.php' );
43 72 }
44 73
74 + /**
75 + * @return string
76 + */
45 77 public static function relative_plugin_url() {
46 78 return str_replace( array( 'https:', 'http:' ), '', self::plugin_url() );
47 79 }
48 80
@@ -63,8 +95,12 @@
63 95 public static function site_name() {
64 96 return get_option( 'blogname' );
65 97 }
66 98
99 + /**
100 + * @param string $url
101 + * @return string
102 + */
67 103 public static function make_affiliate_url( $url ) {
68 104 $affiliate_id = self::get_affiliate();
69 105 if ( ! empty( $affiliate_id ) ) {
70 106 $url = str_replace( array( 'http://', 'https://' ), '', $url );
@@ -73,8 +109,11 @@
73 109
74 110 return $url;
75 111 }
76 112
113 + /**
114 + * @return int
115 + */
77 116 public static function get_affiliate() {
78 117 return absint( apply_filters( 'frm_affiliate_id', 0 ) );
79 118 }
80 119
@@ -131,9 +170,9 @@
131 170 *
132 171 * @since 2.0
133 172 *
134 173 * @param array $args - May include the form id when values need translation.
135 - * @return FrmSettings $frm_setings
174 + * @return FrmSettings $frm_settings
136 175 */
137 176 public static function get_settings( $args = array() ) {
138 177 global $frm_settings;
139 178 if ( empty( $frm_settings ) ) {
@@ -145,16 +184,39 @@
145 184
146 185 return $frm_settings;
147 186 }
148 187
188 + /**
189 + * @return string
190 + */
149 191 public static function get_menu_name() {
150 192 $frm_settings = self::get_settings();
151 193
152 - return $frm_settings->menu;
194 + return FrmAddonsController::is_license_expired() ? 'Formidable' : $frm_settings->menu;
153 195 }
154 196
155 197 /**
198 + * Determine if the current branding is set to 'formidable'.
199 + * Checks the menu icon, and verifies if it matches the formidable branding.
200 + *
201 + * @since 6.4.2
202 + *
203 + * @return bool True if the menu icon is the logo, false otherwise.
204 + */
205 + public static function is_formidable_branding() {
206 + if ( ! self::pro_is_installed() ) {
207 + return true;
208 + }
209 +
210 + $menu_icon = self::get_menu_icon_class();
211 + return strpos( $menu_icon, 'frm_logo_icon' ) !== false;
212 + }
213 +
214 + /**
156 215 * @since 3.05
216 + *
217 + * @param array $atts
218 + * @return string
157 219 */
158 220 public static function svg_logo( $atts = array() ) {
159 221 $defaults = array(
160 222 'height' => 18,
@@ -171,8 +233,11 @@
171 233 }
172 234
173 235 /**
174 236 * @since 4.0
237 + *
238 + * @param array $atts
239 + * @return void
175 240 */
176 241 public static function show_logo( $atts = array() ) {
177 242 echo self::kses( self::svg_logo( $atts ), 'all' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
178 243 }
@@ -178,8 +243,10 @@
178 243 }
179 244
180 245 /**
181 246 * @since 4.03.02
247 + *
248 + * @return void
182 249 */
183 250 public static function show_header_logo() {
184 251 $icon = self::svg_logo(
185 252 array(
@@ -201,21 +268,38 @@
201 268 }
202 269
203 270 /**
204 271 * @since 2.02.04
272 + *
273 + * @return bool
205 274 */
206 275 public static function ips_saved() {
207 276 $frm_settings = self::get_settings();
208 -
209 277 return ! $frm_settings->no_ips;
210 278 }
211 279
280 + /**
281 + * @return bool
282 + */
212 283 public static function pro_is_installed() {
213 - return apply_filters( 'frm_pro_installed', false );
284 + return (bool) apply_filters( 'frm_pro_installed', false );
214 285 }
215 286
216 287 /**
288 + * Check if the Pro plugin is installed, whether authorized or not.
289 + *
290 + * @since 6.8.3
291 + *
292 + * @return bool
293 + */
294 + public static function pro_is_included() {
295 + return function_exists( 'load_formidable_pro' );
296 + }
297 +
298 + /**
217 299 * @since 4.06.02
300 + *
301 + * @return bool
218 302 */
219 303 public static function pro_is_connected() {
220 304 global $frm_vars;
221 305 return self::pro_is_installed() && $frm_vars['pro_is_authorized'];
@@ -222,8 +306,10 @@
222 306 }
223 307
224 308 /**
225 309 * @since 4.06
310 + *
311 + * @return bool
226 312 */
227 313 public static function is_form_builder_page() {
228 314 $action = self::simple_get( 'frm_action', 'sanitize_title' );
229 315 return self::is_admin_page( 'formidable' ) && ( $action === 'edit' || $action === 'settings' || $action === 'duplicate' );
@@ -228,8 +314,11 @@
228 314 $action = self::simple_get( 'frm_action', 'sanitize_title' );
229 315 return self::is_admin_page( 'formidable' ) && ( $action === 'edit' || $action === 'settings' || $action === 'duplicate' );
230 316 }
231 317
318 + /**
319 + * @return bool
320 + */
232 321 public static function is_formidable_admin() {
233 322 $page = self::simple_get( 'page', 'sanitize_title' );
234 323 $is_formidable = strpos( $page, 'formidable' ) !== false;
235 324 if ( empty( $page ) ) {
@@ -243,11 +332,11 @@
243 332 * Check for certain page in Formidable settings
244 333 *
245 334 * @since 2.0
246 335 *
247 - * @param string $page The name of the page to check
336 + * @param string $page The name of the page to check.
248 337 *
249 - * @return boolean
338 + * @return bool
250 339 */
251 340 public static function is_admin_page( $page = 'formidable' ) {
252 341 global $pagenow;
253 342 $get_page = self::simple_get( 'page', 'sanitize_title' );
@@ -266,8 +355,10 @@
266 355 * If the current page is for editing or creating a view.
267 356 * Returns false for the views listing page.
268 357 *
269 358 * @since 4.0
359 + *
360 + * @return bool
270 361 */
271 362 public static function is_view_builder_page() {
272 363 global $pagenow;
273 364
@@ -277,10 +368,10 @@
277 368
278 369 $post_type = self::simple_get( 'post_type', 'sanitize_title' );
279 370
280 371 if ( empty( $post_type ) ) {
281 - $post_id = self::simple_get( 'post', 'absint' );
282 - $post = get_post( $post_id );
372 + $post_id = self::simple_get( 'post', 'absint' );
373 + $post = get_post( $post_id );
283 374 $post_type = $post ? $post->post_type : '';
284 375 }
285 376
286 377 return $post_type === 'frm_display';
@@ -290,17 +381,15 @@
290 381 * Check for the form preview page
291 382 *
292 383 * @since 2.0
293 384 *
294 - * @param None
295 - *
296 - * @return boolean
385 + * @return bool
297 386 */
298 387 public static function is_preview_page() {
299 388 global $pagenow;
300 389 $action = self::simple_get( 'action', 'sanitize_title' );
301 390
302 - return $pagenow && $pagenow == 'admin-ajax.php' && $action == 'frm_forms_preview';
391 + return $pagenow && $pagenow === 'admin-ajax.php' && $action === 'frm_forms_preview';
303 392 }
304 393
305 394 /**
306 395 * Check for ajax except the form preview page
@@ -306,16 +395,17 @@
306 395 * Check for ajax except the form preview page
307 396 *
308 397 * @since 2.0
309 398 *
310 - * @param None
311 - *
312 - * @return boolean
399 + * @return bool
313 400 */
314 401 public static function doing_ajax() {
315 402 return wp_doing_ajax() && ! self::is_preview_page();
316 403 }
317 404
405 + /**
406 + * @return string
407 + */
318 408 public static function js_suffix() {
319 409 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
320 410 }
321 411
@@ -320,13 +410,13 @@
320 410 }
321 411
322 412 /**
323 413 * @since 2.0.8
414 + * @return bool
324 415 */
325 416 public static function prevent_caching() {
326 417 global $frm_vars;
327 -
328 - return isset( $frm_vars['prevent_caching'] ) && $frm_vars['prevent_caching'];
418 + return ! empty( $frm_vars['prevent_caching'] );
329 419 }
330 420
331 421 /**
332 422 * Check if on an admin page
@@ -332,9 +422,9 @@
332 422 * Check if on an admin page
333 423 *
334 424 * @since 2.0
335 425 *
336 - * @return boolean
426 + * @return bool
337 427 */
338 428 public static function is_admin() {
339 429 $is_admin = is_admin() && ! wp_doing_ajax();
340 430
@@ -349,17 +439,22 @@
349 439 * Check if value contains blank value or empty array
350 440 *
351 441 * @since 2.0
352 442 *
353 - * @param mixed $value - value to check
354 - * @param string
443 + * @param mixed $value Value to check.
444 + * @param string $empty
355 445 *
356 - * @return boolean
446 + * @return bool
357 447 */
358 448 public static function is_empty_value( $value, $empty = '' ) {
359 449 return ( is_array( $value ) && empty( $value ) ) || $value === $empty;
360 450 }
361 451
452 + /**
453 + * @param mixed $value
454 + * @param string $empty
455 + * @return bool
456 + */
362 457 public static function is_not_empty_value( $value, $empty = '' ) {
363 458 return ! self::is_empty_value( $value, $empty );
364 459 }
365 460
@@ -376,8 +471,28 @@
376 471 return isset( $_SERVER[ $value ] ) ? wp_strip_all_tags( wp_unslash( $_SERVER[ $value ] ) ) : '';
377 472 }
378 473
379 474 /**
475 + * Get the server OS
476 + *
477 + * @since 6.4.2
478 + *
479 + * @return string
480 + */
481 + public static function get_server_os() {
482 + if ( function_exists( 'php_uname' ) ) {
483 + return php_uname( 's' );
484 + }
485 +
486 + if ( ! defined( 'PHP_OS' ) ) {
487 + return '';
488 + }
489 +
490 + // match the same response for Windows server as php_uname('s')
491 + return in_array( PHP_OS, array( 'WIN32', 'WINNT', 'Windows_NT' ), true ) ? 'Windows NT' : PHP_OS;
492 + }
493 +
494 + /**
380 495 * Check for the IP address in several places (when custom headers are enabled).
381 496 * Used by [ip] shortcode.
382 497 *
383 498 * @return string The IP address of the current user
@@ -392,9 +507,10 @@
392 507 }
393 508
394 509 $key = self::get_server_value( $key );
395 510 foreach ( explode( ',', $key ) as $ip ) {
396 - $ip = trim( $ip ); // Just to be safe.
511 + // Just to be safe.
512 + $ip = trim( $ip );
397 513
398 514 if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
399 515 return sanitize_text_field( $ip );
400 516 }
@@ -485,15 +601,24 @@
485 601
486 602 return $value;
487 603 }
488 604
605 + /**
606 + * Get a value from $_POST data.
607 + *
608 + * @param string $param The key we are trying to access data from in $_POST.
609 + * @param mixed $default The default if nothing is being sent.
610 + * @param callable|string $sanitize Make sure to pass a sanitize method here. This function will NOT sanitize by default.
611 + * @param bool $serialized
612 + * @return mixed
613 + */
489 614 public static function get_post_param( $param, $default = '', $sanitize = '', $serialized = false ) {
490 615 return self::get_simple_request(
491 616 array(
492 - 'type' => 'post',
493 - 'param' => $param,
494 - 'default' => $default,
495 - 'sanitize' => $sanitize,
617 + 'type' => 'post',
618 + 'param' => $param,
619 + 'default' => $default,
620 + 'sanitize' => $sanitize,
496 621 'serialized' => $serialized,
497 622 )
498 623 );
499 624 }
@@ -504,9 +629,9 @@
504 629 * @param string $param
505 630 * @param string $sanitize
506 631 * @param string $default
507 632 *
508 - * @return string|array
633 + * @return array|string
509 634 */
510 635 public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
511 636 return self::get_simple_request(
512 637 array(
@@ -524,27 +649,27 @@
524 649 * @since 2.0.6
525 650 *
526 651 * @param array $args
527 652 *
528 - * @return string|array
653 + * @return array|string
529 654 */
530 655 public static function get_simple_request( $args ) {
531 656 $defaults = array(
532 - 'param' => '',
533 - 'default' => '',
534 - 'type' => 'get',
535 - 'sanitize' => 'sanitize_text_field',
657 + 'param' => '',
658 + 'default' => '',
659 + 'type' => 'get',
660 + 'sanitize' => 'sanitize_text_field',
536 661 'serialized' => false,
537 662 );
538 663 $args = wp_parse_args( $args, $defaults );
539 664
540 665 $value = $args['default'];
541 - if ( $args['type'] == 'get' ) {
666 + if ( $args['type'] === 'get' ) {
542 667 if ( $_GET && isset( $_GET[ $args['param'] ] ) ) {
543 668 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
544 669 $value = wp_unslash( $_GET[ $args['param'] ] );
545 670 }
546 - } elseif ( $args['type'] == 'post' ) {
671 + } elseif ( $args['type'] === 'post' ) {
547 672 if ( isset( $_POST[ $args['param'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
548 673 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
549 674 $value = wp_unslash( $_POST[ $args['param'] ] );
550 675 if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
@@ -550,13 +675,12 @@
550 675 if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
551 676 self::unserialize_or_decode( $value );
552 677 }
553 678 }
554 - } else {
555 - if ( isset( $_REQUEST[ $args['param'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
679 + } elseif ( isset( $_REQUEST[ $args['param'] ] ) ) {
680 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
556 681 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
557 682 $value = wp_unslash( $_REQUEST[ $args['param'] ] );
558 - }
559 683 }
560 684
561 685 self::sanitize_value( $args['sanitize'], $value );
562 686
@@ -580,19 +704,35 @@
580 704
581 705 return $value;
582 706 }
583 707
708 + /**
709 + * Sanitize a value in-place.
710 + * If $value is an array, the sanitize function will get called for each item.
711 + *
712 + * @param callable $sanitize
713 + * @param mixed $value
714 + * @return void
715 + */
584 716 public static function sanitize_value( $sanitize, &$value ) {
585 - if ( ! empty( $sanitize ) ) {
586 - if ( is_array( $value ) ) {
587 - $temp_values = $value;
588 - foreach ( $temp_values as $k => $v ) {
589 - self::sanitize_value( $sanitize, $value[ $k ] );
590 - }
591 - } else {
592 - $value = call_user_func( $sanitize, $value );
717 + if ( ! $sanitize ) {
718 + return;
719 + }
720 +
721 + if ( is_object( $value ) ) {
722 + $value = '';
723 + return;
724 + }
725 +
726 + if ( is_array( $value ) ) {
727 + $temp_values = $value;
728 + foreach ( $temp_values as $k => $v ) {
729 + self::sanitize_value( $sanitize, $value[ $k ] );
593 730 }
731 + return;
594 732 }
733 +
734 + $value = call_user_func( $sanitize, $value );
595 735 }
596 736
597 737 public static function sanitize_request( $sanitize_method, &$values ) {
598 738 $temp_values = $values;
@@ -604,15 +744,52 @@
604 744 }
605 745
606 746 /**
607 747 * @since 4.0.04
748 + *
749 + * @param mixed $value
750 + * @return void
608 751 */
609 752 public static function sanitize_with_html( &$value ) {
610 - self::sanitize_value( 'wp_kses_post', $value );
753 + if ( current_user_can( 'frm_edit_entries' ) || current_user_can( 'administrator' ) ) {
754 + // Only strip unsafe HTML like scripts for a privileged user submitting a form.
755 + self::sanitize_value( 'wp_kses_post', $value );
756 + } else {
757 + self::sanitize_value( self::class . '::strip_most_html', $value );
758 + }
611 759 self::decode_specialchars( $value );
612 760 }
613 761
614 762 /**
763 + * Allow only a small set of very basic HTML for unprivileged users.
764 + *
765 + * @since 6.7.1
766 + *
767 + * @param string $value
768 + */
769 + public static function strip_most_html( $value ) {
770 + $allowed_html = array(
771 + 'b' => array(),
772 + 'br' => array(),
773 + 'strong' => array(),
774 + 'p' => array(),
775 + 'i' => array(),
776 + 'ul' => array(),
777 + 'ol' => array(),
778 + 'li' => array(),
779 + );
780 +
781 + /**
782 + * @since 6.7.1
783 + *
784 + * @param array $allowed_html
785 + */
786 + $allowed_html = apply_filters( 'frm_allowed_form_input_html', $allowed_html );
787 +
788 + return wp_kses( $value, $allowed_html );
789 + }
790 +
791 + /**
615 792 * Do wp_specialchars_decode to get back '&' that wp_kses_post might have turned to '&'
616 793 * this MUST be done, else we'll be back to the '& entity' problem.
617 794 *
618 795 * @since 4.0.04
@@ -646,10 +823,12 @@
646 823 $translation = array(
647 824 '"' => '"',
648 825 '"' => '"',
649 826 '"' => '"',
650 - '&lt; ' => '< ', // The space preserves the HTML.
651 - '&#060; ' => '< ', // The space preserves the HTML.
827 + // The space preserves the HTML.
828 + '&lt; ' => '< ',
829 + // The space preserves the HTML.
830 + '&#060; ' => '< ',
652 831 '&gt;' => '>',
653 832 '&#062;' => '>',
654 833 '&amp;' => '&',
655 834 '&#038;' => '&',
@@ -676,10 +855,10 @@
676 855 * Sanitize the value, and allow some HTML
677 856 *
678 857 * @since 2.0
679 858 *
680 - * @param string $value
681 - * @param array|string $allowed 'all' for everything included as defaults
859 + * @param string $value
860 + * @param array|string $allowed 'all' for everything included as defaults.
682 861 *
683 862 * @return string
684 863 */
685 864 public static function kses( $value, $allowed = array() ) {
@@ -780,9 +959,9 @@
780 959 'id' => true,
781 960 );
782 961
783 962 return array(
784 - 'a' => array(
963 + 'a' => array(
785 964 'class' => true,
786 965 'href' => true,
787 966 'id' => true,
788 967 'rel' => true,
@@ -851,16 +1030,16 @@
851 1030 'cite' => true,
852 1031 'title' => true,
853 1032 ),
854 1033 'rect' => array(
855 - 'class' => true,
856 - 'fill' => true,
857 - 'height' => true,
858 - 'width' => true,
859 - 'x' => true,
860 - 'y' => true,
861 - 'rx' => true,
862 - 'stroke' => true,
1034 + 'class' => true,
1035 + 'fill' => true,
1036 + 'height' => true,
1037 + 'width' => true,
1038 + 'x' => true,
1039 + 'y' => true,
1040 + 'rx' => true,
1041 + 'stroke' => true,
863 1042 'stroke-opacity' => true,
864 1043 'stroke-width' => true,
865 1044 ),
866 1045 'section' => $allow_class,
@@ -895,9 +1074,9 @@
895 1074 'xlink:href' => true,
896 1075 ),
897 1076 'ul' => $allow_class,
898 1077 'label' => array(
899 - 'for' => true,
1078 + 'for' => true,
900 1079 'class' => true,
901 1080 'id' => true,
902 1081 ),
903 1082 'button' => array(
@@ -915,9 +1094,9 @@
915 1094 *
916 1095 * @since 2.0
917 1096 */
918 1097 public static function remove_get_action() {
919 - if ( ! isset( $_GET ) ) {
1098 + if ( empty( $_GET ) ) {
920 1099 return;
921 1100 }
922 1101
923 1102 $action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
@@ -934,9 +1113,9 @@
934 1113 /**
935 1114 * Check the WP query for a parameter
936 1115 *
937 1116 * @since 2.0
938 - * @return string|array
1117 + * @return array|string
939 1118 */
940 1119 public static function get_query_var( $value, $param ) {
941 1120 if ( $value != '' ) {
942 1121 return $value;
@@ -953,10 +1132,12 @@
953 1132 /**
954 1133 * Try to show the SVG if possible. Otherwise, use the font icon.
955 1134 *
956 1135 * @since 4.0.02
1136 + *
957 1137 * @param string $class
958 1138 * @param array $atts
1139 + * @return string|null
959 1140 */
960 1141 public static function icon_by_class( $class, $atts = array() ) {
961 1142 $echo = ! isset( $atts['echo'] ) || $atts['echo'];
962 1143 if ( isset( $atts['echo'] ) ) {
@@ -966,14 +1147,16 @@
966 1147 $html_atts = self::array_to_html_params( $atts );
967 1148
968 1149 $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
969 1150
970 - // Replace icons that have been removed.
1151 + // Replace icons that have been removed or renamed.
971 1152 $deprecated = array(
972 - 'frm_clone_solid_icon' => 'frm_clone_icon',
1153 + 'frm_clone_solid_icon' => 'frm_clone_icon',
1154 + 'frm_keyalt_icon' => 'frm_key_icon',
1155 + 'frm_keyalt_solid_icon' => 'frm_key_solid_icon',
973 1156 );
974 1157 if ( isset( $deprecated[ $icon ] ) ) {
975 - $icon = $deprecated[ $icon ];
1158 + $icon = $deprecated[ $icon ];
976 1159 $class = str_replace( $icon, $deprecated[ $icon ], $class );
977 1160 }
978 1161
979 1162 if ( $icon === $class ) {
@@ -983,11 +1166,9 @@
983 1166 if ( strpos( $icon, ' ' ) ) {
984 1167 $icon = explode( ' ', $icon );
985 1168 $icon = reset( $icon );
986 1169 }
987 - $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '>
988 - <use xlink:href="#' . esc_attr( $icon ) . '" />
989 - </svg>';
1170 + $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use xlink:href="#' . esc_attr( $icon ) . '" /></svg>';
990 1171 }
991 1172
992 1173 if ( $echo ) {
993 1174 echo self::kses_icon( $icon ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
@@ -1073,11 +1254,18 @@
1073 1254 /**
1074 1255 * Include svg images.
1075 1256 *
1076 1257 * @since 4.0.02
1258 + * @return void
1077 1259 */
1078 1260 public static function include_svg() {
1079 - include_once self::plugin_path() . '/images/icons.svg';
1261 + if ( self::$included_svg ) {
1262 + return;
1263 + }
1264 +
1265 + // Use readfile instead of include_once because of a default security rule in Snuffleupagus.
1266 + readfile( self::plugin_path() . '/images/icons.svg' );
1267 + self::$included_svg = true;
1080 1268 }
1081 1269
1082 1270 /**
1083 1271 * Convert an associative array to HTML values.
@@ -1089,9 +1277,9 @@
1089 1277 * @param bool $echo
1090 1278 * @return string|void
1091 1279 */
1092 1280 public static function array_to_html_params( $atts, $echo = false ) {
1093 - $callback = function() use ( $atts ) {
1281 + $callback = function () use ( $atts ) {
1094 1282 if ( $atts ) {
1095 1283 foreach ( $atts as $key => $value ) {
1096 1284 echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1097 1285 }
@@ -1106,9 +1294,9 @@
1106 1294 * @since 5.0.13
1107 1295 *
1108 1296 * @param Closure $echo_function
1109 1297 * @param bool $echo
1110 - * @return string|void
1298 + * @return string|null
1111 1299 */
1112 1300 public static function clip( $echo_function, $echo = false ) {
1113 1301 if ( ! $echo ) {
1114 1302 ob_start();
@@ -1126,12 +1314,15 @@
1126 1314 }
1127 1315
1128 1316 /**
1129 1317 * @since 3.0
1318 + *
1319 + * @param array $atts
1320 + * @return void
1130 1321 */
1131 1322 public static function get_admin_header( $atts ) {
1132 - $has_nav = ( isset( $atts['form'] ) && ! empty( $atts['form'] ) && ( ! isset( $atts['is_template'] ) || ! $atts['is_template'] ) );
1133 - if ( ! isset( $atts['close'] ) || empty( $atts['close'] ) ) {
1323 + $has_nav = ! empty( $atts['form'] ) && empty( $atts['is_template'] );
1324 + if ( empty( $atts['close'] ) ) {
1134 1325 $atts['close'] = admin_url( 'admin.php?page=formidable' );
1135 1326 }
1136 1327 if ( ! isset( $atts['import_link'] ) ) {
1137 1328 $atts['import_link'] = false;
@@ -1136,9 +1327,9 @@
1136 1327 if ( ! isset( $atts['import_link'] ) ) {
1137 1328 $atts['import_link'] = false;
1138 1329 }
1139 1330
1140 - include( self::plugin_path() . '/classes/views/shared/admin-header.php' );
1331 + include self::plugin_path() . '/classes/views/shared/admin-header.php';
1141 1332 }
1142 1333
1143 1334 /**
1144 1335 * @since 6.0
@@ -1174,10 +1365,22 @@
1174 1365 return;
1175 1366 }
1176 1367 ?>
1177 1368 <div class="frm-upgrade-bar">
1178 - <span>You're using Formidable Forms Lite. To unlock more features consider</span>
1179 - <a href="<?php echo esc_url( self::admin_upgrade_link( 'top-bar' ) ); ?>" target="_blank" rel="noopener">upgrading to Pro</a>.
1369 + <?php
1370 + $upgrade_link = self::admin_upgrade_link(
1371 + array(
1372 + 'medium' => 'settings-license',
1373 + 'content' => 'lite-banner',
1374 + )
1375 + );
1376 + printf(
1377 + /* translators: %1$s: Start link HTML, %2$s: End link HTML */
1378 + esc_html__( 'You\'re using Formidable Forms Lite. To unlock more features consider %1$supgrading to PRO%2$s.', 'formidable' ),
1379 + '<a href="' . esc_url( $upgrade_link ) . '">',
1380 + '</a>'
1381 + );
1382 + ?>
1180 1383 </div>
1181 1384 <?php
1182 1385 }
1183 1386
@@ -1194,8 +1397,10 @@
1194 1397 * Render a button for a new item (Form, Application, etc).
1195 1398 *
1196 1399 * @since 3.0
1197 1400 * @param array $atts {
1401 + * Details about the button.
1402 + *
1198 1403 * @type array $link_hook Custom link hook, calls do_action and exits early.
1199 1404 * @type string $new_link Href value, default #.
1200 1405 * @type string $class Custom class names, space separated.
1201 1406 * @type string $button_text Button text. Default "Add New".
@@ -1207,9 +1412,9 @@
1207 1412 do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
1208 1413 return;
1209 1414 }
1210 1415
1211 - if ( empty( $atts['new_link'] ) && empty( $atts['trigger_new_form_modal'] ) && empty( $atts['class'] ) ) {
1416 + if ( empty( $atts['new_link'] ) && empty( $atts['create_form'] ) && empty( $atts['class'] ) ) {
1212 1417 // Do not render a button if none of these attributes are set.
1213 1418 return;
1214 1419 }
1215 1420
@@ -1215,12 +1420,8 @@
1215 1420
1216 1421 $href = ! empty( $atts['new_link'] ) ? esc_url( $atts['new_link'] ) : '#';
1217 1422 $class = 'button button-primary frm-button-primary';
1218 1423
1219 - if ( ! empty( $atts['trigger_new_form_modal'] ) ) {
1220 - $class .= ' frm-trigger-new-form-modal';
1221 - }
1222 -
1223 1424 if ( ! empty( $atts['class'] ) ) {
1224 1425 $class .= ' ' . $atts['class'];
1225 1426 }
1226 1427
@@ -1237,10 +1438,11 @@
1237 1438 'placeholder' => '',
1238 1439 'tosearch' => '',
1239 1440 'text' => __( 'Search', 'formidable' ),
1240 1441 'input_id' => '',
1442 + 'value' => false,
1241 1443 );
1242 - $atts = array_merge( $defaults, $atts );
1444 + $atts = array_merge( $defaults, $atts );
1243 1445
1244 1446 if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
1245 1447 $atts['tosearch'] = 'frm-card';
1246 1448 }
@@ -1251,8 +1453,27 @@
1251 1453 }
1252 1454
1253 1455 $input_id = $atts['input_id'] . '-search-input';
1254 1456
1457 + $input_atts = array(
1458 + 'type' => 'search',
1459 + 'id' => $input_id,
1460 + 'name' => 's',
1461 + 'placeholder' => $atts['placeholder'],
1462 + 'class' => $class,
1463 + 'data-tosearch' => $atts['tosearch'],
1464 + );
1465 +
1466 + if ( is_string( $atts['value'] ) ) {
1467 + $input_atts['value'] = $atts['value'];
1468 + } elseif ( isset( $_REQUEST['s'] ) ) {
1469 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1470 + $input_atts['value'] = wp_unslash( $_REQUEST['s'] );
1471 + }
1472 +
1473 + if ( ! empty( $atts['tosearch'] ) ) {
1474 + $input_atts['autocomplete'] = 'off';
1475 + }
1255 1476 ?>
1256 1477 <p class="frm-search">
1257 1478 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1258 1479 <?php echo esc_html( $atts['text'] ); ?>:
@@ -1257,15 +1478,9 @@
1257 1478 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1258 1479 <?php echo esc_html( $atts['text'] ); ?>:
1259 1480 </label>
1260 1481 <span class="frmfont frm_search_icon"></span>
1261 - <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
1262 - value="<?php _admin_search_query(); ?>" placeholder="<?php echo esc_attr( $atts['placeholder'] ); ?>"
1263 - class="<?php echo esc_attr( $class ); ?>" data-tosearch="<?php echo esc_attr( $atts['tosearch'] ); ?>"
1264 - <?php if ( ! empty( $atts['tosearch'] ) ) { ?>
1265 - autocomplete="off"
1266 - <?php } ?>
1267 - />
1482 + <input <?php self::array_to_html_params( $input_atts, true ); ?> />
1268 1483 <?php
1269 1484 if ( empty( $atts['tosearch'] ) ) {
1270 1485 submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
1271 1486 }
@@ -1275,8 +1490,9 @@
1275 1490 }
1276 1491
1277 1492 /**
1278 1493 * @param string $type
1494 + * @return void
1279 1495 */
1280 1496 public static function trigger_hook_load( $type, $object = null ) {
1281 1497 // Only load the form hooks once.
1282 1498 $hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
@@ -1285,11 +1501,14 @@
1285 1501 }
1286 1502 }
1287 1503
1288 1504 /**
1289 - * Save all front-end js scripts into a single file
1505 + * Save all front-end js scripts into a single file.
1506 + * And save an additional single file of all front-end Stripe JS scripts.
1290 1507 *
1291 1508 * @since 3.0
1509 + *
1510 + * @return void
1292 1511 */
1293 1512 public static function save_combined_js() {
1294 1513 $file_atts = apply_filters(
1295 1514 'frm_js_location',
@@ -1302,10 +1521,34 @@
1302 1521
1303 1522 $files = array(
1304 1523 self::plugin_path() . '/js/formidable.min.js',
1305 1524 );
1525 + /**
1526 + * @param array $files
1527 + */
1306 1528 $files = apply_filters( 'frm_combined_js_files', $files );
1307 1529 $new_file->combine_files( $files );
1530 +
1531 + // Create the minified Stripe Script.
1532 + $file_atts = apply_filters(
1533 + 'frm_stripe_js_location',
1534 + array(
1535 + 'file_name' => 'frmstrp.min.js',
1536 + 'new_file_path' => self::plugin_path() . '/js',
1537 + )
1538 + );
1539 + $new_file = new FrmCreateFile( $file_atts );
1540 + $files = array(
1541 + FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.min.js',
1542 + );
1543 +
1544 + /**
1545 + * @since 6.5
1546 + *
1547 + * @param array $files
1548 + */
1549 + $files = apply_filters( 'frm_stripe_combined_js_files', $files );
1550 + $new_file->combine_files( $files );
1308 1551 }
1309 1552
1310 1553 /**
1311 1554 * Check a value from a shortcode to see if true or false.
@@ -1312,14 +1555,14 @@
1312 1555 * True when value is 1, true, 'true', 'yes'
1313 1556 *
1314 1557 * @since 1.07.10
1315 1558 *
1316 - * @param string $value The value to compare
1559 + * @param string $value The value to compare.
1317 1560 *
1318 - * @return boolean True or False
1561 + * @return bool
1319 1562 */
1320 1563 public static function is_true( $value ) {
1321 - return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1564 + return true === $value || 1 == $value || 'true' === $value || 'yes' === $value;
1322 1565 }
1323 1566
1324 1567 /**
1325 1568 * Gets all post from a specific post type.
@@ -1385,9 +1628,9 @@
1385 1628
1386 1629 wp_enqueue_script( 'jquery-ui-autocomplete' );
1387 1630
1388 1631 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1389 - $title = '';
1632 + $title = '';
1390 1633
1391 1634 if ( $selected ) {
1392 1635 $title = get_the_title( $selected );
1393 1636 }
@@ -1403,11 +1646,11 @@
1403 1646 <?php
1404 1647 }
1405 1648
1406 1649 /**
1407 - * @param array $args
1408 - * @param string $page_id Deprecated.
1409 - * @param boolean $truncate Deprecated.
1650 + * @param array $args
1651 + * @param string $page_id Deprecated.
1652 + * @param bool $truncate Deprecated.
1410 1653 */
1411 1654 public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1412 1655 self::prep_page_dropdown_params( $page_id, $truncate, $args );
1413 1656
@@ -1451,13 +1694,13 @@
1451 1694 * @since 4.10.01 Added `post_type` and `autocomplete_placeholder` to the arguments array.
1452 1695 */
1453 1696 private static function preformat_selection_args( $args ) {
1454 1697 $defaults = array(
1455 - 'truncate' => false,
1456 - 'placeholder' => ' ',
1457 - 'field_name' => '',
1458 - 'page_id' => '',
1459 - 'post_type' => 'page',
1698 + 'truncate' => false,
1699 + 'placeholder' => ' ',
1700 + 'field_name' => '',
1701 + 'page_id' => '',
1702 + 'post_type' => 'page',
1460 1703 'autocomplete_placeholder' => __( 'Select a Page', 'formidable' ),
1461 1704 );
1462 1705
1463 1706 return array_merge( $defaults, $args );
@@ -1528,25 +1771,16 @@
1528 1771 return self::is_admin_page( 'formidable-views-editor' );
1529 1772 }
1530 1773
1531 1774 /**
1532 - * @since 4.0
1533 - * @deprecated 5.5.3
1775 + * @param string $field_name
1776 + * @param array|string $capability
1777 + * @param string $multiple 'single' and 'multiple'.
1534 1778 */
1535 - public static function maybe_full_screen_link( $link ) {
1536 - _deprecated_function( __METHOD__, '5.5.3' );
1537 - return $link;
1538 - }
1539 -
1540 - /**
1541 - * @param string $field_name
1542 - * @param string|array $capability
1543 - * @param string $multiple 'single' and 'multiple'
1544 - */
1545 1779 public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1546 1780 ?>
1547 1781 <select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1548 - <?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1782 + <?php echo 'multiple' === $multiple ? 'multiple="multiple"' : ''; ?>
1549 1783 class="frm_multiselect">
1550 1784 <?php self::roles_options( $capability ); ?>
1551 1785 </select>
1552 1786 <?php
@@ -1554,9 +1788,9 @@
1554 1788
1555 1789 /**
1556 1790 * @since 4.07
1557 1791 * @param array|string $selected
1558 - * @param string $current
1792 + * @param string $current
1559 1793 */
1560 1794 private static function selected( $selected, $current ) {
1561 1795 if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1562 1796 FrmProAppHelper::selected( $selected, $current );
@@ -1565,9 +1799,9 @@
1565 1799 }
1566 1800 }
1567 1801
1568 1802 /**
1569 - * @param string|array $capability
1803 + * @param array|string $capability
1570 1804 */
1571 1805 public static function roles_options( $capability ) {
1572 1806 global $frm_vars;
1573 1807 if ( isset( $frm_vars['editable_roles'] ) ) {
@@ -1579,9 +1813,9 @@
1579 1813
1580 1814 foreach ( $editable_roles as $role => $details ) {
1581 1815 $name = translate_user_role( $details['name'] );
1582 1816 ?>
1583 - <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_attr( $name ); ?> </option>
1817 + <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_html( $name ); ?> </option>
1584 1818 <?php
1585 1819 unset( $role, $details );
1586 1820 }
1587 1821 }
@@ -1602,9 +1836,8 @@
1602 1836 $pro_cap = array(
1603 1837 'frm_create_entries' => __( 'Add Entries from Admin Area', 'formidable' ),
1604 1838 'frm_edit_entries' => __( 'Edit Entries from Admin Area', 'formidable' ),
1605 1839 'frm_view_reports' => __( 'View Reports', 'formidable' ),
1606 - 'frm_edit_displays' => __( 'Add/Edit Views', 'formidable' ),
1607 1840 );
1608 1841 /**
1609 1842 * @since 5.3.1
1610 1843 *
@@ -1611,8 +1844,14 @@
1611 1844 * @param array<string,string> $pro_cap
1612 1845 */
1613 1846 $pro_cap = apply_filters( 'frm_pro_capabilities', $pro_cap );
1614 1847
1848 + if ( ! array_key_exists( 'frm_edit_displays', $pro_cap ) && is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed() ) {
1849 + // For backward compatibility, add the Add/Edit Views permission if Pro is not up to date.
1850 + // This was added in 6.5.4. Remove this in the future.
1851 + $pro_cap['frm_edit_displays'] = __( 'Add/Edit Views', 'formidable' );
1852 + }
1853 +
1615 1854 if ( 'pro_only' === $type ) {
1616 1855 return $pro_cap;
1617 1856 }
1618 1857
@@ -1627,9 +1866,9 @@
1627 1866 * @return array<string,string>
1628 1867 */
1629 1868 private static function get_lite_capabilities() {
1630 1869 return array(
1631 - 'frm_view_forms' => __( 'View Forms', 'formidable' ),
1870 + 'frm_view_forms' => __( 'View Forms List', 'formidable' ),
1632 1871 'frm_edit_forms' => __( 'Add and Edit Forms', 'formidable' ),
1633 1872 'frm_delete_forms' => __( 'Delete Forms', 'formidable' ),
1634 1873 'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1635 1874 'frm_view_entries' => __( 'View Entries from Admin Area', 'formidable' ),
@@ -1670,9 +1909,9 @@
1670 1909 return current_user_can( $role );
1671 1910 }
1672 1911
1673 1912 /**
1674 - * @param string|array $needed_role
1913 + * @param array|string $needed_role
1675 1914 * @return bool
1676 1915 */
1677 1916 public static function user_has_permission( $needed_role ) {
1678 1917 if ( is_array( $needed_role ) ) {
@@ -1728,8 +1967,11 @@
1728 1967 /**
1729 1968 * Make sure admins have permission to see the menu items
1730 1969 *
1731 1970 * @since 2.0.6
1971 + *
1972 + * @param string $cap
1973 + * @return void
1732 1974 */
1733 1975 public static function force_capability( $cap = 'frm_change_settings' ) {
1734 1976 if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1735 1977 $role = get_role( 'administrator' );
@@ -1740,9 +1982,9 @@
1740 1982 }
1741 1983 }
1742 1984
1743 1985 /**
1744 - * Check if the user has permision for action.
1986 + * Check if the user has permission for action.
1745 1987 * Return permission message and stop the action if no permission
1746 1988 *
1747 1989 * @since 2.0
1748 1990 *
@@ -1778,9 +2020,9 @@
1778 2020 if ( empty( $nonce_name ) ) {
1779 2021 return $error;
1780 2022 }
1781 2023
1782 - $nonce_value = ( $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
2024 + $nonce_value = $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
1783 2025 if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1784 2026 $frm_settings = self::get_settings();
1785 2027 $error = $frm_settings->admin_permission;
1786 2028 }
@@ -1794,12 +2036,13 @@
1794 2036 }
1795 2037 }
1796 2038
1797 2039 public static function check_selected( $values, $current ) {
1798 - $values = self::recursive_function_map( $values, 'trim' );
1799 - $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1800 - $current = htmlspecialchars_decode( trim( $current ) );
2040 + $values = self::recursive_function_map( $values, 'trim' );
2041 + $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1801 2042
2043 + $current = is_null( $current ) ? '' : htmlspecialchars_decode( trim( $current ) );
2044 +
1802 2045 return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1803 2046 }
1804 2047
1805 2048 public static function recursive_function_map( $value, $function ) {
@@ -1819,8 +2062,9 @@
1819 2062 }
1820 2063 }
1821 2064 }
1822 2065 } else {
2066 + $value = self::maybe_update_value_if_null( $value, $function );
1823 2067 $value = call_user_func( $function, $value );
1824 2068 }
1825 2069
1826 2070 return $value;
@@ -1825,8 +2069,24 @@
1825 2069
1826 2070 return $value;
1827 2071 }
1828 2072
2073 + /**
2074 + * Updates value to empty string if it is null and being passed to a string function.
2075 + *
2076 + * @since 6.8.4
2077 + * @param mixed $value
2078 + * @param string $function
2079 + * @return mixed
2080 + */
2081 + private static function maybe_update_value_if_null( $value, $function ) {
2082 + if ( null === $value && in_array( $function, array( 'trim', 'strlen' ), true ) ) {
2083 + $value = '';
2084 + }
2085 +
2086 + return $value;
2087 + }
2088 +
1829 2089 public static function is_assoc( $array ) {
1830 2090 return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1831 2091 }
1832 2092
@@ -1837,14 +2097,12 @@
1837 2097 $return = array();
1838 2098 foreach ( $array as $key => $value ) {
1839 2099 if ( is_array( $value ) ) {
1840 2100 $return = array_merge( $return, self::array_flatten( $value, $keys ) );
2101 + } elseif ( $keys === 'keep' ) {
2102 + $return[ $key ] = $value;
1841 2103 } else {
1842 - if ( $keys == 'keep' ) {
1843 - $return[ $key ] = $value;
1844 - } else {
1845 - $return[] = $value;
1846 - }
2104 + $return[] = $value;
1847 2105 }
1848 2106 }
1849 2107
1850 2108 return $return;
@@ -1849,8 +2107,27 @@
1849 2107
1850 2108 return $return;
1851 2109 }
1852 2110
2111 + /**
2112 + * Flatten an array before imploding it to avoid Array to string conversion warnings.
2113 + *
2114 + * @since 6.16.1
2115 + *
2116 + * @param string $sep
2117 + * @param array $array
2118 + * @return string
2119 + */
2120 + public static function safe_implode( $sep, $array ) {
2121 + $array = self::array_flatten( $array );
2122 + return implode( $sep, $array );
2123 + }
2124 +
2125 + /**
2126 + * @param string $text
2127 + * @param bool $is_rich_text
2128 + * @return string
2129 + */
1853 2130 public static function esc_textarea( $text, $is_rich_text = false ) {
1854 2131 $safe_text = str_replace( '&quot;', '"', $text );
1855 2132 if ( ! $is_rich_text ) {
1856 2133 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
@@ -1856,9 +2133,13 @@
1856 2133 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1857 2134 }
1858 2135 $safe_text = str_replace( '&amp; ', '& ', $safe_text );
1859 2136
1860 - return apply_filters( 'esc_textarea', $safe_text, $text );
2137 + /**
2138 + * @param string $safe_text
2139 + * @param string $text
2140 + */
2141 + return (string) apply_filters( 'esc_textarea', $safe_text, $text );
1861 2142 }
1862 2143
1863 2144 /**
1864 2145 * Add auto paragraphs to text areas
@@ -1909,12 +2190,12 @@
1909 2190 * @since 5.0.13 added $echo param.
1910 2191 *
1911 2192 * @param string $url
1912 2193 * @param bool $echo
1913 - * @return string|void
2194 + * @return string|null
1914 2195 */
1915 2196 public static function js_redirect( $url, $echo = false ) {
1916 - $callback = function() use ( $url ) {
2197 + $callback = function () use ( $url ) {
1917 2198 echo '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1918 2199 };
1919 2200 return self::clip( $callback, $echo );
1920 2201 }
@@ -1924,9 +2205,9 @@
1924 2205 return $user_id;
1925 2206 }
1926 2207
1927 2208 $user_id = sanitize_text_field( $user_id );
1928 - if ( $user_id == 'current' ) {
2209 + if ( $user_id === 'current' ) {
1929 2210 $user_id = get_current_user_id();
1930 2211 } else {
1931 2212 if ( is_email( $user_id ) ) {
1932 2213 $user = get_user_by( 'email', $user_id );
@@ -1942,8 +2223,13 @@
1942 2223
1943 2224 return $user_id;
1944 2225 }
1945 2226
2227 + /**
2228 + * @param string $filename
2229 + * @param array $atts
2230 + * @return false|string
2231 + */
1946 2232 public static function get_file_contents( $filename, $atts = array() ) {
1947 2233 if ( ! is_file( $filename ) ) {
1948 2234 return false;
1949 2235 }
@@ -1949,9 +2235,9 @@
1949 2235 }
1950 2236
1951 2237 extract( $atts ); // phpcs:ignore WordPress.PHP.DontExtract
1952 2238 ob_start();
1953 - include( $filename );
2239 + include $filename;
1954 2240 $contents = ob_get_contents();
1955 2241 ob_end_clean();
1956 2242
1957 2243 return $contents;
@@ -2006,9 +2292,9 @@
2006 2292 ++$suffix;
2007 2293 } while ( in_array( $key_check, $similar_keys, true ) );
2008 2294
2009 2295 $key = $key_check;
2010 - }
2296 + }//end if
2011 2297
2012 2298 return $key;
2013 2299 }
2014 2300
@@ -2052,9 +2338,11 @@
2052 2338 * @return string
2053 2339 */
2054 2340 private static function generate_new_key( $num_chars ) {
2055 2341 $max_slug_value = pow( 36, $num_chars );
2056 - $min_slug_value = 37; // we want to have at least 2 characters in the slug
2342 +
2343 + // We want to have at least 2 characters in the slug.
2344 + $min_slug_value = 37;
2057 2345 return base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
2058 2346 }
2059 2347
2060 2348 /**
@@ -2083,11 +2371,16 @@
2083 2371
2084 2372 /**
2085 2373 * Editing a Form or Entry
2086 2374 *
2087 - * @param string $table
2375 + * @param object $record
2376 + * @param string $table
2377 + * @param array|string $fields
2378 + * @param bool $default
2379 + * @param array $post_values
2380 + * @param array $args
2088 2381 *
2089 - * @return bool|array
2382 + * @return array|bool
2090 2383 */
2091 2384 public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
2092 2385 if ( ! $record ) {
2093 2386 return false;
@@ -2140,13 +2433,12 @@
2140 2433 $post_values = $args['post_values'];
2141 2434
2142 2435 if ( $args['default'] ) {
2143 2436 $meta_value = $field->default_value;
2144 - } else {
2145 - if ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2146 - if ( ! isset( $field->field_options['custom_field'] ) ) {
2147 - $field->field_options['custom_field'] = '';
2148 - }
2437 + } elseif ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2438 + if ( ! isset( $field->field_options['custom_field'] ) ) {
2439 + $field->field_options['custom_field'] = '';
2440 + }
2149 2441 $meta_value = FrmProEntryMetaHelper::get_post_value(
2150 2442 $record->post_id,
2151 2443 $field->field_options['post_field'],
2152 2444 $field->field_options['custom_field'],
@@ -2156,12 +2448,11 @@
2156 2448 'form_id' => $field->form_id,
2157 2449 'field' => $field,
2158 2450 )
2159 2451 );
2160 - } else {
2161 - $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2162 - }
2163 - }
2452 + } else {
2453 + $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2454 + }//end if
2164 2455
2165 2456 $field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
2166 2457 if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
2167 2458 $new_value = $post_values['item_meta'][ $field->id ];
@@ -2209,12 +2500,15 @@
2209 2500 );
2210 2501 }
2211 2502
2212 2503 /**
2504 + * @param object $record
2213 2505 * @param string $table
2506 + * @param array $post_values
2507 + * @param array $values
2214 2508 */
2215 2509 private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
2216 - if ( $table == 'entries' ) {
2510 + if ( $table === 'entries' ) {
2217 2511 $form = $record->form_id;
2218 2512 FrmForm::maybe_get_form( $form );
2219 2513 } else {
2220 2514 $form = $record;
@@ -2250,9 +2544,9 @@
2250 2544 $form_defaults = FrmFormsHelper::get_default_opts();
2251 2545
2252 2546 foreach ( $form_defaults as $opt => $default ) {
2253 2547 if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
2254 - $values[ $opt ] = ( $post_values && isset( $post_values['options'][ $opt ] ) ) ? $post_values['options'][ $opt ] : $default;
2548 + $values[ $opt ] = $post_values && isset( $post_values['options'][ $opt ] ) ? $post_values['options'][ $opt ] : $default;
2255 2549 }
2256 2550
2257 2551 unset( $opt, $default );
2258 2552 }
@@ -2273,9 +2567,9 @@
2273 2567 * @since 2.2.10
2274 2568 *
2275 2569 * @param array $post_values
2276 2570 *
2277 - * @return boolean|int
2571 + * @return bool|int
2278 2572 */
2279 2573 public static function custom_style_value( $post_values ) {
2280 2574 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2281 2575 $custom_style = absint( $post_values['options']['custom_style'] );
@@ -2280,29 +2574,37 @@
2280 2574 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2281 2575 $custom_style = absint( $post_values['options']['custom_style'] );
2282 2576 } else {
2283 2577 $frm_settings = self::get_settings();
2284 - $custom_style = ( $frm_settings->load_style != 'none' );
2578 + $custom_style = ( $frm_settings->load_style !== 'none' );
2285 2579 }
2286 2580
2287 2581 return $custom_style;
2288 2582 }
2289 2583
2290 - public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
2291 - if ( is_array( $str ) ) {
2584 + /**
2585 + * @param mixed $original_string
2586 + * @param int|string $length
2587 + * @param int $minword
2588 + * @param string $continue
2589 + * @return string
2590 + */
2591 + public static function truncate( $original_string, $length, $minword = 3, $continue = '...' ) {
2592 + if ( ! is_string( $original_string ) && ! is_int( $original_string ) ) {
2292 2593 return '';
2293 2594 }
2294 2595
2295 2596 $length = (int) $length;
2296 - $str = wp_strip_all_tags( $str );
2597 + $str = wp_strip_all_tags( (string) $original_string );
2297 2598 $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
2298 2599
2299 2600 if ( $length == 0 ) {
2300 2601 return '';
2301 - } elseif ( $length <= 10 ) {
2602 + }
2603 +
2604 + if ( $length <= 10 ) {
2302 2605 $sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
2303 -
2304 - return $sub . ( ( $length < $original_len ) ? $continue : '' );
2606 + return $sub . ( $length < $original_len ? $continue : '' );
2305 2607 }
2306 2608
2307 2609 $sub = '';
2308 2610 $len = 0;
@@ -2308,10 +2610,14 @@
2308 2610 $len = 0;
2309 2611
2310 2612 $words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
2311 2613
2614 + if ( ! is_array( $words ) ) {
2615 + return $original_string;
2616 + }
2617 +
2312 2618 foreach ( $words as $word ) {
2313 - $part = ( ( $sub != '' ) ? ' ' : '' ) . $word;
2619 + $part = ( $sub != '' ? ' ' : '' ) . $word;
2314 2620 $total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
2315 2621 if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
2316 2622 break;
2317 2623 }
@@ -2325,11 +2631,37 @@
2325 2631
2326 2632 unset( $total_len, $word );
2327 2633 }
2328 2634
2329 - return $sub . ( ( $len < $original_len ) ? $continue : '' );
2635 + $sub = self::maybe_force_truncate_on_string_with_no_spaces( $sub, $length );
2636 +
2637 + return $sub . ( $len < $original_len ? $continue : '' );
2330 2638 }
2331 2639
2640 + /**
2641 + * If the string is still too long because there may not have been any spaces, force truncate.
2642 + *
2643 + * @since 6.5.4
2644 + *
2645 + * @param string $sub Current substring.
2646 + * @param int $length The length limit.
2647 + * @return string
2648 + */
2649 + private static function maybe_force_truncate_on_string_with_no_spaces( $sub, $length ) {
2650 + if ( strlen( $sub ) < $length + 50 ) {
2651 + // If the string isn't way over the limit, leave it.
2652 + return $sub;
2653 + }
2654 +
2655 + $first_space = strpos( $sub, ' ', $length );
2656 + if ( false !== $first_space ) {
2657 + // Ignore anything with spaces.
2658 + return $sub;
2659 + }
2660 +
2661 + return substr( $sub, 0, $length + 10 );
2662 + }
2663 +
2332 2664 public static function mb_function( $function_names, $args ) {
2333 2665 $mb_function_name = $function_names[0];
2334 2666 $function_name = $function_names[1];
2335 2667 if ( function_exists( $mb_function_name ) ) {
@@ -2386,12 +2718,12 @@
2386 2718 return date_i18n( $date_format, strtotime( $date ) );
2387 2719 }
2388 2720
2389 2721 /**
2390 - * Gets the time ago in words
2722 + * Gets the time ago in words.
2391 2723 *
2392 - * @param int $from in seconds
2393 - * @param int|string $to in seconds
2724 + * @param int $from In seconds.
2725 + * @param int|string $to In seconds.
2394 2726 *
2395 2727 * @return string $time_ago
2396 2728 */
2397 2729 public static function human_time_diff( $from, $to = '', $levels = 1 ) {
@@ -2406,9 +2738,9 @@
2406 2738 $diff_object = $now->diff( $ago );
2407 2739 $diff = get_object_vars( $diff_object );
2408 2740
2409 2741 // Add week amount and update day amount
2410 - $diff['w'] = floor( $diff['d'] / 7 );
2742 + $diff['w'] = floor( $diff['d'] / 7 );
2411 2743 $diff['d'] -= $diff['w'] * 7;
2412 2744
2413 2745 $time_strings = self::get_time_strings();
2414 2746
@@ -2415,9 +2747,9 @@
2415 2747 if ( ! is_numeric( $levels ) ) {
2416 2748 // Show time in specified unit.
2417 2749 $levels = self::get_unit( $levels );
2418 2750 if ( isset( $time_strings[ $levels ] ) ) {
2419 - $diff = array(
2751 + $diff = array(
2420 2752 $levels => self::time_format( $levels, $diff ),
2421 2753 );
2422 2754 $time_strings = array(
2423 2755 $levels => $time_strings[ $levels ],
@@ -2506,9 +2838,9 @@
2506 2838 }
2507 2839
2508 2840 /**
2509 2841 * Get the translatable time strings. The untranslated version is a failsafe
2510 - * in case langauges are changing for the unit set in the shortcode.
2842 + * in case languages are changing for the unit set in the shortcode.
2511 2843 *
2512 2844 * @since 2.0.20
2513 2845 * @return array
2514 2846 */
@@ -2554,23 +2886,28 @@
2554 2886
2555 2887 // Pagination Methods.
2556 2888
2557 2889 /**
2558 - * @param integer $current_p
2890 + * @param int $r_count
2891 + * @param int $current_p
2892 + * @param int $p_size
2893 + * @return int
2559 2894 */
2560 2895 public static function get_last_record_num( $r_count, $current_p, $p_size ) {
2561 - return ( ( $r_count < ( $current_p * $p_size ) ) ? $r_count : ( $current_p * $p_size ) );
2896 + return ( $r_count < $current_p * $p_size ? $r_count : $current_p * $p_size );
2562 2897 }
2563 2898
2564 2899 /**
2565 - * @param integer $current_p
2900 + * @param int $r_count
2901 + * @param int $current_p
2902 + * @param int $p_size
2903 + * @return int
2566 2904 */
2567 2905 public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2568 2906 if ( $current_p == 1 ) {
2569 2907 return 1;
2570 - } else {
2571 - return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2572 2908 }
2909 + return self::get_last_record_num( $r_count, $current_p - 1, $p_size ) + 1;
2573 2910 }
2574 2911
2575 2912 /**
2576 2913 * @return array
@@ -2593,9 +2930,9 @@
2593 2930 if ( ! isset( $l3 ) ) {
2594 2931 $l3 = $name;
2595 2932 }
2596 2933
2597 - $this_val = ( $p == $last ) ? $jv['value'] : array();
2934 + $this_val = $p == $last ? $jv['value'] : array();
2598 2935
2599 2936 switch ( $p ) {
2600 2937 case 0:
2601 2938 $l1 = $name;
@@ -2617,12 +2954,12 @@
2617 2954 self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2618 2955 }
2619 2956
2620 2957 unset( $this_val, $n );
2621 - }
2958 + }//end foreach
2622 2959
2623 2960 unset( $last, $jv );
2624 - }
2961 + }//end foreach
2625 2962
2626 2963 return $vars;
2627 2964 }
2628 2965
@@ -2647,8 +2984,9 @@
2647 2984 'reply_to' => __( 'If you would like a different reply to address than the "from" address, add a single address here. FORMAT: Name <name@email.com> or name@email.com.', 'formidable' ),
2648 2985 'from' => __( 'Enter the name and/or email address of the sender. FORMAT: John Bates <john@example.com> or john@example.com.', 'formidable' ),
2649 2986 /* translators: %1$s: Form name, %2$s: Date */
2650 2987 'email_subject' => esc_attr( sprintf( __( 'If you leave the subject blank, the default will be used: %1$s Form submitted on %2$s', 'formidable' ), $form_name, self::site_name() ) ),
2988 + 'new_tab' => __( 'This option will open the link in a new browser tab. Please note that some popup blockers may prevent this from happening, in which case the link will be displayed.', 'formidable' ),
2651 2989 );
2652 2990
2653 2991 if ( ! isset( $tooltips[ $name ] ) ) {
2654 2992 return;
@@ -2869,8 +3207,11 @@
2869 3207 }
2870 3208
2871 3209 /**
2872 3210 * @since 4.02.03
3211 + *
3212 + * @param array|string $value
3213 + * @return string
2873 3214 */
2874 3215 public static function maybe_json_encode( $value ) {
2875 3216 if ( is_array( $value ) ) {
2876 3217 $value = wp_json_encode( $value );
@@ -2878,12 +3219,14 @@
2878 3219 return $value;
2879 3220 }
2880 3221
2881 3222 /**
3223 + * Echo The javascript to open and highlight the Formidable menu
3224 + *
2882 3225 * @since 1.07.10
2883 3226 *
2884 - * @param string $post_type The name of the post type that may need to be highlighted
2885 - * echo The javascript to open and highlight the Formidable menu
3227 + * @param string $post_type The name of the post type that may need to be highlighted.
3228 + * @return void
2886 3229 */
2887 3230 public static function maybe_highlight_menu( $post_type ) {
2888 3231 global $post;
2889 3232
@@ -2902,8 +3245,11 @@
2902 3245 /**
2903 3246 * Load the JS file on non-Formidable pages in the admin area
2904 3247 *
2905 3248 * @since 2.0
3249 + *
3250 + * @param bool $load
3251 + * @return void
2906 3252 */
2907 3253 public static function load_admin_wide_js( $load = true ) {
2908 3254 $version = self::plugin_version();
2909 3255 wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
@@ -2917,8 +3263,9 @@
2917 3263 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ),
2918 3264 'loading' => __( 'Loading&hellip;', 'formidable' ),
2919 3265 'nonce' => wp_create_nonce( 'frm_ajax' ),
2920 3266 'proIncludesSliderJs' => is_callable( 'FrmProFormsHelper::prepare_custom_currency' ),
3267 + 'inboxSlideIn' => FrmInbox::get_inbox_slide_in_value_for_js(),
2921 3268 );
2922 3269 wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
2923 3270
2924 3271 if ( $load ) {
@@ -2927,8 +3274,9 @@
2927 3274 }
2928 3275
2929 3276 /**
2930 3277 * @since 2.0.9
3278 + * @return void
2931 3279 */
2932 3280 public static function load_font_style() {
2933 3281 wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
2934 3282 }
@@ -2934,99 +3282,133 @@
2934 3282 }
2935 3283
2936 3284 /**
2937 3285 * @param string $location
3286 + * @return void
2938 3287 */
2939 3288 public static function localize_script( $location ) {
2940 - global $wp_scripts;
3289 + global $wp_scripts, $wp_version;
2941 3290
2942 - $ajax_url = admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' );
2943 - $ajax_url = apply_filters( 'frm_ajax_url', $ajax_url );
2944 -
2945 3291 $script_strings = array(
2946 - 'ajax_url' => $ajax_url,
2947 - 'images_url' => self::plugin_url() . '/images',
2948 - 'loading' => __( 'Loading&hellip;', 'formidable' ),
2949 - 'remove' => __( 'Remove', 'formidable' ),
2950 - 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
2951 - 'nonce' => wp_create_nonce( 'frm_ajax' ),
2952 - 'id' => __( 'ID', 'formidable' ),
2953 - 'no_results' => __( 'No results match', 'formidable' ),
2954 - 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
2955 - 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
2956 - 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
2957 - 'focus_first_error' => self::should_focus_first_error(),
2958 - 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3292 + 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3293 + 'images_url' => self::plugin_url() . '/images',
3294 + 'loading' => __( 'Loading&hellip;', 'formidable' ),
3295 + 'remove' => __( 'Remove', 'formidable' ),
3296 + 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3297 + 'nonce' => wp_create_nonce( 'frm_ajax' ),
3298 + 'id' => __( 'ID', 'formidable' ),
3299 + 'no_results' => __( 'No results match', 'formidable' ),
3300 + 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3301 + 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3302 + 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3303 + 'focus_first_error' => self::should_focus_first_error(),
3304 + 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3305 + // We need to keep this setting for a few versions because Pro checks for this.
3306 + 'include_resend_email' => false,
2959 3307 );
2960 3308
2961 3309 $data = $wp_scripts->get_data( 'formidable', 'data' );
2962 - if ( empty( $data ) ) {
3310 + if ( ! $data ) {
2963 3311 wp_localize_script( 'formidable', 'frm_js', $script_strings );
2964 3312 }
2965 3313
2966 - if ( $location == 'admin' ) {
2967 - $frm_settings = self::get_settings();
3314 + if ( $location === 'admin' ) {
2968 3315 $admin_script_strings = array(
2969 - 'desc' => __( '(Click to add description)', 'formidable' ),
2970 - 'blank' => __( '(Blank)', 'formidable' ),
2971 - 'no_label' => __( '(no label)', 'formidable' ),
2972 - 'saving' => '', // Deprecated in 6.0.
2973 - 'saved' => '', // Deprecated in 6.0.
2974 - 'ok' => __( 'OK', 'formidable' ),
2975 - 'cancel' => __( 'Cancel', 'formidable' ),
2976 - 'default_label' => __( 'Default', 'formidable' ),
2977 - 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
2978 - 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
2979 - 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
2980 - 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
2981 - 'confirm' => __( 'Are you sure?', 'formidable' ),
2982 - 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
2983 - 'conf_delete_sec' => __( 'All fields inside this Section will be deleted along with their data. Are you sure you want to delete this group of fields?', 'formidable' ),
2984 - 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
2985 - 'default_unique' => $frm_settings->unique_msg,
2986 - 'default_conf' => __( 'The entered values do not match', 'formidable' ),
2987 - 'enter_email' => __( 'Enter Email', 'formidable' ),
2988 - 'confirm_email' => __( 'Confirm Email', 'formidable' ),
2989 - 'conditional_text' => __( 'Conditional content here', 'formidable' ),
2990 - 'new_option' => __( 'New Option', 'formidable' ),
2991 - 'css_invalid_size' => __( 'In certain browsers (e.g. Firefox) text will not display correctly if the field height is too small relative to the field padding and text size. Please increase your field height or decrease your field padding.', 'formidable' ),
2992 - 'enter_password' => __( 'Enter Password', 'formidable' ),
2993 - 'confirm_password' => __( 'Confirm Password', 'formidable' ),
2994 - 'import_complete' => __( 'Import Complete', 'formidable' ),
2995 - 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
2996 - 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
2997 - 'private_label' => __( 'Private', 'formidable' ),
2998 - 'jquery_ui_url' => '',
2999 - 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3000 - 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3001 - 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3002 - 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3003 - 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3004 - 'only_one_action' => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
3005 - 'unsafe_params' => FrmFormsHelper::reserved_words(),
3316 + 'desc' => __( '(Click to add description)', 'formidable' ),
3317 + 'blank' => __( '(Blank)', 'formidable' ),
3318 + 'no_label' => __( '(no label)', 'formidable' ),
3319 + 'ok' => __( 'OK', 'formidable' ),
3320 + 'cancel' => __( 'Cancel', 'formidable' ),
3321 + 'default_label' => __( 'Default', 'formidable' ),
3322 + 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3323 + 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3324 + 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3325 + 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3326 + 'confirm' => __( 'Are you sure?', 'formidable' ),
3327 + 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3328 + 'conf_delete_sec' => __( 'All fields inside this Section will be deleted along with their data. Are you sure you want to delete this group of fields?', 'formidable' ),
3329 + 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3330 + 'default_unique' => FrmFieldsHelper::default_unique_msg(),
3331 + 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3332 + 'enter_email' => __( 'Enter Email', 'formidable' ),
3333 + 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3334 + 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3335 + 'new_option' => __( 'New Option', 'formidable' ),
3336 + 'css_invalid_size' => __( 'In certain browsers (e.g. Firefox) text will not display correctly if the field height is too small relative to the field padding and text size. Please increase your field height or decrease your field padding.', 'formidable' ),
3337 + 'enter_password' => __( 'Enter Password', 'formidable' ),
3338 + 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3339 + 'import_complete' => __( 'Import Complete', 'formidable' ),
3340 + 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3341 + 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3342 + 'private_label' => __( 'Private', 'formidable' ),
3343 + 'jquery_ui_url' => '',
3344 + 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3345 + 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3346 + 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3347 + 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3348 + 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3349 + /* translators: %d is the number of allowed actions per form */
3350 + 'only_one_action' => sprintf( __( 'This form action is limited to %d per form.', 'formidable' ), 1 ),
3351 + 'edit_action_text' => __( 'Please edit the existing form action.', 'formidable' ),
3352 + 'unsafe_params' => FrmFormsHelper::reserved_words(),
3006 3353 /* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
3007 - 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3354 + 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3008 3355 /* Translators: %s is the name of a parameter that is a reserved word. More than one word could be listed here, though that would not be common. */
3009 - 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3010 - 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3011 - 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3012 - 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3013 - 'install' => __( 'Install', 'formidable' ),
3014 - 'active' => __( 'Active', 'formidable' ),
3015 - 'select_a_field' => __( 'Select a Field', 'formidable' ),
3016 - 'no_items_found' => __( 'No items found.', 'formidable' ),
3017 - 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3356 + 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3357 + 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3358 + 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3359 + 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3360 + 'install' => __( 'Install', 'formidable' ),
3361 + 'active' => __( 'Active', 'formidable' ),
3362 + 'installed' => __( 'Installed', 'formidable' ),
3363 + 'not_installed' => __( 'Not Installed', 'formidable' ),
3364 + 'select_a_field' => __( 'Select a Field', 'formidable' ),
3365 + 'no_items_found' => __( 'No items found.', 'formidable' ),
3366 + 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3367 +
3368 + // Deprecated in 6.0.
3369 + 'saving' => '',
3370 +
3371 + // Deprecated in 6.0.
3372 + 'saved' => '',
3373 +
3374 + // translators: %1$s: HTML open tag, %2$s: HTML end tag.
3375 + 'holdShiftMsg' => esc_html__( 'You can hold %1$sShift%2$s on your keyboard to select multiple fields', 'formidable' ),
3376 + 'noTitleText' => FrmFormsHelper::get_no_title_text(),
3377 +
3378 + // In older versions this event listener causes the section to immediately close again
3379 + // when the h3 element is clicked. It's only required in WP 6.7+.
3380 + 'requireAccordionTitleClickListener' => version_compare( $wp_version, '6.7', '>=' ),
3018 3381 );
3382 + /**
3383 + * @param array $admin_script_strings
3384 + */
3019 3385 $admin_script_strings = apply_filters( 'frm_admin_script_strings', $admin_script_strings );
3020 3386
3021 3387 $data = $wp_scripts->get_data( 'formidable_admin', 'data' );
3022 - if ( empty( $data ) ) {
3388 + if ( ! $data ) {
3023 3389 wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
3024 3390 }
3025 - }
3391 + }//end if
3026 3392 }
3027 3393
3028 3394 /**
3395 + * @since 6.5
3396 + *
3397 + * @return string
3398 + */
3399 + public static function get_ajax_url() {
3400 + $ajax_url = admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' );
3401 +
3402 + /**
3403 + * @since 2.0.13
3404 + *
3405 + * @param string $ajax_url
3406 + */
3407 + return apply_filters( 'frm_ajax_url', $ajax_url );
3408 + }
3409 +
3410 + /**
3029 3411 * Returns whether or not the first errored input should be auto-focused (default true).
3030 3412 *
3031 3413 * @since 5.2.05
3032 3414 *
@@ -3051,9 +3433,10 @@
3051 3433 * Echo the message on the plugins listing page
3052 3434 *
3053 3435 * @since 1.07.10
3054 3436 *
3055 - * @param float $min_version The version the add-on requires
3437 + * @param float $min_version The version the add-on requires.
3438 + * @return void
3056 3439 */
3057 3440 public static function min_version_notice( $min_version ) {
3058 3441 $frm_version = self::plugin_version();
3059 3442
@@ -3087,9 +3470,8 @@
3087 3470 if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
3088 3471 return;
3089 3472 }
3090 3473
3091 - $pro_version = FrmProDb::$plug_version;
3092 3474 $expired = FrmAddonsController::is_license_expired();
3093 3475 ?>
3094 3476 <div class="frm-banner-alert frm_error_style frm_previous_install">
3095 3477 <?php
@@ -3107,8 +3489,11 @@
3107 3489 /**
3108 3490 * If Pro is installed, check the version number.
3109 3491 *
3110 3492 * @since 4.0.01
3493 + *
3494 + * @param string $min_version
3495 + * @return bool
3111 3496 */
3112 3497 public static function meets_min_pro_version( $min_version ) {
3113 3498 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3114 3499 }
@@ -3113,24 +3498,19 @@
3113 3498 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3114 3499 }
3115 3500
3116 3501 /**
3117 - * Show a message if the browser or PHP version is below the recommendations.
3502 + * Show a message if the PHP version is below the recommendations.
3118 3503 *
3119 3504 * @since 4.0.02
3505 + * @return void
3120 3506 */
3121 3507 private static function php_version_notice() {
3122 3508 $message = array();
3123 - if ( version_compare( phpversion(), '5.6', '<' ) ) {
3509 + if ( version_compare( phpversion(), '7.0', '<' ) ) {
3124 3510 $message[] = __( 'The version of PHP on your server is too low. If this is not corrected, you may see issues with Formidable Forms. Please contact your web host and ask to be updated to PHP 7.0+.', 'formidable' );
3125 3511 }
3126 3512
3127 - $browser = self::get_server_value( 'HTTP_USER_AGENT' );
3128 - $is_ie = strpos( $browser, 'MSIE' ) !== false;
3129 - if ( $is_ie ) {
3130 - $message[] = __( 'You are using an outdated browser that is not compatible with Formidable Forms. Please update to a more current browser (we recommend Chrome).', 'formidable' );
3131 - }
3132 -
3133 3513 foreach ( $message as $m ) {
3134 3514 ?>
3135 3515 <div class="frm-banner-alert frm_error_style frm_previous_install">
3136 3516 <?php echo esc_html( $m ); ?>
@@ -3260,16 +3640,10 @@
3260 3640 return $locales;
3261 3641 }
3262 3642
3263 3643 /**
3264 - * Output HTML containing reference text for accessibility
3265 - *
3266 - * @deprecated 5.1
3644 + * @return string
3267 3645 */
3268 - public static function multiselect_accessibility() {
3269 - _deprecated_function( __METHOD__, '5.1' );
3270 - }
3271 -
3272 3646 public static function get_menu_icon_class() {
3273 3647 if ( is_callable( 'FrmProAppHelper::get_settings' ) ) {
3274 3648 $settings = FrmProAppHelper::get_settings();
3275 3649 if ( is_object( $settings ) && ! empty( $settings->menu_icon ) ) {
@@ -3379,8 +3753,18 @@
3379 3753 return apply_filters( 'frm_images_dropdown_input_attrs', $input_attrs_str, $args );
3380 3754 }
3381 3755
3382 3756 /**
3757 + * @since 6.7.1
3758 + */
3759 + public static function get_images_dropdown_atts( $option, $args ) {
3760 + $image = self::get_images_dropdown_option_image( $option, $args );
3761 + $classes = self::get_images_dropdown_option_classes( $option, $args );
3762 + $custom_attrs = self::get_images_dropdown_option_html_attrs( $option, $args );
3763 + return compact( 'image', 'classes', 'custom_attrs' );
3764 + }
3765 +
3766 + /**
3383 3767 * Gets the image of each option in images_dropdown() method.
3384 3768 *
3385 3769 * @since 5.0.04
3386 3770 *
@@ -3391,9 +3775,9 @@
3391 3775 private static function get_images_dropdown_option_image( $option, $args ) {
3392 3776 $image = self::icon_by_class(
3393 3777 'frmfont ' . $option['svg'],
3394 3778 array(
3395 - 'echo' => false,
3779 + 'echo' => false,
3396 3780 )
3397 3781 );
3398 3782
3399 3783 $args['option'] = $option;
@@ -3531,15 +3915,15 @@
3531 3915 return $values;
3532 3916 }
3533 3917
3534 3918 /**
3535 - * Some back end fields allow privleged users to add scripts.
3919 + * Some back end fields allow privileged users to add scripts.
3536 3920 * A site that uses the DISALLOW_UNFILTERED_HTML always remove scripts on echo.
3537 3921 *
3538 3922 * @since 5.0.13
3539 3923 *
3540 3924 * @param string $value
3541 - * @param array|string $allowed 'all' for everything included as defaults
3925 + * @param array|string $allowed 'all' for everything included as defaults.
3542 3926 * @return string
3543 3927 */
3544 3928 public static function maybe_kses( $value, $allowed = 'all' ) {
3545 3929 if ( self::should_never_allow_unfiltered_html() ) {
@@ -3548,8 +3932,64 @@
3548 3932 return $value;
3549 3933 }
3550 3934
3551 3935 /**
3936 + * Check if an option attribute used in an [input] shortcode is safe.
3937 + *
3938 + * @since 6.11.2
3939 + *
3940 + * @param string $key
3941 + * @param string $context Either 'display' or 'update'. On update, we want to allow a few keys that are never displayed.
3942 + * @return bool
3943 + */
3944 + public static function input_key_is_safe( $key, $context = 'display' ) {
3945 + if ( 'update' === $context && in_array( $key, array( 'opt', 'label' ), true ) ) {
3946 + $safe = true;
3947 + } elseif ( 0 === strpos( $key, 'data-' ) ) {
3948 + // Allow all data attributes.
3949 + $safe = true;
3950 + } elseif ( 0 === strpos( $key, 'aria-' ) ) {
3951 + // Allow all aria attributes.
3952 + $safe = true;
3953 + } else {
3954 + $safe_keys = array(
3955 + 'class',
3956 + 'required',
3957 + 'title',
3958 + 'placeholder',
3959 + 'value',
3960 + 'readonly',
3961 + 'disabled',
3962 + 'size',
3963 + 'maxlength',
3964 + 'min',
3965 + 'max',
3966 + 'pattern',
3967 + 'step',
3968 + 'autofocus',
3969 + 'width',
3970 + 'height',
3971 + 'autocomplete',
3972 + 'tabindex',
3973 + 'role',
3974 + 'style',
3975 + );
3976 + $safe = in_array( $key, $safe_keys, true );
3977 + }//end if
3978 +
3979 + /**
3980 + * Filter the $safe value so additional keys can be allowed or disallowed.
3981 + *
3982 + * @since 6.11.2
3983 + *
3984 + * @param bool $safe True if the key is considered safe.
3985 + * @param string $key
3986 + * @param string $context Either 'display' or 'update'.
3987 + */
3988 + return (bool) apply_filters( 'frm_input_key_is_safe', $safe, $key, $context );
3989 + }
3990 +
3991 + /**
3552 3992 * @since 5.0.16
3553 3993 *
3554 3994 * @return bool
3555 3995 */
@@ -3574,20 +4014,9 @@
3574 4014
3575 4015 /**
3576 4016 * @since 5.0.17
3577 4017 *
3578 - * @param string $plugin
3579 - * @return string|false
3580 - */
3581 - private static function get_plan_required( $plugin ) {
3582 - $link = FrmAddonsController::install_link( $plugin );
3583 - return FrmFormsHelper::get_plan_required( $link );
3584 - }
3585 -
3586 - /**
3587 - * @since 5.0.17
3588 - *
3589 - * @param string
4018 + * @param string $feature
3590 4019 * @return bool
3591 4020 */
3592 4021 public static function show_new_feature( $feature ) {
3593 4022 $link = FrmAddonsController::install_link( $feature );
@@ -3660,9 +4089,9 @@
3660 4089 public static function show_pill_text( $text = null ) {
3661 4090 if ( null === $text ) {
3662 4091 $text = __( 'NEW', 'formidable' );
3663 4092 }
3664 - echo '<span class="frm-new-pill">' . esc_html( $text ) . '</span>';
4093 + echo '<span class="frm-meta-tag frm-new-pill">' . esc_html( $text ) . '</span>';
3665 4094 }
3666 4095
3667 4096 /**
3668 4097 * Count the number of decimals digits.
@@ -3669,9 +4098,9 @@
3669 4098 *
3670 4099 * @since 5.2.07
3671 4100 *
3672 4101 * @param mixed $num Number.
3673 - * @return int|false Returns `false` if the passed parameter is not number.
4102 + * @return false|int Returns `false` if the passed parameter is not number.
3674 4103 */
3675 4104 public static function count_decimals( $num ) {
3676 4105 if ( ! is_numeric( $num ) ) {
3677 4106 return false;
@@ -3702,9 +4131,9 @@
3702 4131 }
3703 4132
3704 4133 add_filter(
3705 4134 'option_gmt_offset',
3706 - function( $offset ) {
4135 + function ( $offset ) {
3707 4136 if ( ! is_string( $offset ) || is_numeric( $offset ) ) {
3708 4137 // Leave a valid value alone.
3709 4138 return $offset;
3710 4139 }
@@ -3786,65 +4215,8 @@
3786 4215 return true;
3787 4216 }
3788 4217
3789 4218 /**
3790 - * @since 4.08
3791 - * @deprecated 4.09.01
3792 - */
3793 - public static function expiring_message() {
3794 - _deprecated_function( __METHOD__, '4.09.01', 'FrmProAddonsController::expiring_message' );
3795 - if ( is_callable( 'FrmProAddonsController::expiring_message' ) ) {
3796 - FrmProAddonsController::expiring_message();
3797 - }
3798 - }
3799 -
3800 - /**
3801 - * Use the WP 4.7 wp_doing_ajax function
3802 - *
3803 - * @since 2.05.07
3804 - * @deprecated 4.04.04
3805 - */
3806 - public static function wp_doing_ajax() {
3807 - _deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
3808 - return wp_doing_ajax();
3809 - }
3810 -
3811 - /**
3812 - * @deprecated 4.0
3813 - */
3814 - public static function insert_opt_html( $args ) {
3815 - _deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
3816 - FrmFormsHelper::insert_opt_html( $args );
3817 - }
3818 -
3819 - /**
3820 - * @deprecated 3.01
3821 - * @codeCoverageIgnore
3822 - */
3823 - public static function sanitize_array( &$values ) {
3824 - FrmDeprecated::sanitize_array( $values );
3825 - }
3826 -
3827 - /**
3828 - * @since 2.0
3829 - * @deprecated 5.0.13
3830 - *
3831 - * @return string The base Google APIS url for the current version of jQuery UI
3832 - */
3833 - public static function jquery_ui_base_url() {
3834 - _deprecated_function( __FUNCTION__, '5.0.13', 'FrmProAppHelper::jquery_ui_base_url' );
3835 - return is_callable( 'FrmProAppHelper::jquery_ui_base_url' ) ? FrmProAppHelper::jquery_ui_base_url() : '';
3836 - }
3837 -
3838 - /**
3839 - * @since 4.07
3840 - * @deprecated 6.0
3841 - */
3842 - public static function renewal_message() {
3843 - _deprecated_function( __METHOD__, '6.0', 'FrmProAddonsController::renewal_message' );
3844 - }
3845 -
3846 - /**
3847 4219 * Display a dismissable warning message and save its dismissal state.
3848 4220 *
3849 4221 * @since 6.3
3850 4222 *
@@ -3856,9 +4228,9 @@
3856 4228 if ( ! $message || ! $option ) {
3857 4229 return;
3858 4230 }
3859 4231
3860 - $ajax_callback = function() use ( $option ) {
4232 + $ajax_callback = function () use ( $option ) {
3861 4233 self::dismiss_warning_message( $option );
3862 4234 };
3863 4235
3864 4236 // We're handling JS codes with `doJsonPost` and it adds 'frm_' to the beginning of the action.
@@ -3866,9 +4238,9 @@
3866 4238 add_action( 'wp_ajax_frm_' . $option, $ajax_callback );
3867 4239
3868 4240 add_filter(
3869 4241 'frm_message_list',
3870 - function( $show_messages ) use ( $message, $option ) {
4242 + function ( $show_messages ) use ( $message, $option ) {
3871 4243 if ( get_option( $option, false ) ) {
3872 4244 return $show_messages;
3873 4245 }
3874 4246
@@ -3875,9 +4247,9 @@
3875 4247 $dismiss_icon = self::icon_by_class(
3876 4248 'frmfont frm_close_icon',
3877 4249 array(
3878 4250 'aria-label' => _x( 'Dismiss', 'warning message: close icon label', 'formidable' ),
3879 - 'echo' => false,
4251 + 'echo' => false,
3880 4252 )
3881 4253 );
3882 4254
3883 4255 $show_messages[] = $message;
@@ -3904,6 +4276,100 @@
3904 4276 update_option( $option, true, 'no' );
3905 4277 }
3906 4278
3907 4279 wp_send_json_success();
4280 + }
4281 +
4282 + /**
4283 + * Lite license copy.
4284 + * Used in FrmDashboardController & FrmSettingsController
4285 + *
4286 + * @since 6.8
4287 + *
4288 + * @return string
4289 + */
4290 + public static function copy_for_lite_license() {
4291 + $message = __( 'You\'re using Formidable Forms Lite - no license needed. Enjoy!', 'formidable' ) . ' 🙂';
4292 +
4293 + if ( is_callable( 'FrmProAddonsController::get_readable_license_type' ) && ! class_exists( 'FrmProDashboardController' ) ) {
4294 + // Manage PRO versions without PRO dashboard functionality.
4295 + $license_type = FrmProAddonsController::get_readable_license_type();
4296 + if ( 'lite' !== strtolower( $license_type ) ) {
4297 + $message = 'Formidable Pro ' . $license_type;
4298 + }
4299 + }
4300 +
4301 + return apply_filters( 'frm_license_type_text', $message );
4302 + }
4303 +
4304 + /**
4305 + * Removes scripts that are unnecessarily loaded across the pages!
4306 + *
4307 + * @since 6.9
4308 + * @return void
4309 + */
4310 + public static function dequeue_extra_global_scripts() {
4311 + wp_dequeue_script( 'frm-surveys-admin' );
4312 + wp_dequeue_script( 'frm-quizzes-form-action' );
4313 + }
4314 +
4315 + /**
4316 + * Shows tooltip icon.
4317 + *
4318 + * @since 6.12
4319 + *
4320 + * @param string $tooltip_text Tooltip text.
4321 + * @param array $atts Tooltip wrapper HTML attributes.
4322 + *
4323 + * @return void
4324 + */
4325 + public static function tooltip_icon( $tooltip_text, $atts = array() ) {
4326 + $atts['title'] = $tooltip_text;
4327 + if ( isset( $atts['class'] ) ) {
4328 + $atts['class'] .= ' frm_help';
4329 + } else {
4330 + $atts['class'] = 'frm_help';
4331 + }
4332 + ?>
4333 + <span <?php self::array_to_html_params( $atts, true ); ?>>
4334 + <?php self::icon_by_class( 'frmfont frm_tooltip_icon' ); ?>
4335 + </span>
4336 + <?php
4337 + }
4338 +
4339 + /**
4340 + * Prints errors for settings in onboarding wizard or template settings.
4341 + *
4342 + * @since 6.15
4343 + *
4344 + * @param array $args Args.
4345 + *
4346 + * @return void
4347 + */
4348 + public static function print_setting_error( $args ) {
4349 + $args = wp_parse_args(
4350 + $args,
4351 + array(
4352 + 'id' => '',
4353 + 'errors' => array(),
4354 + 'class' => '',
4355 + )
4356 + );
4357 +
4358 + $args['class'] .= ' frm-validation-error frm-mt-xs frm_hidden';
4359 + ?>
4360 + <span id="<?php echo esc_attr( $args['id'] ); ?>" class="<?php echo esc_attr( $args['class'] ); ?>">
4361 + <?php
4362 + if ( is_array( $args['errors'] ) ) {
4363 + foreach ( $args['errors'] as $key => $msg ) {
4364 + ?>
4365 + <span frm-error="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $msg ); ?></span>
4366 + <?php
4367 + }
4368 + } else {
4369 + echo '<span>' . esc_html( $args['errors'] ) . '</span>';
4370 + }
4371 + ?>
4372 + </span>
4373 + <?php
3908 4374 }
3909 4375 }