PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.13
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.13
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 +750 -332 6.46.13 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.4';
36 + public static $plug_version = '6.13';
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,16 @@
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 + printf(
1371 + /* translators: %1$s: Start link HTML, %2$s: End link HTML */
1372 + esc_html__( 'You\'re using Formidable Forms Lite. To unlock more features consider %1$supgrading to PRO%2$s.', 'formidable' ),
1373 + '<a href="' . esc_url( self::admin_upgrade_link( 'settings-license' ) ) . '">',
1374 + '</a>'
1375 + );
1376 + ?>
1180 1377 </div>
1181 1378 <?php
1182 1379 }
1183 1380
@@ -1194,8 +1391,10 @@
1194 1391 * Render a button for a new item (Form, Application, etc).
1195 1392 *
1196 1393 * @since 3.0
1197 1394 * @param array $atts {
1395 + * Details about the button.
1396 + *
1198 1397 * @type array $link_hook Custom link hook, calls do_action and exits early.
1199 1398 * @type string $new_link Href value, default #.
1200 1399 * @type string $class Custom class names, space separated.
1201 1400 * @type string $button_text Button text. Default "Add New".
@@ -1207,9 +1406,9 @@
1207 1406 do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
1208 1407 return;
1209 1408 }
1210 1409
1211 - if ( empty( $atts['new_link'] ) && empty( $atts['trigger_new_form_modal'] ) && empty( $atts['class'] ) ) {
1410 + if ( empty( $atts['new_link'] ) && empty( $atts['create_form'] ) && empty( $atts['class'] ) ) {
1212 1411 // Do not render a button if none of these attributes are set.
1213 1412 return;
1214 1413 }
1215 1414
@@ -1215,12 +1414,8 @@
1215 1414
1216 1415 $href = ! empty( $atts['new_link'] ) ? esc_url( $atts['new_link'] ) : '#';
1217 1416 $class = 'button button-primary frm-button-primary';
1218 1417
1219 - if ( ! empty( $atts['trigger_new_form_modal'] ) ) {
1220 - $class .= ' frm-trigger-new-form-modal';
1221 - }
1222 -
1223 1418 if ( ! empty( $atts['class'] ) ) {
1224 1419 $class .= ' ' . $atts['class'];
1225 1420 }
1226 1421
@@ -1237,10 +1432,11 @@
1237 1432 'placeholder' => '',
1238 1433 'tosearch' => '',
1239 1434 'text' => __( 'Search', 'formidable' ),
1240 1435 'input_id' => '',
1436 + 'value' => false,
1241 1437 );
1242 - $atts = array_merge( $defaults, $atts );
1438 + $atts = array_merge( $defaults, $atts );
1243 1439
1244 1440 if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
1245 1441 $atts['tosearch'] = 'frm-card';
1246 1442 }
@@ -1251,8 +1447,27 @@
1251 1447 }
1252 1448
1253 1449 $input_id = $atts['input_id'] . '-search-input';
1254 1450
1451 + $input_atts = array(
1452 + 'type' => 'search',
1453 + 'id' => $input_id,
1454 + 'name' => 's',
1455 + 'placeholder' => $atts['placeholder'],
1456 + 'class' => $class,
1457 + 'data-tosearch' => $atts['tosearch'],
1458 + );
1459 +
1460 + if ( is_string( $atts['value'] ) ) {
1461 + $input_atts['value'] = $atts['value'];
1462 + } elseif ( isset( $_REQUEST['s'] ) ) {
1463 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1464 + $input_atts['value'] = wp_unslash( $_REQUEST['s'] );
1465 + }
1466 +
1467 + if ( ! empty( $atts['tosearch'] ) ) {
1468 + $input_atts['autocomplete'] = 'off';
1469 + }
1255 1470 ?>
1256 1471 <p class="frm-search">
1257 1472 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1258 1473 <?php echo esc_html( $atts['text'] ); ?>:
@@ -1257,15 +1472,9 @@
1257 1472 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1258 1473 <?php echo esc_html( $atts['text'] ); ?>:
1259 1474 </label>
1260 1475 <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 - />
1476 + <input <?php self::array_to_html_params( $input_atts, true ); ?> />
1268 1477 <?php
1269 1478 if ( empty( $atts['tosearch'] ) ) {
1270 1479 submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
1271 1480 }
@@ -1275,8 +1484,9 @@
1275 1484 }
1276 1485
1277 1486 /**
1278 1487 * @param string $type
1488 + * @return void
1279 1489 */
1280 1490 public static function trigger_hook_load( $type, $object = null ) {
1281 1491 // Only load the form hooks once.
1282 1492 $hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
@@ -1285,11 +1495,14 @@
1285 1495 }
1286 1496 }
1287 1497
1288 1498 /**
1289 - * Save all front-end js scripts into a single file
1499 + * Save all front-end js scripts into a single file.
1500 + * And save an additional single file of all front-end Stripe JS scripts.
1290 1501 *
1291 1502 * @since 3.0
1503 + *
1504 + * @return void
1292 1505 */
1293 1506 public static function save_combined_js() {
1294 1507 $file_atts = apply_filters(
1295 1508 'frm_js_location',
@@ -1302,10 +1515,34 @@
1302 1515
1303 1516 $files = array(
1304 1517 self::plugin_path() . '/js/formidable.min.js',
1305 1518 );
1519 + /**
1520 + * @param array $files
1521 + */
1306 1522 $files = apply_filters( 'frm_combined_js_files', $files );
1307 1523 $new_file->combine_files( $files );
1524 +
1525 + // Create the minified Stripe Script.
1526 + $file_atts = apply_filters(
1527 + 'frm_stripe_js_location',
1528 + array(
1529 + 'file_name' => 'frmstrp.min.js',
1530 + 'new_file_path' => self::plugin_path() . '/js',
1531 + )
1532 + );
1533 + $new_file = new FrmCreateFile( $file_atts );
1534 + $files = array(
1535 + FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.min.js',
1536 + );
1537 +
1538 + /**
1539 + * @since 6.5
1540 + *
1541 + * @param array $files
1542 + */
1543 + $files = apply_filters( 'frm_stripe_combined_js_files', $files );
1544 + $new_file->combine_files( $files );
1308 1545 }
1309 1546
1310 1547 /**
1311 1548 * Check a value from a shortcode to see if true or false.
@@ -1312,14 +1549,14 @@
1312 1549 * True when value is 1, true, 'true', 'yes'
1313 1550 *
1314 1551 * @since 1.07.10
1315 1552 *
1316 - * @param string $value The value to compare
1553 + * @param string $value The value to compare.
1317 1554 *
1318 - * @return boolean True or False
1555 + * @return bool
1319 1556 */
1320 1557 public static function is_true( $value ) {
1321 - return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1558 + return true === $value || 1 == $value || 'true' === $value || 'yes' === $value;
1322 1559 }
1323 1560
1324 1561 /**
1325 1562 * Gets all post from a specific post type.
@@ -1385,9 +1622,9 @@
1385 1622
1386 1623 wp_enqueue_script( 'jquery-ui-autocomplete' );
1387 1624
1388 1625 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1389 - $title = '';
1626 + $title = '';
1390 1627
1391 1628 if ( $selected ) {
1392 1629 $title = get_the_title( $selected );
1393 1630 }
@@ -1403,11 +1640,11 @@
1403 1640 <?php
1404 1641 }
1405 1642
1406 1643 /**
1407 - * @param array $args
1408 - * @param string $page_id Deprecated.
1409 - * @param boolean $truncate Deprecated.
1644 + * @param array $args
1645 + * @param string $page_id Deprecated.
1646 + * @param bool $truncate Deprecated.
1410 1647 */
1411 1648 public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1412 1649 self::prep_page_dropdown_params( $page_id, $truncate, $args );
1413 1650
@@ -1451,13 +1688,13 @@
1451 1688 * @since 4.10.01 Added `post_type` and `autocomplete_placeholder` to the arguments array.
1452 1689 */
1453 1690 private static function preformat_selection_args( $args ) {
1454 1691 $defaults = array(
1455 - 'truncate' => false,
1456 - 'placeholder' => ' ',
1457 - 'field_name' => '',
1458 - 'page_id' => '',
1459 - 'post_type' => 'page',
1692 + 'truncate' => false,
1693 + 'placeholder' => ' ',
1694 + 'field_name' => '',
1695 + 'page_id' => '',
1696 + 'post_type' => 'page',
1460 1697 'autocomplete_placeholder' => __( 'Select a Page', 'formidable' ),
1461 1698 );
1462 1699
1463 1700 return array_merge( $defaults, $args );
@@ -1537,16 +1774,16 @@
1537 1774 return $link;
1538 1775 }
1539 1776
1540 1777 /**
1541 - * @param string $field_name
1542 - * @param string|array $capability
1543 - * @param string $multiple 'single' and 'multiple'
1778 + * @param string $field_name
1779 + * @param array|string $capability
1780 + * @param string $multiple 'single' and 'multiple'.
1544 1781 */
1545 1782 public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1546 1783 ?>
1547 1784 <select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1548 - <?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1785 + <?php echo 'multiple' === $multiple ? 'multiple="multiple"' : ''; ?>
1549 1786 class="frm_multiselect">
1550 1787 <?php self::roles_options( $capability ); ?>
1551 1788 </select>
1552 1789 <?php
@@ -1554,9 +1791,9 @@
1554 1791
1555 1792 /**
1556 1793 * @since 4.07
1557 1794 * @param array|string $selected
1558 - * @param string $current
1795 + * @param string $current
1559 1796 */
1560 1797 private static function selected( $selected, $current ) {
1561 1798 if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1562 1799 FrmProAppHelper::selected( $selected, $current );
@@ -1565,9 +1802,9 @@
1565 1802 }
1566 1803 }
1567 1804
1568 1805 /**
1569 - * @param string|array $capability
1806 + * @param array|string $capability
1570 1807 */
1571 1808 public static function roles_options( $capability ) {
1572 1809 global $frm_vars;
1573 1810 if ( isset( $frm_vars['editable_roles'] ) ) {
@@ -1579,9 +1816,9 @@
1579 1816
1580 1817 foreach ( $editable_roles as $role => $details ) {
1581 1818 $name = translate_user_role( $details['name'] );
1582 1819 ?>
1583 - <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_attr( $name ); ?> </option>
1820 + <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_html( $name ); ?> </option>
1584 1821 <?php
1585 1822 unset( $role, $details );
1586 1823 }
1587 1824 }
@@ -1602,9 +1839,8 @@
1602 1839 $pro_cap = array(
1603 1840 'frm_create_entries' => __( 'Add Entries from Admin Area', 'formidable' ),
1604 1841 'frm_edit_entries' => __( 'Edit Entries from Admin Area', 'formidable' ),
1605 1842 'frm_view_reports' => __( 'View Reports', 'formidable' ),
1606 - 'frm_edit_displays' => __( 'Add/Edit Views', 'formidable' ),
1607 1843 );
1608 1844 /**
1609 1845 * @since 5.3.1
1610 1846 *
@@ -1611,8 +1847,14 @@
1611 1847 * @param array<string,string> $pro_cap
1612 1848 */
1613 1849 $pro_cap = apply_filters( 'frm_pro_capabilities', $pro_cap );
1614 1850
1851 + if ( ! array_key_exists( 'frm_edit_displays', $pro_cap ) && is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed() ) {
1852 + // For backward compatibility, add the Add/Edit Views permission if Pro is not up to date.
1853 + // This was added in 6.5.4. Remove this in the future.
1854 + $pro_cap['frm_edit_displays'] = __( 'Add/Edit Views', 'formidable' );
1855 + }
1856 +
1615 1857 if ( 'pro_only' === $type ) {
1616 1858 return $pro_cap;
1617 1859 }
1618 1860
@@ -1627,9 +1869,9 @@
1627 1869 * @return array<string,string>
1628 1870 */
1629 1871 private static function get_lite_capabilities() {
1630 1872 return array(
1631 - 'frm_view_forms' => __( 'View Forms', 'formidable' ),
1873 + 'frm_view_forms' => __( 'View Forms List', 'formidable' ),
1632 1874 'frm_edit_forms' => __( 'Add and Edit Forms', 'formidable' ),
1633 1875 'frm_delete_forms' => __( 'Delete Forms', 'formidable' ),
1634 1876 'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1635 1877 'frm_view_entries' => __( 'View Entries from Admin Area', 'formidable' ),
@@ -1670,9 +1912,9 @@
1670 1912 return current_user_can( $role );
1671 1913 }
1672 1914
1673 1915 /**
1674 - * @param string|array $needed_role
1916 + * @param array|string $needed_role
1675 1917 * @return bool
1676 1918 */
1677 1919 public static function user_has_permission( $needed_role ) {
1678 1920 if ( is_array( $needed_role ) ) {
@@ -1728,8 +1970,11 @@
1728 1970 /**
1729 1971 * Make sure admins have permission to see the menu items
1730 1972 *
1731 1973 * @since 2.0.6
1974 + *
1975 + * @param string $cap
1976 + * @return void
1732 1977 */
1733 1978 public static function force_capability( $cap = 'frm_change_settings' ) {
1734 1979 if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1735 1980 $role = get_role( 'administrator' );
@@ -1740,9 +1985,9 @@
1740 1985 }
1741 1986 }
1742 1987
1743 1988 /**
1744 - * Check if the user has permision for action.
1989 + * Check if the user has permission for action.
1745 1990 * Return permission message and stop the action if no permission
1746 1991 *
1747 1992 * @since 2.0
1748 1993 *
@@ -1778,9 +2023,9 @@
1778 2023 if ( empty( $nonce_name ) ) {
1779 2024 return $error;
1780 2025 }
1781 2026
1782 - $nonce_value = ( $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
2027 + $nonce_value = $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
1783 2028 if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1784 2029 $frm_settings = self::get_settings();
1785 2030 $error = $frm_settings->admin_permission;
1786 2031 }
@@ -1794,12 +2039,13 @@
1794 2039 }
1795 2040 }
1796 2041
1797 2042 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 ) );
2043 + $values = self::recursive_function_map( $values, 'trim' );
2044 + $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1801 2045
2046 + $current = is_null( $current ) ? '' : htmlspecialchars_decode( trim( $current ) );
2047 +
1802 2048 return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1803 2049 }
1804 2050
1805 2051 public static function recursive_function_map( $value, $function ) {
@@ -1819,8 +2065,9 @@
1819 2065 }
1820 2066 }
1821 2067 }
1822 2068 } else {
2069 + $value = self::maybe_update_value_if_null( $value, $function );
1823 2070 $value = call_user_func( $function, $value );
1824 2071 }
1825 2072
1826 2073 return $value;
@@ -1825,8 +2072,24 @@
1825 2072
1826 2073 return $value;
1827 2074 }
1828 2075
2076 + /**
2077 + * Updates value to empty string if it is null and being passed to a string function.
2078 + *
2079 + * @since 6.8.4
2080 + * @param mixed $value
2081 + * @param string $function
2082 + * @return mixed
2083 + */
2084 + private static function maybe_update_value_if_null( $value, $function ) {
2085 + if ( null === $value && in_array( $function, array( 'trim', 'strlen' ), true ) ) {
2086 + $value = '';
2087 + }
2088 +
2089 + return $value;
2090 + }
2091 +
1829 2092 public static function is_assoc( $array ) {
1830 2093 return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1831 2094 }
1832 2095
@@ -1837,14 +2100,12 @@
1837 2100 $return = array();
1838 2101 foreach ( $array as $key => $value ) {
1839 2102 if ( is_array( $value ) ) {
1840 2103 $return = array_merge( $return, self::array_flatten( $value, $keys ) );
2104 + } elseif ( $keys === 'keep' ) {
2105 + $return[ $key ] = $value;
1841 2106 } else {
1842 - if ( $keys == 'keep' ) {
1843 - $return[ $key ] = $value;
1844 - } else {
1845 - $return[] = $value;
1846 - }
2107 + $return[] = $value;
1847 2108 }
1848 2109 }
1849 2110
1850 2111 return $return;
@@ -1849,8 +2110,13 @@
1849 2110
1850 2111 return $return;
1851 2112 }
1852 2113
2114 + /**
2115 + * @param string $text
2116 + * @param bool $is_rich_text
2117 + * @return string
2118 + */
1853 2119 public static function esc_textarea( $text, $is_rich_text = false ) {
1854 2120 $safe_text = str_replace( '&quot;', '"', $text );
1855 2121 if ( ! $is_rich_text ) {
1856 2122 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
@@ -1856,9 +2122,13 @@
1856 2122 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1857 2123 }
1858 2124 $safe_text = str_replace( '&amp; ', '& ', $safe_text );
1859 2125
1860 - return apply_filters( 'esc_textarea', $safe_text, $text );
2126 + /**
2127 + * @param string $safe_text
2128 + * @param string $text
2129 + */
2130 + return (string) apply_filters( 'esc_textarea', $safe_text, $text );
1861 2131 }
1862 2132
1863 2133 /**
1864 2134 * Add auto paragraphs to text areas
@@ -1909,12 +2179,12 @@
1909 2179 * @since 5.0.13 added $echo param.
1910 2180 *
1911 2181 * @param string $url
1912 2182 * @param bool $echo
1913 - * @return string|void
2183 + * @return string|null
1914 2184 */
1915 2185 public static function js_redirect( $url, $echo = false ) {
1916 - $callback = function() use ( $url ) {
2186 + $callback = function () use ( $url ) {
1917 2187 echo '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1918 2188 };
1919 2189 return self::clip( $callback, $echo );
1920 2190 }
@@ -1924,9 +2194,9 @@
1924 2194 return $user_id;
1925 2195 }
1926 2196
1927 2197 $user_id = sanitize_text_field( $user_id );
1928 - if ( $user_id == 'current' ) {
2198 + if ( $user_id === 'current' ) {
1929 2199 $user_id = get_current_user_id();
1930 2200 } else {
1931 2201 if ( is_email( $user_id ) ) {
1932 2202 $user = get_user_by( 'email', $user_id );
@@ -1942,8 +2212,13 @@
1942 2212
1943 2213 return $user_id;
1944 2214 }
1945 2215
2216 + /**
2217 + * @param string $filename
2218 + * @param array $atts
2219 + * @return false|string
2220 + */
1946 2221 public static function get_file_contents( $filename, $atts = array() ) {
1947 2222 if ( ! is_file( $filename ) ) {
1948 2223 return false;
1949 2224 }
@@ -1949,9 +2224,9 @@
1949 2224 }
1950 2225
1951 2226 extract( $atts ); // phpcs:ignore WordPress.PHP.DontExtract
1952 2227 ob_start();
1953 - include( $filename );
2228 + include $filename;
1954 2229 $contents = ob_get_contents();
1955 2230 ob_end_clean();
1956 2231
1957 2232 return $contents;
@@ -2006,9 +2281,9 @@
2006 2281 ++$suffix;
2007 2282 } while ( in_array( $key_check, $similar_keys, true ) );
2008 2283
2009 2284 $key = $key_check;
2010 - }
2285 + }//end if
2011 2286
2012 2287 return $key;
2013 2288 }
2014 2289
@@ -2052,9 +2327,11 @@
2052 2327 * @return string
2053 2328 */
2054 2329 private static function generate_new_key( $num_chars ) {
2055 2330 $max_slug_value = pow( 36, $num_chars );
2056 - $min_slug_value = 37; // we want to have at least 2 characters in the slug
2331 +
2332 + // We want to have at least 2 characters in the slug.
2333 + $min_slug_value = 37;
2057 2334 return base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
2058 2335 }
2059 2336
2060 2337 /**
@@ -2083,11 +2360,16 @@
2083 2360
2084 2361 /**
2085 2362 * Editing a Form or Entry
2086 2363 *
2087 - * @param string $table
2364 + * @param object $record
2365 + * @param string $table
2366 + * @param array|string $fields
2367 + * @param bool $default
2368 + * @param array $post_values
2369 + * @param array $args
2088 2370 *
2089 - * @return bool|array
2371 + * @return array|bool
2090 2372 */
2091 2373 public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
2092 2374 if ( ! $record ) {
2093 2375 return false;
@@ -2140,13 +2422,12 @@
2140 2422 $post_values = $args['post_values'];
2141 2423
2142 2424 if ( $args['default'] ) {
2143 2425 $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 - }
2426 + } elseif ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2427 + if ( ! isset( $field->field_options['custom_field'] ) ) {
2428 + $field->field_options['custom_field'] = '';
2429 + }
2149 2430 $meta_value = FrmProEntryMetaHelper::get_post_value(
2150 2431 $record->post_id,
2151 2432 $field->field_options['post_field'],
2152 2433 $field->field_options['custom_field'],
@@ -2156,12 +2437,11 @@
2156 2437 'form_id' => $field->form_id,
2157 2438 'field' => $field,
2158 2439 )
2159 2440 );
2160 - } else {
2161 - $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2162 - }
2163 - }
2441 + } else {
2442 + $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2443 + }//end if
2164 2444
2165 2445 $field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
2166 2446 if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
2167 2447 $new_value = $post_values['item_meta'][ $field->id ];
@@ -2209,12 +2489,15 @@
2209 2489 );
2210 2490 }
2211 2491
2212 2492 /**
2493 + * @param object $record
2213 2494 * @param string $table
2495 + * @param array $post_values
2496 + * @param array $values
2214 2497 */
2215 2498 private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
2216 - if ( $table == 'entries' ) {
2499 + if ( $table === 'entries' ) {
2217 2500 $form = $record->form_id;
2218 2501 FrmForm::maybe_get_form( $form );
2219 2502 } else {
2220 2503 $form = $record;
@@ -2250,9 +2533,9 @@
2250 2533 $form_defaults = FrmFormsHelper::get_default_opts();
2251 2534
2252 2535 foreach ( $form_defaults as $opt => $default ) {
2253 2536 if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
2254 - $values[ $opt ] = ( $post_values && isset( $post_values['options'][ $opt ] ) ) ? $post_values['options'][ $opt ] : $default;
2537 + $values[ $opt ] = $post_values && isset( $post_values['options'][ $opt ] ) ? $post_values['options'][ $opt ] : $default;
2255 2538 }
2256 2539
2257 2540 unset( $opt, $default );
2258 2541 }
@@ -2273,9 +2556,9 @@
2273 2556 * @since 2.2.10
2274 2557 *
2275 2558 * @param array $post_values
2276 2559 *
2277 - * @return boolean|int
2560 + * @return bool|int
2278 2561 */
2279 2562 public static function custom_style_value( $post_values ) {
2280 2563 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2281 2564 $custom_style = absint( $post_values['options']['custom_style'] );
@@ -2280,29 +2563,37 @@
2280 2563 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2281 2564 $custom_style = absint( $post_values['options']['custom_style'] );
2282 2565 } else {
2283 2566 $frm_settings = self::get_settings();
2284 - $custom_style = ( $frm_settings->load_style != 'none' );
2567 + $custom_style = ( $frm_settings->load_style !== 'none' );
2285 2568 }
2286 2569
2287 2570 return $custom_style;
2288 2571 }
2289 2572
2290 - public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
2291 - if ( is_array( $str ) ) {
2573 + /**
2574 + * @param mixed $original_string
2575 + * @param int|string $length
2576 + * @param int $minword
2577 + * @param string $continue
2578 + * @return string
2579 + */
2580 + public static function truncate( $original_string, $length, $minword = 3, $continue = '...' ) {
2581 + if ( ! is_string( $original_string ) && ! is_int( $original_string ) ) {
2292 2582 return '';
2293 2583 }
2294 2584
2295 2585 $length = (int) $length;
2296 - $str = wp_strip_all_tags( $str );
2586 + $str = wp_strip_all_tags( (string) $original_string );
2297 2587 $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
2298 2588
2299 2589 if ( $length == 0 ) {
2300 2590 return '';
2301 - } elseif ( $length <= 10 ) {
2591 + }
2592 +
2593 + if ( $length <= 10 ) {
2302 2594 $sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
2303 -
2304 - return $sub . ( ( $length < $original_len ) ? $continue : '' );
2595 + return $sub . ( $length < $original_len ? $continue : '' );
2305 2596 }
2306 2597
2307 2598 $sub = '';
2308 2599 $len = 0;
@@ -2308,10 +2599,14 @@
2308 2599 $len = 0;
2309 2600
2310 2601 $words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
2311 2602
2603 + if ( ! is_array( $words ) ) {
2604 + return $original_string;
2605 + }
2606 +
2312 2607 foreach ( $words as $word ) {
2313 - $part = ( ( $sub != '' ) ? ' ' : '' ) . $word;
2608 + $part = ( $sub != '' ? ' ' : '' ) . $word;
2314 2609 $total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
2315 2610 if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
2316 2611 break;
2317 2612 }
@@ -2325,11 +2620,37 @@
2325 2620
2326 2621 unset( $total_len, $word );
2327 2622 }
2328 2623
2329 - return $sub . ( ( $len < $original_len ) ? $continue : '' );
2624 + $sub = self::maybe_force_truncate_on_string_with_no_spaces( $sub, $length );
2625 +
2626 + return $sub . ( $len < $original_len ? $continue : '' );
2330 2627 }
2331 2628
2629 + /**
2630 + * If the string is still too long because there may not have been any spaces, force truncate.
2631 + *
2632 + * @since 6.5.4
2633 + *
2634 + * @param string $sub Current substring.
2635 + * @param int $length The length limit.
2636 + * @return string
2637 + */
2638 + private static function maybe_force_truncate_on_string_with_no_spaces( $sub, $length ) {
2639 + if ( strlen( $sub ) < $length + 50 ) {
2640 + // If the string isn't way over the limit, leave it.
2641 + return $sub;
2642 + }
2643 +
2644 + $first_space = strpos( $sub, ' ', $length );
2645 + if ( false !== $first_space ) {
2646 + // Ignore anything with spaces.
2647 + return $sub;
2648 + }
2649 +
2650 + return substr( $sub, 0, $length + 10 );
2651 + }
2652 +
2332 2653 public static function mb_function( $function_names, $args ) {
2333 2654 $mb_function_name = $function_names[0];
2334 2655 $function_name = $function_names[1];
2335 2656 if ( function_exists( $mb_function_name ) ) {
@@ -2386,12 +2707,12 @@
2386 2707 return date_i18n( $date_format, strtotime( $date ) );
2387 2708 }
2388 2709
2389 2710 /**
2390 - * Gets the time ago in words
2711 + * Gets the time ago in words.
2391 2712 *
2392 - * @param int $from in seconds
2393 - * @param int|string $to in seconds
2713 + * @param int $from In seconds.
2714 + * @param int|string $to In seconds.
2394 2715 *
2395 2716 * @return string $time_ago
2396 2717 */
2397 2718 public static function human_time_diff( $from, $to = '', $levels = 1 ) {
@@ -2406,9 +2727,9 @@
2406 2727 $diff_object = $now->diff( $ago );
2407 2728 $diff = get_object_vars( $diff_object );
2408 2729
2409 2730 // Add week amount and update day amount
2410 - $diff['w'] = floor( $diff['d'] / 7 );
2731 + $diff['w'] = floor( $diff['d'] / 7 );
2411 2732 $diff['d'] -= $diff['w'] * 7;
2412 2733
2413 2734 $time_strings = self::get_time_strings();
2414 2735
@@ -2415,9 +2736,9 @@
2415 2736 if ( ! is_numeric( $levels ) ) {
2416 2737 // Show time in specified unit.
2417 2738 $levels = self::get_unit( $levels );
2418 2739 if ( isset( $time_strings[ $levels ] ) ) {
2419 - $diff = array(
2740 + $diff = array(
2420 2741 $levels => self::time_format( $levels, $diff ),
2421 2742 );
2422 2743 $time_strings = array(
2423 2744 $levels => $time_strings[ $levels ],
@@ -2506,9 +2827,9 @@
2506 2827 }
2507 2828
2508 2829 /**
2509 2830 * Get the translatable time strings. The untranslated version is a failsafe
2510 - * in case langauges are changing for the unit set in the shortcode.
2831 + * in case languages are changing for the unit set in the shortcode.
2511 2832 *
2512 2833 * @since 2.0.20
2513 2834 * @return array
2514 2835 */
@@ -2554,23 +2875,28 @@
2554 2875
2555 2876 // Pagination Methods.
2556 2877
2557 2878 /**
2558 - * @param integer $current_p
2879 + * @param int $r_count
2880 + * @param int $current_p
2881 + * @param int $p_size
2882 + * @return int
2559 2883 */
2560 2884 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 ) );
2885 + return ( $r_count < $current_p * $p_size ? $r_count : $current_p * $p_size );
2562 2886 }
2563 2887
2564 2888 /**
2565 - * @param integer $current_p
2889 + * @param int $r_count
2890 + * @param int $current_p
2891 + * @param int $p_size
2892 + * @return int
2566 2893 */
2567 2894 public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2568 2895 if ( $current_p == 1 ) {
2569 2896 return 1;
2570 - } else {
2571 - return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2572 2897 }
2898 + return self::get_last_record_num( $r_count, $current_p - 1, $p_size ) + 1;
2573 2899 }
2574 2900
2575 2901 /**
2576 2902 * @return array
@@ -2593,9 +2919,9 @@
2593 2919 if ( ! isset( $l3 ) ) {
2594 2920 $l3 = $name;
2595 2921 }
2596 2922
2597 - $this_val = ( $p == $last ) ? $jv['value'] : array();
2923 + $this_val = $p == $last ? $jv['value'] : array();
2598 2924
2599 2925 switch ( $p ) {
2600 2926 case 0:
2601 2927 $l1 = $name;
@@ -2617,12 +2943,12 @@
2617 2943 self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2618 2944 }
2619 2945
2620 2946 unset( $this_val, $n );
2621 - }
2947 + }//end foreach
2622 2948
2623 2949 unset( $last, $jv );
2624 - }
2950 + }//end foreach
2625 2951
2626 2952 return $vars;
2627 2953 }
2628 2954
@@ -2870,8 +3196,11 @@
2870 3196 }
2871 3197
2872 3198 /**
2873 3199 * @since 4.02.03
3200 + *
3201 + * @param array|string $value
3202 + * @return string
2874 3203 */
2875 3204 public static function maybe_json_encode( $value ) {
2876 3205 if ( is_array( $value ) ) {
2877 3206 $value = wp_json_encode( $value );
@@ -2879,12 +3208,14 @@
2879 3208 return $value;
2880 3209 }
2881 3210
2882 3211 /**
3212 + * Echo The javascript to open and highlight the Formidable menu
3213 + *
2883 3214 * @since 1.07.10
2884 3215 *
2885 - * @param string $post_type The name of the post type that may need to be highlighted
2886 - * echo The javascript to open and highlight the Formidable menu
3216 + * @param string $post_type The name of the post type that may need to be highlighted.
3217 + * @return void
2887 3218 */
2888 3219 public static function maybe_highlight_menu( $post_type ) {
2889 3220 global $post;
2890 3221
@@ -2903,8 +3234,11 @@
2903 3234 /**
2904 3235 * Load the JS file on non-Formidable pages in the admin area
2905 3236 *
2906 3237 * @since 2.0
3238 + *
3239 + * @param bool $load
3240 + * @return void
2907 3241 */
2908 3242 public static function load_admin_wide_js( $load = true ) {
2909 3243 $version = self::plugin_version();
2910 3244 wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
@@ -2918,8 +3252,9 @@
2918 3252 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ),
2919 3253 'loading' => __( 'Loading&hellip;', 'formidable' ),
2920 3254 'nonce' => wp_create_nonce( 'frm_ajax' ),
2921 3255 'proIncludesSliderJs' => is_callable( 'FrmProFormsHelper::prepare_custom_currency' ),
3256 + 'inboxSlideIn' => FrmInbox::get_inbox_slide_in_value_for_js(),
2922 3257 );
2923 3258 wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
2924 3259
2925 3260 if ( $load ) {
@@ -2928,8 +3263,9 @@
2928 3263 }
2929 3264
2930 3265 /**
2931 3266 * @since 2.0.9
3267 + * @return void
2932 3268 */
2933 3269 public static function load_font_style() {
2934 3270 wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
2935 3271 }
@@ -2935,99 +3271,128 @@
2935 3271 }
2936 3272
2937 3273 /**
2938 3274 * @param string $location
3275 + * @return void
2939 3276 */
2940 3277 public static function localize_script( $location ) {
2941 3278 global $wp_scripts;
2942 3279
2943 - $ajax_url = admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' );
2944 - $ajax_url = apply_filters( 'frm_ajax_url', $ajax_url );
2945 -
2946 3280 $script_strings = array(
2947 - 'ajax_url' => $ajax_url,
2948 - 'images_url' => self::plugin_url() . '/images',
2949 - 'loading' => __( 'Loading&hellip;', 'formidable' ),
2950 - 'remove' => __( 'Remove', 'formidable' ),
2951 - 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
2952 - 'nonce' => wp_create_nonce( 'frm_ajax' ),
2953 - 'id' => __( 'ID', 'formidable' ),
2954 - 'no_results' => __( 'No results match', 'formidable' ),
2955 - 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
2956 - 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
2957 - 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
2958 - 'focus_first_error' => self::should_focus_first_error(),
2959 - 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3281 + 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3282 + 'images_url' => self::plugin_url() . '/images',
3283 + 'loading' => __( 'Loading&hellip;', 'formidable' ),
3284 + 'remove' => __( 'Remove', 'formidable' ),
3285 + 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3286 + 'nonce' => wp_create_nonce( 'frm_ajax' ),
3287 + 'id' => __( 'ID', 'formidable' ),
3288 + 'no_results' => __( 'No results match', 'formidable' ),
3289 + 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3290 + 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3291 + 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3292 + 'focus_first_error' => self::should_focus_first_error(),
3293 + 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3294 + // We need to keep this setting for a few versions because Pro checks for this.
3295 + 'include_resend_email' => false,
2960 3296 );
2961 3297
2962 3298 $data = $wp_scripts->get_data( 'formidable', 'data' );
2963 - if ( empty( $data ) ) {
3299 + if ( ! $data ) {
2964 3300 wp_localize_script( 'formidable', 'frm_js', $script_strings );
2965 3301 }
2966 3302
2967 - if ( $location == 'admin' ) {
2968 - $frm_settings = self::get_settings();
3303 + if ( $location === 'admin' ) {
2969 3304 $admin_script_strings = array(
2970 - 'desc' => __( '(Click to add description)', 'formidable' ),
2971 - 'blank' => __( '(Blank)', 'formidable' ),
2972 - 'no_label' => __( '(no label)', 'formidable' ),
2973 - 'saving' => '', // Deprecated in 6.0.
2974 - 'saved' => '', // Deprecated in 6.0.
2975 - 'ok' => __( 'OK', 'formidable' ),
2976 - 'cancel' => __( 'Cancel', 'formidable' ),
2977 - 'default_label' => __( 'Default', 'formidable' ),
2978 - 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
2979 - 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
2980 - 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
2981 - 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
2982 - 'confirm' => __( 'Are you sure?', 'formidable' ),
2983 - 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
2984 - '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' ),
2985 - 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
2986 - 'default_unique' => $frm_settings->unique_msg,
2987 - 'default_conf' => __( 'The entered values do not match', 'formidable' ),
2988 - 'enter_email' => __( 'Enter Email', 'formidable' ),
2989 - 'confirm_email' => __( 'Confirm Email', 'formidable' ),
2990 - 'conditional_text' => __( 'Conditional content here', 'formidable' ),
2991 - 'new_option' => __( 'New Option', 'formidable' ),
2992 - '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' ),
2993 - 'enter_password' => __( 'Enter Password', 'formidable' ),
2994 - 'confirm_password' => __( 'Confirm Password', 'formidable' ),
2995 - 'import_complete' => __( 'Import Complete', 'formidable' ),
2996 - 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
2997 - 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
2998 - 'private_label' => __( 'Private', 'formidable' ),
2999 - 'jquery_ui_url' => '',
3000 - 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3001 - 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3002 - 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3003 - 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3004 - 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3005 - 'only_one_action' => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
3006 - 'unsafe_params' => FrmFormsHelper::reserved_words(),
3305 + 'desc' => __( '(Click to add description)', 'formidable' ),
3306 + 'blank' => __( '(Blank)', 'formidable' ),
3307 + 'no_label' => __( '(no label)', 'formidable' ),
3308 + 'ok' => __( 'OK', 'formidable' ),
3309 + 'cancel' => __( 'Cancel', 'formidable' ),
3310 + 'default_label' => __( 'Default', 'formidable' ),
3311 + 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3312 + 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3313 + 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3314 + 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3315 + 'confirm' => __( 'Are you sure?', 'formidable' ),
3316 + 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3317 + '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' ),
3318 + 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3319 + 'default_unique' => FrmFieldsHelper::default_unique_msg(),
3320 + 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3321 + 'enter_email' => __( 'Enter Email', 'formidable' ),
3322 + 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3323 + 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3324 + 'new_option' => __( 'New Option', 'formidable' ),
3325 + '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' ),
3326 + 'enter_password' => __( 'Enter Password', 'formidable' ),
3327 + 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3328 + 'import_complete' => __( 'Import Complete', 'formidable' ),
3329 + 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3330 + 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3331 + 'private_label' => __( 'Private', 'formidable' ),
3332 + 'jquery_ui_url' => '',
3333 + 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3334 + 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3335 + 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3336 + 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3337 + 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3338 + /* translators: %d is the number of allowed actions per form */
3339 + 'only_one_action' => sprintf( __( 'This form action is limited to %d per form.', 'formidable' ), 1 ),
3340 + 'edit_action_text' => __( 'Please edit the existing form action.', 'formidable' ),
3341 + 'unsafe_params' => FrmFormsHelper::reserved_words(),
3007 3342 /* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
3008 - 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3343 + 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3009 3344 /* 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. */
3010 - 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3011 - 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3012 - 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3013 - 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3014 - 'install' => __( 'Install', 'formidable' ),
3015 - 'active' => __( 'Active', 'formidable' ),
3016 - 'select_a_field' => __( 'Select a Field', 'formidable' ),
3017 - 'no_items_found' => __( 'No items found.', 'formidable' ),
3345 + 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3346 + 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3347 + 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3348 + 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3349 + 'install' => __( 'Install', 'formidable' ),
3350 + 'active' => __( 'Active', 'formidable' ),
3351 + 'installed' => __( 'Installed', 'formidable' ),
3352 + 'not_installed' => __( 'Not Installed', 'formidable' ),
3353 + 'select_a_field' => __( 'Select a Field', 'formidable' ),
3354 + 'no_items_found' => __( 'No items found.', 'formidable' ),
3018 3355 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3356 +
3357 + // Deprecated in 6.0.
3358 + 'saving' => '',
3359 +
3360 + // Deprecated in 6.0.
3361 + 'saved' => '',
3362 +
3363 + // translators: %1$s: HTML open tag, %2$s: HTML end tag.
3364 + 'holdShiftMsg' => esc_html__( 'You can hold %1$sShift%2$s on your keyboard to select multiple fields', 'formidable' ),
3019 3365 );
3366 + /**
3367 + * @param array $admin_script_strings
3368 + */
3020 3369 $admin_script_strings = apply_filters( 'frm_admin_script_strings', $admin_script_strings );
3021 3370
3022 3371 $data = $wp_scripts->get_data( 'formidable_admin', 'data' );
3023 - if ( empty( $data ) ) {
3372 + if ( ! $data ) {
3024 3373 wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
3025 3374 }
3026 - }
3375 + }//end if
3027 3376 }
3028 3377
3029 3378 /**
3379 + * @since 6.5
3380 + *
3381 + * @return string
3382 + */
3383 + public static function get_ajax_url() {
3384 + $ajax_url = admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' );
3385 +
3386 + /**
3387 + * @since 2.0.13
3388 + *
3389 + * @param string $ajax_url
3390 + */
3391 + return apply_filters( 'frm_ajax_url', $ajax_url );
3392 + }
3393 +
3394 + /**
3030 3395 * Returns whether or not the first errored input should be auto-focused (default true).
3031 3396 *
3032 3397 * @since 5.2.05
3033 3398 *
@@ -3052,9 +3417,10 @@
3052 3417 * Echo the message on the plugins listing page
3053 3418 *
3054 3419 * @since 1.07.10
3055 3420 *
3056 - * @param float $min_version The version the add-on requires
3421 + * @param float $min_version The version the add-on requires.
3422 + * @return void
3057 3423 */
3058 3424 public static function min_version_notice( $min_version ) {
3059 3425 $frm_version = self::plugin_version();
3060 3426
@@ -3088,9 +3454,8 @@
3088 3454 if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
3089 3455 return;
3090 3456 }
3091 3457
3092 - $pro_version = FrmProDb::$plug_version;
3093 3458 $expired = FrmAddonsController::is_license_expired();
3094 3459 ?>
3095 3460 <div class="frm-banner-alert frm_error_style frm_previous_install">
3096 3461 <?php
@@ -3108,8 +3473,11 @@
3108 3473 /**
3109 3474 * If Pro is installed, check the version number.
3110 3475 *
3111 3476 * @since 4.0.01
3477 + *
3478 + * @param string $min_version
3479 + * @return bool
3112 3480 */
3113 3481 public static function meets_min_pro_version( $min_version ) {
3114 3482 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3115 3483 }
@@ -3117,12 +3485,13 @@
3117 3485 /**
3118 3486 * Show a message if the browser or PHP version is below the recommendations.
3119 3487 *
3120 3488 * @since 4.0.02
3489 + * @return void
3121 3490 */
3122 3491 private static function php_version_notice() {
3123 3492 $message = array();
3124 - if ( version_compare( phpversion(), '5.6', '<' ) ) {
3493 + if ( version_compare( phpversion(), '7.0', '<' ) ) {
3125 3494 $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' );
3126 3495 }
3127 3496
3128 3497 $browser = self::get_server_value( 'HTTP_USER_AGENT' );
@@ -3261,16 +3630,10 @@
3261 3630 return $locales;
3262 3631 }
3263 3632
3264 3633 /**
3265 - * Output HTML containing reference text for accessibility
3266 - *
3267 - * @deprecated 5.1
3634 + * @return string
3268 3635 */
3269 - public static function multiselect_accessibility() {
3270 - _deprecated_function( __METHOD__, '5.1' );
3271 - }
3272 -
3273 3636 public static function get_menu_icon_class() {
3274 3637 if ( is_callable( 'FrmProAppHelper::get_settings' ) ) {
3275 3638 $settings = FrmProAppHelper::get_settings();
3276 3639 if ( is_object( $settings ) && ! empty( $settings->menu_icon ) ) {
@@ -3380,8 +3743,18 @@
3380 3743 return apply_filters( 'frm_images_dropdown_input_attrs', $input_attrs_str, $args );
3381 3744 }
3382 3745
3383 3746 /**
3747 + * @since 6.7.1
3748 + */
3749 + public static function get_images_dropdown_atts( $option, $args ) {
3750 + $image = self::get_images_dropdown_option_image( $option, $args );
3751 + $classes = self::get_images_dropdown_option_classes( $option, $args );
3752 + $custom_attrs = self::get_images_dropdown_option_html_attrs( $option, $args );
3753 + return compact( 'image', 'classes', 'custom_attrs' );
3754 + }
3755 +
3756 + /**
3384 3757 * Gets the image of each option in images_dropdown() method.
3385 3758 *
3386 3759 * @since 5.0.04
3387 3760 *
@@ -3392,9 +3765,9 @@
3392 3765 private static function get_images_dropdown_option_image( $option, $args ) {
3393 3766 $image = self::icon_by_class(
3394 3767 'frmfont ' . $option['svg'],
3395 3768 array(
3396 - 'echo' => false,
3769 + 'echo' => false,
3397 3770 )
3398 3771 );
3399 3772
3400 3773 $args['option'] = $option;
@@ -3532,15 +3905,15 @@
3532 3905 return $values;
3533 3906 }
3534 3907
3535 3908 /**
3536 - * Some back end fields allow privleged users to add scripts.
3909 + * Some back end fields allow privileged users to add scripts.
3537 3910 * A site that uses the DISALLOW_UNFILTERED_HTML always remove scripts on echo.
3538 3911 *
3539 3912 * @since 5.0.13
3540 3913 *
3541 3914 * @param string $value
3542 - * @param array|string $allowed 'all' for everything included as defaults
3915 + * @param array|string $allowed 'all' for everything included as defaults.
3543 3916 * @return string
3544 3917 */
3545 3918 public static function maybe_kses( $value, $allowed = 'all' ) {
3546 3919 if ( self::should_never_allow_unfiltered_html() ) {
@@ -3549,8 +3922,64 @@
3549 3922 return $value;
3550 3923 }
3551 3924
3552 3925 /**
3926 + * Check if an option attribute used in an [input] shortcode is safe.
3927 + *
3928 + * @since 6.11.2
3929 + *
3930 + * @param string $key
3931 + * @param string $context Either 'display' or 'update'. On update, we want to allow a few keys that are never displayed.
3932 + * @return bool
3933 + */
3934 + public static function input_key_is_safe( $key, $context = 'display' ) {
3935 + if ( 'update' === $context && in_array( $key, array( 'opt', 'label' ), true ) ) {
3936 + $safe = true;
3937 + } elseif ( 0 === strpos( $key, 'data-' ) ) {
3938 + // Allow all data attributes.
3939 + $safe = true;
3940 + } elseif ( 0 === strpos( $key, 'aria-' ) ) {
3941 + // Allow all aria attributes.
3942 + $safe = true;
3943 + } else {
3944 + $safe_keys = array(
3945 + 'class',
3946 + 'required',
3947 + 'title',
3948 + 'placeholder',
3949 + 'value',
3950 + 'readonly',
3951 + 'disabled',
3952 + 'size',
3953 + 'maxlength',
3954 + 'min',
3955 + 'max',
3956 + 'pattern',
3957 + 'step',
3958 + 'autofocus',
3959 + 'width',
3960 + 'height',
3961 + 'autocomplete',
3962 + 'tabindex',
3963 + 'role',
3964 + 'style',
3965 + );
3966 + $safe = in_array( $key, $safe_keys, true );
3967 + }//end if
3968 +
3969 + /**
3970 + * Filter the $safe value so additional keys can be allowed or disallowed.
3971 + *
3972 + * @since 6.11.2
3973 + *
3974 + * @param bool $safe True if the key is considered safe.
3975 + * @param string $key
3976 + * @param string $context Either 'display' or 'update'.
3977 + */
3978 + return (bool) apply_filters( 'frm_input_key_is_safe', $safe, $key, $context );
3979 + }
3980 +
3981 + /**
3553 3982 * @since 5.0.16
3554 3983 *
3555 3984 * @return bool
3556 3985 */
@@ -3575,20 +4004,9 @@
3575 4004
3576 4005 /**
3577 4006 * @since 5.0.17
3578 4007 *
3579 - * @param string $plugin
3580 - * @return string|false
3581 - */
3582 - private static function get_plan_required( $plugin ) {
3583 - $link = FrmAddonsController::install_link( $plugin );
3584 - return FrmFormsHelper::get_plan_required( $link );
3585 - }
3586 -
3587 - /**
3588 - * @since 5.0.17
3589 - *
3590 - * @param string
4008 + * @param string $feature
3591 4009 * @return bool
3592 4010 */
3593 4011 public static function show_new_feature( $feature ) {
3594 4012 $link = FrmAddonsController::install_link( $feature );
@@ -3661,9 +4079,9 @@
3661 4079 public static function show_pill_text( $text = null ) {
3662 4080 if ( null === $text ) {
3663 4081 $text = __( 'NEW', 'formidable' );
3664 4082 }
3665 - echo '<span class="frm-new-pill">' . esc_html( $text ) . '</span>';
4083 + echo '<span class="frm-meta-tag frm-new-pill">' . esc_html( $text ) . '</span>';
3666 4084 }
3667 4085
3668 4086 /**
3669 4087 * Count the number of decimals digits.
@@ -3670,9 +4088,9 @@
3670 4088 *
3671 4089 * @since 5.2.07
3672 4090 *
3673 4091 * @param mixed $num Number.
3674 - * @return int|false Returns `false` if the passed parameter is not number.
4092 + * @return false|int Returns `false` if the passed parameter is not number.
3675 4093 */
3676 4094 public static function count_decimals( $num ) {
3677 4095 if ( ! is_numeric( $num ) ) {
3678 4096 return false;
@@ -3703,9 +4121,9 @@
3703 4121 }
3704 4122
3705 4123 add_filter(
3706 4124 'option_gmt_offset',
3707 - function( $offset ) {
4125 + function ( $offset ) {
3708 4126 if ( ! is_string( $offset ) || is_numeric( $offset ) ) {
3709 4127 // Leave a valid value alone.
3710 4128 return $offset;
3711 4129 }
@@ -3787,65 +4205,8 @@
3787 4205 return true;
3788 4206 }
3789 4207
3790 4208 /**
3791 - * @since 4.08
3792 - * @deprecated 4.09.01
3793 - */
3794 - public static function expiring_message() {
3795 - _deprecated_function( __METHOD__, '4.09.01', 'FrmProAddonsController::expiring_message' );
3796 - if ( is_callable( 'FrmProAddonsController::expiring_message' ) ) {
3797 - FrmProAddonsController::expiring_message();
3798 - }
3799 - }
3800 -
3801 - /**
3802 - * Use the WP 4.7 wp_doing_ajax function
3803 - *
3804 - * @since 2.05.07
3805 - * @deprecated 4.04.04
3806 - */
3807 - public static function wp_doing_ajax() {
3808 - _deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
3809 - return wp_doing_ajax();
3810 - }
3811 -
3812 - /**
3813 - * @deprecated 4.0
3814 - */
3815 - public static function insert_opt_html( $args ) {
3816 - _deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
3817 - FrmFormsHelper::insert_opt_html( $args );
3818 - }
3819 -
3820 - /**
3821 - * @deprecated 3.01
3822 - * @codeCoverageIgnore
3823 - */
3824 - public static function sanitize_array( &$values ) {
3825 - FrmDeprecated::sanitize_array( $values );
3826 - }
3827 -
3828 - /**
3829 - * @since 2.0
3830 - * @deprecated 5.0.13
3831 - *
3832 - * @return string The base Google APIS url for the current version of jQuery UI
3833 - */
3834 - public static function jquery_ui_base_url() {
3835 - _deprecated_function( __FUNCTION__, '5.0.13', 'FrmProAppHelper::jquery_ui_base_url' );
3836 - return is_callable( 'FrmProAppHelper::jquery_ui_base_url' ) ? FrmProAppHelper::jquery_ui_base_url() : '';
3837 - }
3838 -
3839 - /**
3840 - * @since 4.07
3841 - * @deprecated 6.0
3842 - */
3843 - public static function renewal_message() {
3844 - _deprecated_function( __METHOD__, '6.0', 'FrmProAddonsController::renewal_message' );
3845 - }
3846 -
3847 - /**
3848 4209 * Display a dismissable warning message and save its dismissal state.
3849 4210 *
3850 4211 * @since 6.3
3851 4212 *
@@ -3857,9 +4218,9 @@
3857 4218 if ( ! $message || ! $option ) {
3858 4219 return;
3859 4220 }
3860 4221
3861 - $ajax_callback = function() use ( $option ) {
4222 + $ajax_callback = function () use ( $option ) {
3862 4223 self::dismiss_warning_message( $option );
3863 4224 };
3864 4225
3865 4226 // We're handling JS codes with `doJsonPost` and it adds 'frm_' to the beginning of the action.
@@ -3867,9 +4228,9 @@
3867 4228 add_action( 'wp_ajax_frm_' . $option, $ajax_callback );
3868 4229
3869 4230 add_filter(
3870 4231 'frm_message_list',
3871 - function( $show_messages ) use ( $message, $option ) {
4232 + function ( $show_messages ) use ( $message, $option ) {
3872 4233 if ( get_option( $option, false ) ) {
3873 4234 return $show_messages;
3874 4235 }
3875 4236
@@ -3876,9 +4237,9 @@
3876 4237 $dismiss_icon = self::icon_by_class(
3877 4238 'frmfont frm_close_icon',
3878 4239 array(
3879 4240 'aria-label' => _x( 'Dismiss', 'warning message: close icon label', 'formidable' ),
3880 - 'echo' => false,
4241 + 'echo' => false,
3881 4242 )
3882 4243 );
3883 4244
3884 4245 $show_messages[] = $message;
@@ -3905,6 +4266,63 @@
3905 4266 update_option( $option, true, 'no' );
3906 4267 }
3907 4268
3908 4269 wp_send_json_success();
4270 + }
4271 +
4272 + /**
4273 + * Lite license copy.
4274 + * Used in FrmDashboardController & FrmSettingsController
4275 + *
4276 + * @since 6.8
4277 + *
4278 + * @return string
4279 + */
4280 + public static function copy_for_lite_license() {
4281 + $message = __( 'You\'re using Formidable Forms Lite - no license needed. Enjoy!', 'formidable' ) . ' 🙂';
4282 +
4283 + if ( is_callable( 'FrmProAddonsController::get_readable_license_type' ) && ! class_exists( 'FrmProDashboardController' ) ) {
4284 + // Manage PRO versions without PRO dashboard functionality.
4285 + $license_type = FrmProAddonsController::get_readable_license_type();
4286 + if ( 'lite' !== strtolower( $license_type ) ) {
4287 + $message = 'Formidable Pro ' . $license_type;
4288 + }
4289 + }
4290 +
4291 + return apply_filters( 'frm_license_type_text', $message );
4292 + }
4293 +
4294 + /**
4295 + * Removes scripts that are unnecessarily loaded across the pages!
4296 + *
4297 + * @since 6.9
4298 + * @return void
4299 + */
4300 + public static function dequeue_extra_global_scripts() {
4301 + wp_dequeue_script( 'frm-surveys-admin' );
4302 + wp_dequeue_script( 'frm-quizzes-form-action' );
4303 + }
4304 +
4305 + /**
4306 + * Shows tooltip icon.
4307 + *
4308 + * @since 6.12
4309 + *
4310 + * @param string $tooltip_text Tooltip text.
4311 + * @param array $atts Tooltip wrapper HTML attributes.
4312 + *
4313 + * @return void
4314 + */
4315 + public static function tooltip_icon( $tooltip_text, $atts = array() ) {
4316 + $atts['title'] = $tooltip_text;
4317 + if ( isset( $atts['class'] ) ) {
4318 + $atts['class'] .= ' frm_help';
4319 + } else {
4320 + $atts['class'] = 'frm_help';
4321 + }
4322 + ?>
4323 + <span <?php self::array_to_html_params( $atts, true ); ?>>
4324 + <?php self::icon_by_class( 'frmfont frm_tooltip_icon' ); ?>
4325 + </span>
4326 + <?php
3909 4327 }
3910 4328 }