PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.16.3
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.16.3
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 +749 -352 6.5 → 6.16.3 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 = 102;
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.5';
36 + public static $plug_version = '6.16.3';
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,32 +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 /**
156 198 * Determine if the current branding is set to 'formidable'.
199 + * Checks the menu icon, and verifies if it matches the formidable branding.
157 200 *
158 - * Checks the menu title, retrieved through get_menu_name,
159 - * and verifies if it matches the 'formidable' branding.
160 - *
161 201 * @since 6.4.2
162 202 *
163 - * @return bool True if the menu title is 'formidable', false otherwise.
203 + * @return bool True if the menu icon is the logo, false otherwise.
164 204 */
165 205 public static function is_formidable_branding() {
166 - $menu_title = self::get_menu_name();
206 + if ( ! self::pro_is_installed() ) {
207 + return true;
208 + }
167 209
168 - return 'formidable' === strtolower( trim( $menu_title ) );
210 + $menu_icon = self::get_menu_icon_class();
211 + return strpos( $menu_icon, 'frm_logo_icon' ) !== false;
169 212 }
170 213
171 214 /**
172 215 * @since 3.05
216 + *
217 + * @param array $atts
218 + * @return string
173 219 */
174 220 public static function svg_logo( $atts = array() ) {
175 221 $defaults = array(
176 222 'height' => 18,
@@ -187,8 +233,11 @@
187 233 }
188 234
189 235 /**
190 236 * @since 4.0
237 + *
238 + * @param array $atts
239 + * @return void
191 240 */
192 241 public static function show_logo( $atts = array() ) {
193 242 echo self::kses( self::svg_logo( $atts ), 'all' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
194 243 }
@@ -194,8 +243,10 @@
194 243 }
195 244
196 245 /**
197 246 * @since 4.03.02
247 + *
248 + * @return void
198 249 */
199 250 public static function show_header_logo() {
200 251 $icon = self::svg_logo(
201 252 array(
@@ -217,21 +268,38 @@
217 268 }
218 269
219 270 /**
220 271 * @since 2.02.04
272 + *
273 + * @return bool
221 274 */
222 275 public static function ips_saved() {
223 276 $frm_settings = self::get_settings();
224 -
225 277 return ! $frm_settings->no_ips;
226 278 }
227 279
280 + /**
281 + * @return bool
282 + */
228 283 public static function pro_is_installed() {
229 - return apply_filters( 'frm_pro_installed', false );
284 + return (bool) apply_filters( 'frm_pro_installed', false );
230 285 }
231 286
232 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 + /**
233 299 * @since 4.06.02
300 + *
301 + * @return bool
234 302 */
235 303 public static function pro_is_connected() {
236 304 global $frm_vars;
237 305 return self::pro_is_installed() && $frm_vars['pro_is_authorized'];
@@ -238,14 +306,26 @@
238 306 }
239 307
240 308 /**
241 309 * @since 4.06
310 + * @since 6.16.2 Added $check_for_settings parameter
311 + *
312 + * @param bool $check_for_settings
313 + *
314 + * @return bool
242 315 */
243 - public static function is_form_builder_page() {
244 - $action = self::simple_get( 'frm_action', 'sanitize_title' );
245 - return self::is_admin_page( 'formidable' ) && ( $action === 'edit' || $action === 'settings' || $action === 'duplicate' );
316 + public static function is_form_builder_page( $check_for_settings = true ) {
317 + $action = self::simple_get( 'frm_action', 'sanitize_title' );
318 + $check_actions = array( 'edit', 'duplicate' );
319 + if ( $check_for_settings ) {
320 + $check_actions[] = 'settings';
321 + }
322 + return self::is_admin_page( 'formidable' ) && in_array( $action, $check_actions, true );
246 323 }
247 324
325 + /**
326 + * @return bool
327 + */
248 328 public static function is_formidable_admin() {
249 329 $page = self::simple_get( 'page', 'sanitize_title' );
250 330 $is_formidable = strpos( $page, 'formidable' ) !== false;
251 331 if ( empty( $page ) ) {
@@ -259,11 +339,11 @@
259 339 * Check for certain page in Formidable settings
260 340 *
261 341 * @since 2.0
262 342 *
263 - * @param string $page The name of the page to check
343 + * @param string $page The name of the page to check.
264 344 *
265 - * @return boolean
345 + * @return bool
266 346 */
267 347 public static function is_admin_page( $page = 'formidable' ) {
268 348 global $pagenow;
269 349 $get_page = self::simple_get( 'page', 'sanitize_title' );
@@ -282,8 +362,10 @@
282 362 * If the current page is for editing or creating a view.
283 363 * Returns false for the views listing page.
284 364 *
285 365 * @since 4.0
366 + *
367 + * @return bool
286 368 */
287 369 public static function is_view_builder_page() {
288 370 global $pagenow;
289 371
@@ -293,10 +375,10 @@
293 375
294 376 $post_type = self::simple_get( 'post_type', 'sanitize_title' );
295 377
296 378 if ( empty( $post_type ) ) {
297 - $post_id = self::simple_get( 'post', 'absint' );
298 - $post = get_post( $post_id );
379 + $post_id = self::simple_get( 'post', 'absint' );
380 + $post = get_post( $post_id );
299 381 $post_type = $post ? $post->post_type : '';
300 382 }
301 383
302 384 return $post_type === 'frm_display';
@@ -306,17 +388,15 @@
306 388 * Check for the form preview page
307 389 *
308 390 * @since 2.0
309 391 *
310 - * @param None
311 - *
312 - * @return boolean
392 + * @return bool
313 393 */
314 394 public static function is_preview_page() {
315 395 global $pagenow;
316 396 $action = self::simple_get( 'action', 'sanitize_title' );
317 397
318 - return $pagenow && $pagenow == 'admin-ajax.php' && $action == 'frm_forms_preview';
398 + return $pagenow && $pagenow === 'admin-ajax.php' && $action === 'frm_forms_preview';
319 399 }
320 400
321 401 /**
322 402 * Check for ajax except the form preview page
@@ -322,16 +402,17 @@
322 402 * Check for ajax except the form preview page
323 403 *
324 404 * @since 2.0
325 405 *
326 - * @param None
327 - *
328 - * @return boolean
406 + * @return bool
329 407 */
330 408 public static function doing_ajax() {
331 409 return wp_doing_ajax() && ! self::is_preview_page();
332 410 }
333 411
412 + /**
413 + * @return string
414 + */
334 415 public static function js_suffix() {
335 416 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
336 417 }
337 418
@@ -336,13 +417,13 @@
336 417 }
337 418
338 419 /**
339 420 * @since 2.0.8
421 + * @return bool
340 422 */
341 423 public static function prevent_caching() {
342 424 global $frm_vars;
343 -
344 - return isset( $frm_vars['prevent_caching'] ) && $frm_vars['prevent_caching'];
425 + return ! empty( $frm_vars['prevent_caching'] );
345 426 }
346 427
347 428 /**
348 429 * Check if on an admin page
@@ -348,9 +429,9 @@
348 429 * Check if on an admin page
349 430 *
350 431 * @since 2.0
351 432 *
352 - * @return boolean
433 + * @return bool
353 434 */
354 435 public static function is_admin() {
355 436 $is_admin = is_admin() && ! wp_doing_ajax();
356 437
@@ -365,17 +446,22 @@
365 446 * Check if value contains blank value or empty array
366 447 *
367 448 * @since 2.0
368 449 *
369 - * @param mixed $value - value to check
370 - * @param string
450 + * @param mixed $value Value to check.
451 + * @param string $empty
371 452 *
372 - * @return boolean
453 + * @return bool
373 454 */
374 455 public static function is_empty_value( $value, $empty = '' ) {
375 456 return ( is_array( $value ) && empty( $value ) ) || $value === $empty;
376 457 }
377 458
459 + /**
460 + * @param mixed $value
461 + * @param string $empty
462 + * @return bool
463 + */
378 464 public static function is_not_empty_value( $value, $empty = '' ) {
379 465 return ! self::is_empty_value( $value, $empty );
380 466 }
381 467
@@ -394,14 +480,13 @@
394 480
395 481 /**
396 482 * Get the server OS
397 483 *
398 - * @since 6.4.x
484 + * @since 6.4.2
399 485 *
400 486 * @return string
401 487 */
402 488 public static function get_server_os() {
403 -
404 489 if ( function_exists( 'php_uname' ) ) {
405 490 return php_uname( 's' );
406 491 }
407 492
@@ -429,9 +514,10 @@
429 514 }
430 515
431 516 $key = self::get_server_value( $key );
432 517 foreach ( explode( ',', $key ) as $ip ) {
433 - $ip = trim( $ip ); // Just to be safe.
518 + // Just to be safe.
519 + $ip = trim( $ip );
434 520
435 521 if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
436 522 return sanitize_text_field( $ip );
437 523 }
@@ -522,15 +608,24 @@
522 608
523 609 return $value;
524 610 }
525 611
612 + /**
613 + * Get a value from $_POST data.
614 + *
615 + * @param string $param The key we are trying to access data from in $_POST.
616 + * @param mixed $default The default if nothing is being sent.
617 + * @param callable|string $sanitize Make sure to pass a sanitize method here. This function will NOT sanitize by default.
618 + * @param bool $serialized
619 + * @return mixed
620 + */
526 621 public static function get_post_param( $param, $default = '', $sanitize = '', $serialized = false ) {
527 622 return self::get_simple_request(
528 623 array(
529 - 'type' => 'post',
530 - 'param' => $param,
531 - 'default' => $default,
532 - 'sanitize' => $sanitize,
624 + 'type' => 'post',
625 + 'param' => $param,
626 + 'default' => $default,
627 + 'sanitize' => $sanitize,
533 628 'serialized' => $serialized,
534 629 )
535 630 );
536 631 }
@@ -541,9 +636,9 @@
541 636 * @param string $param
542 637 * @param string $sanitize
543 638 * @param string $default
544 639 *
545 - * @return string|array
640 + * @return array|string
546 641 */
547 642 public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
548 643 return self::get_simple_request(
549 644 array(
@@ -561,16 +656,16 @@
561 656 * @since 2.0.6
562 657 *
563 658 * @param array $args
564 659 *
565 - * @return string|array
660 + * @return array|string
566 661 */
567 662 public static function get_simple_request( $args ) {
568 663 $defaults = array(
569 - 'param' => '',
570 - 'default' => '',
571 - 'type' => 'get',
572 - 'sanitize' => 'sanitize_text_field',
664 + 'param' => '',
665 + 'default' => '',
666 + 'type' => 'get',
667 + 'sanitize' => 'sanitize_text_field',
573 668 'serialized' => false,
574 669 );
575 670 $args = wp_parse_args( $args, $defaults );
576 671
@@ -587,13 +682,12 @@
587 682 if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
588 683 self::unserialize_or_decode( $value );
589 684 }
590 685 }
591 - } else {
592 - if ( isset( $_REQUEST[ $args['param'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
686 + } elseif ( isset( $_REQUEST[ $args['param'] ] ) ) {
687 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
593 688 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
594 689 $value = wp_unslash( $_REQUEST[ $args['param'] ] );
595 - }
596 690 }
597 691
598 692 self::sanitize_value( $args['sanitize'], $value );
599 693
@@ -617,19 +711,35 @@
617 711
618 712 return $value;
619 713 }
620 714
715 + /**
716 + * Sanitize a value in-place.
717 + * If $value is an array, the sanitize function will get called for each item.
718 + *
719 + * @param callable $sanitize
720 + * @param mixed $value
721 + * @return void
722 + */
621 723 public static function sanitize_value( $sanitize, &$value ) {
622 - if ( ! empty( $sanitize ) ) {
623 - if ( is_array( $value ) ) {
624 - $temp_values = $value;
625 - foreach ( $temp_values as $k => $v ) {
626 - self::sanitize_value( $sanitize, $value[ $k ] );
627 - }
628 - } else {
629 - $value = call_user_func( $sanitize, $value );
724 + if ( ! $sanitize ) {
725 + return;
726 + }
727 +
728 + if ( is_object( $value ) ) {
729 + $value = '';
730 + return;
731 + }
732 +
733 + if ( is_array( $value ) ) {
734 + $temp_values = $value;
735 + foreach ( $temp_values as $k => $v ) {
736 + self::sanitize_value( $sanitize, $value[ $k ] );
630 737 }
738 + return;
631 739 }
740 +
741 + $value = call_user_func( $sanitize, $value );
632 742 }
633 743
634 744 public static function sanitize_request( $sanitize_method, &$values ) {
635 745 $temp_values = $values;
@@ -641,15 +751,52 @@
641 751 }
642 752
643 753 /**
644 754 * @since 4.0.04
755 + *
756 + * @param mixed $value
757 + * @return void
645 758 */
646 759 public static function sanitize_with_html( &$value ) {
647 - self::sanitize_value( 'wp_kses_post', $value );
760 + if ( current_user_can( 'frm_edit_entries' ) || current_user_can( 'administrator' ) ) {
761 + // Only strip unsafe HTML like scripts for a privileged user submitting a form.
762 + self::sanitize_value( 'wp_kses_post', $value );
763 + } else {
764 + self::sanitize_value( self::class . '::strip_most_html', $value );
765 + }
648 766 self::decode_specialchars( $value );
649 767 }
650 768
651 769 /**
770 + * Allow only a small set of very basic HTML for unprivileged users.
771 + *
772 + * @since 6.7.1
773 + *
774 + * @param string $value
775 + */
776 + public static function strip_most_html( $value ) {
777 + $allowed_html = array(
778 + 'b' => array(),
779 + 'br' => array(),
780 + 'strong' => array(),
781 + 'p' => array(),
782 + 'i' => array(),
783 + 'ul' => array(),
784 + 'ol' => array(),
785 + 'li' => array(),
786 + );
787 +
788 + /**
789 + * @since 6.7.1
790 + *
791 + * @param array $allowed_html
792 + */
793 + $allowed_html = apply_filters( 'frm_allowed_form_input_html', $allowed_html );
794 +
795 + return wp_kses( $value, $allowed_html );
796 + }
797 +
798 + /**
652 799 * Do wp_specialchars_decode to get back '&' that wp_kses_post might have turned to '&'
653 800 * this MUST be done, else we'll be back to the '& entity' problem.
654 801 *
655 802 * @since 4.0.04
@@ -683,10 +830,12 @@
683 830 $translation = array(
684 831 '"' => '"',
685 832 '"' => '"',
686 833 '"' => '"',
687 - '&lt; ' => '< ', // The space preserves the HTML.
688 - '&#060; ' => '< ', // The space preserves the HTML.
834 + // The space preserves the HTML.
835 + '&lt; ' => '< ',
836 + // The space preserves the HTML.
837 + '&#060; ' => '< ',
689 838 '&gt;' => '>',
690 839 '&#062;' => '>',
691 840 '&amp;' => '&',
692 841 '&#038;' => '&',
@@ -713,10 +862,10 @@
713 862 * Sanitize the value, and allow some HTML
714 863 *
715 864 * @since 2.0
716 865 *
717 - * @param string $value
718 - * @param array|string $allowed 'all' for everything included as defaults
866 + * @param string $value
867 + * @param array|string $allowed 'all' for everything included as defaults.
719 868 *
720 869 * @return string
721 870 */
722 871 public static function kses( $value, $allowed = array() ) {
@@ -817,9 +966,9 @@
817 966 'id' => true,
818 967 );
819 968
820 969 return array(
821 - 'a' => array(
970 + 'a' => array(
822 971 'class' => true,
823 972 'href' => true,
824 973 'id' => true,
825 974 'rel' => true,
@@ -888,16 +1037,16 @@
888 1037 'cite' => true,
889 1038 'title' => true,
890 1039 ),
891 1040 'rect' => array(
892 - 'class' => true,
893 - 'fill' => true,
894 - 'height' => true,
895 - 'width' => true,
896 - 'x' => true,
897 - 'y' => true,
898 - 'rx' => true,
899 - 'stroke' => true,
1041 + 'class' => true,
1042 + 'fill' => true,
1043 + 'height' => true,
1044 + 'width' => true,
1045 + 'x' => true,
1046 + 'y' => true,
1047 + 'rx' => true,
1048 + 'stroke' => true,
900 1049 'stroke-opacity' => true,
901 1050 'stroke-width' => true,
902 1051 ),
903 1052 'section' => $allow_class,
@@ -932,9 +1081,9 @@
932 1081 'xlink:href' => true,
933 1082 ),
934 1083 'ul' => $allow_class,
935 1084 'label' => array(
936 - 'for' => true,
1085 + 'for' => true,
937 1086 'class' => true,
938 1087 'id' => true,
939 1088 ),
940 1089 'button' => array(
@@ -952,9 +1101,9 @@
952 1101 *
953 1102 * @since 2.0
954 1103 */
955 1104 public static function remove_get_action() {
956 - if ( ! isset( $_GET ) ) {
1105 + if ( empty( $_GET ) ) {
957 1106 return;
958 1107 }
959 1108
960 1109 $action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
@@ -971,9 +1120,9 @@
971 1120 /**
972 1121 * Check the WP query for a parameter
973 1122 *
974 1123 * @since 2.0
975 - * @return string|array
1124 + * @return array|string
976 1125 */
977 1126 public static function get_query_var( $value, $param ) {
978 1127 if ( $value != '' ) {
979 1128 return $value;
@@ -990,10 +1139,12 @@
990 1139 /**
991 1140 * Try to show the SVG if possible. Otherwise, use the font icon.
992 1141 *
993 1142 * @since 4.0.02
1143 + *
994 1144 * @param string $class
995 1145 * @param array $atts
1146 + * @return string|null
996 1147 */
997 1148 public static function icon_by_class( $class, $atts = array() ) {
998 1149 $echo = ! isset( $atts['echo'] ) || $atts['echo'];
999 1150 if ( isset( $atts['echo'] ) ) {
@@ -1003,14 +1154,16 @@
1003 1154 $html_atts = self::array_to_html_params( $atts );
1004 1155
1005 1156 $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
1006 1157
1007 - // Replace icons that have been removed.
1158 + // Replace icons that have been removed or renamed.
1008 1159 $deprecated = array(
1009 - 'frm_clone_solid_icon' => 'frm_clone_icon',
1160 + 'frm_clone_solid_icon' => 'frm_clone_icon',
1161 + 'frm_keyalt_icon' => 'frm_key_icon',
1162 + 'frm_keyalt_solid_icon' => 'frm_key_solid_icon',
1010 1163 );
1011 1164 if ( isset( $deprecated[ $icon ] ) ) {
1012 - $icon = $deprecated[ $icon ];
1165 + $icon = $deprecated[ $icon ];
1013 1166 $class = str_replace( $icon, $deprecated[ $icon ], $class );
1014 1167 }
1015 1168
1016 1169 if ( $icon === $class ) {
@@ -1020,11 +1173,9 @@
1020 1173 if ( strpos( $icon, ' ' ) ) {
1021 1174 $icon = explode( ' ', $icon );
1022 1175 $icon = reset( $icon );
1023 1176 }
1024 - $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '>
1025 - <use xlink:href="#' . esc_attr( $icon ) . '" />
1026 - </svg>';
1177 + $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use xlink:href="#' . esc_attr( $icon ) . '" /></svg>';
1027 1178 }
1028 1179
1029 1180 if ( $echo ) {
1030 1181 echo self::kses_icon( $icon ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
@@ -1110,11 +1261,18 @@
1110 1261 /**
1111 1262 * Include svg images.
1112 1263 *
1113 1264 * @since 4.0.02
1265 + * @return void
1114 1266 */
1115 1267 public static function include_svg() {
1116 - include_once self::plugin_path() . '/images/icons.svg';
1268 + if ( self::$included_svg ) {
1269 + return;
1270 + }
1271 +
1272 + // Use readfile instead of include_once because of a default security rule in Snuffleupagus.
1273 + readfile( self::plugin_path() . '/images/icons.svg' );
1274 + self::$included_svg = true;
1117 1275 }
1118 1276
1119 1277 /**
1120 1278 * Convert an associative array to HTML values.
@@ -1126,9 +1284,9 @@
1126 1284 * @param bool $echo
1127 1285 * @return string|void
1128 1286 */
1129 1287 public static function array_to_html_params( $atts, $echo = false ) {
1130 - $callback = function() use ( $atts ) {
1288 + $callback = function () use ( $atts ) {
1131 1289 if ( $atts ) {
1132 1290 foreach ( $atts as $key => $value ) {
1133 1291 echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1134 1292 }
@@ -1143,9 +1301,9 @@
1143 1301 * @since 5.0.13
1144 1302 *
1145 1303 * @param Closure $echo_function
1146 1304 * @param bool $echo
1147 - * @return string|void
1305 + * @return string|null
1148 1306 */
1149 1307 public static function clip( $echo_function, $echo = false ) {
1150 1308 if ( ! $echo ) {
1151 1309 ob_start();
@@ -1163,12 +1321,15 @@
1163 1321 }
1164 1322
1165 1323 /**
1166 1324 * @since 3.0
1325 + *
1326 + * @param array $atts
1327 + * @return void
1167 1328 */
1168 1329 public static function get_admin_header( $atts ) {
1169 - $has_nav = ( isset( $atts['form'] ) && ! empty( $atts['form'] ) && ( ! isset( $atts['is_template'] ) || ! $atts['is_template'] ) );
1170 - if ( ! isset( $atts['close'] ) || empty( $atts['close'] ) ) {
1330 + $has_nav = ! empty( $atts['form'] ) && empty( $atts['is_template'] );
1331 + if ( empty( $atts['close'] ) ) {
1171 1332 $atts['close'] = admin_url( 'admin.php?page=formidable' );
1172 1333 }
1173 1334 if ( ! isset( $atts['import_link'] ) ) {
1174 1335 $atts['import_link'] = false;
@@ -1173,9 +1334,9 @@
1173 1334 if ( ! isset( $atts['import_link'] ) ) {
1174 1335 $atts['import_link'] = false;
1175 1336 }
1176 1337
1177 - include( self::plugin_path() . '/classes/views/shared/admin-header.php' );
1338 + include self::plugin_path() . '/classes/views/shared/admin-header.php';
1178 1339 }
1179 1340
1180 1341 /**
1181 1342 * @since 6.0
@@ -1211,10 +1372,22 @@
1211 1372 return;
1212 1373 }
1213 1374 ?>
1214 1375 <div class="frm-upgrade-bar">
1215 - <span>You're using Formidable Forms Lite. To unlock more features consider</span>
1216 - <a href="<?php echo esc_url( self::admin_upgrade_link( 'top-bar' ) ); ?>" target="_blank" rel="noopener">upgrading to Pro</a>.
1376 + <?php
1377 + $upgrade_link = self::admin_upgrade_link(
1378 + array(
1379 + 'medium' => 'settings-license',
1380 + 'content' => 'lite-banner',
1381 + )
1382 + );
1383 + printf(
1384 + /* translators: %1$s: Start link HTML, %2$s: End link HTML */
1385 + esc_html__( 'You\'re using Formidable Forms Lite. To unlock more features consider %1$supgrading to PRO%2$s.', 'formidable' ),
1386 + '<a href="' . esc_url( $upgrade_link ) . '">',
1387 + '</a>'
1388 + );
1389 + ?>
1217 1390 </div>
1218 1391 <?php
1219 1392 }
1220 1393
@@ -1231,8 +1404,10 @@
1231 1404 * Render a button for a new item (Form, Application, etc).
1232 1405 *
1233 1406 * @since 3.0
1234 1407 * @param array $atts {
1408 + * Details about the button.
1409 + *
1235 1410 * @type array $link_hook Custom link hook, calls do_action and exits early.
1236 1411 * @type string $new_link Href value, default #.
1237 1412 * @type string $class Custom class names, space separated.
1238 1413 * @type string $button_text Button text. Default "Add New".
@@ -1244,9 +1419,9 @@
1244 1419 do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
1245 1420 return;
1246 1421 }
1247 1422
1248 - if ( empty( $atts['new_link'] ) && empty( $atts['trigger_new_form_modal'] ) && empty( $atts['class'] ) ) {
1423 + if ( empty( $atts['new_link'] ) && empty( $atts['create_form'] ) && empty( $atts['class'] ) ) {
1249 1424 // Do not render a button if none of these attributes are set.
1250 1425 return;
1251 1426 }
1252 1427
@@ -1252,12 +1427,8 @@
1252 1427
1253 1428 $href = ! empty( $atts['new_link'] ) ? esc_url( $atts['new_link'] ) : '#';
1254 1429 $class = 'button button-primary frm-button-primary';
1255 1430
1256 - if ( ! empty( $atts['trigger_new_form_modal'] ) ) {
1257 - $class .= ' frm-trigger-new-form-modal';
1258 - }
1259 -
1260 1431 if ( ! empty( $atts['class'] ) ) {
1261 1432 $class .= ' ' . $atts['class'];
1262 1433 }
1263 1434
@@ -1274,10 +1445,11 @@
1274 1445 'placeholder' => '',
1275 1446 'tosearch' => '',
1276 1447 'text' => __( 'Search', 'formidable' ),
1277 1448 'input_id' => '',
1449 + 'value' => false,
1278 1450 );
1279 - $atts = array_merge( $defaults, $atts );
1451 + $atts = array_merge( $defaults, $atts );
1280 1452
1281 1453 if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
1282 1454 $atts['tosearch'] = 'frm-card';
1283 1455 }
@@ -1288,8 +1460,27 @@
1288 1460 }
1289 1461
1290 1462 $input_id = $atts['input_id'] . '-search-input';
1291 1463
1464 + $input_atts = array(
1465 + 'type' => 'search',
1466 + 'id' => $input_id,
1467 + 'name' => 's',
1468 + 'placeholder' => $atts['placeholder'],
1469 + 'class' => $class,
1470 + 'data-tosearch' => $atts['tosearch'],
1471 + );
1472 +
1473 + if ( is_string( $atts['value'] ) ) {
1474 + $input_atts['value'] = $atts['value'];
1475 + } elseif ( isset( $_REQUEST['s'] ) ) {
1476 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1477 + $input_atts['value'] = wp_unslash( $_REQUEST['s'] );
1478 + }
1479 +
1480 + if ( ! empty( $atts['tosearch'] ) ) {
1481 + $input_atts['autocomplete'] = 'off';
1482 + }
1292 1483 ?>
1293 1484 <p class="frm-search">
1294 1485 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1295 1486 <?php echo esc_html( $atts['text'] ); ?>:
@@ -1294,15 +1485,9 @@
1294 1485 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1295 1486 <?php echo esc_html( $atts['text'] ); ?>:
1296 1487 </label>
1297 1488 <span class="frmfont frm_search_icon"></span>
1298 - <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
1299 - value="<?php _admin_search_query(); ?>" placeholder="<?php echo esc_attr( $atts['placeholder'] ); ?>"
1300 - class="<?php echo esc_attr( $class ); ?>" data-tosearch="<?php echo esc_attr( $atts['tosearch'] ); ?>"
1301 - <?php if ( ! empty( $atts['tosearch'] ) ) { ?>
1302 - autocomplete="off"
1303 - <?php } ?>
1304 - />
1489 + <input <?php self::array_to_html_params( $input_atts, true ); ?> />
1305 1490 <?php
1306 1491 if ( empty( $atts['tosearch'] ) ) {
1307 1492 submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
1308 1493 }
@@ -1312,8 +1497,9 @@
1312 1497 }
1313 1498
1314 1499 /**
1315 1500 * @param string $type
1501 + * @return void
1316 1502 */
1317 1503 public static function trigger_hook_load( $type, $object = null ) {
1318 1504 // Only load the form hooks once.
1319 1505 $hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
@@ -1357,9 +1543,9 @@
1357 1543 'new_file_path' => self::plugin_path() . '/js',
1358 1544 )
1359 1545 );
1360 1546 $new_file = new FrmCreateFile( $file_atts );
1361 - $files = array(
1547 + $files = array(
1362 1548 FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.min.js',
1363 1549 );
1364 1550
1365 1551 /**
@@ -1376,14 +1562,14 @@
1376 1562 * True when value is 1, true, 'true', 'yes'
1377 1563 *
1378 1564 * @since 1.07.10
1379 1565 *
1380 - * @param string $value The value to compare
1566 + * @param string $value The value to compare.
1381 1567 *
1382 - * @return boolean True or False
1568 + * @return bool
1383 1569 */
1384 1570 public static function is_true( $value ) {
1385 - return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1571 + return true === $value || 1 == $value || 'true' === $value || 'yes' === $value;
1386 1572 }
1387 1573
1388 1574 /**
1389 1575 * Gets all post from a specific post type.
@@ -1449,9 +1635,9 @@
1449 1635
1450 1636 wp_enqueue_script( 'jquery-ui-autocomplete' );
1451 1637
1452 1638 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1453 - $title = '';
1639 + $title = '';
1454 1640
1455 1641 if ( $selected ) {
1456 1642 $title = get_the_title( $selected );
1457 1643 }
@@ -1467,11 +1653,11 @@
1467 1653 <?php
1468 1654 }
1469 1655
1470 1656 /**
1471 - * @param array $args
1472 - * @param string $page_id Deprecated.
1473 - * @param boolean $truncate Deprecated.
1657 + * @param array $args
1658 + * @param string $page_id Deprecated.
1659 + * @param bool $truncate Deprecated.
1474 1660 */
1475 1661 public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1476 1662 self::prep_page_dropdown_params( $page_id, $truncate, $args );
1477 1663
@@ -1515,13 +1701,13 @@
1515 1701 * @since 4.10.01 Added `post_type` and `autocomplete_placeholder` to the arguments array.
1516 1702 */
1517 1703 private static function preformat_selection_args( $args ) {
1518 1704 $defaults = array(
1519 - 'truncate' => false,
1520 - 'placeholder' => ' ',
1521 - 'field_name' => '',
1522 - 'page_id' => '',
1523 - 'post_type' => 'page',
1705 + 'truncate' => false,
1706 + 'placeholder' => ' ',
1707 + 'field_name' => '',
1708 + 'page_id' => '',
1709 + 'post_type' => 'page',
1524 1710 'autocomplete_placeholder' => __( 'Select a Page', 'formidable' ),
1525 1711 );
1526 1712
1527 1713 return array_merge( $defaults, $args );
@@ -1592,25 +1778,16 @@
1592 1778 return self::is_admin_page( 'formidable-views-editor' );
1593 1779 }
1594 1780
1595 1781 /**
1596 - * @since 4.0
1597 - * @deprecated 5.5.3
1782 + * @param string $field_name
1783 + * @param array|string $capability
1784 + * @param string $multiple 'single' and 'multiple'.
1598 1785 */
1599 - public static function maybe_full_screen_link( $link ) {
1600 - _deprecated_function( __METHOD__, '5.5.3' );
1601 - return $link;
1602 - }
1603 -
1604 - /**
1605 - * @param string $field_name
1606 - * @param string|array $capability
1607 - * @param string $multiple 'single' and 'multiple'
1608 - */
1609 1786 public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1610 1787 ?>
1611 1788 <select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1612 - <?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1789 + <?php echo 'multiple' === $multiple ? 'multiple="multiple"' : ''; ?>
1613 1790 class="frm_multiselect">
1614 1791 <?php self::roles_options( $capability ); ?>
1615 1792 </select>
1616 1793 <?php
@@ -1618,9 +1795,9 @@
1618 1795
1619 1796 /**
1620 1797 * @since 4.07
1621 1798 * @param array|string $selected
1622 - * @param string $current
1799 + * @param string $current
1623 1800 */
1624 1801 private static function selected( $selected, $current ) {
1625 1802 if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1626 1803 FrmProAppHelper::selected( $selected, $current );
@@ -1629,9 +1806,9 @@
1629 1806 }
1630 1807 }
1631 1808
1632 1809 /**
1633 - * @param string|array $capability
1810 + * @param array|string $capability
1634 1811 */
1635 1812 public static function roles_options( $capability ) {
1636 1813 global $frm_vars;
1637 1814 if ( isset( $frm_vars['editable_roles'] ) ) {
@@ -1643,9 +1820,9 @@
1643 1820
1644 1821 foreach ( $editable_roles as $role => $details ) {
1645 1822 $name = translate_user_role( $details['name'] );
1646 1823 ?>
1647 - <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_attr( $name ); ?> </option>
1824 + <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_html( $name ); ?> </option>
1648 1825 <?php
1649 1826 unset( $role, $details );
1650 1827 }
1651 1828 }
@@ -1666,9 +1843,8 @@
1666 1843 $pro_cap = array(
1667 1844 'frm_create_entries' => __( 'Add Entries from Admin Area', 'formidable' ),
1668 1845 'frm_edit_entries' => __( 'Edit Entries from Admin Area', 'formidable' ),
1669 1846 'frm_view_reports' => __( 'View Reports', 'formidable' ),
1670 - 'frm_edit_displays' => __( 'Add/Edit Views', 'formidable' ),
1671 1847 );
1672 1848 /**
1673 1849 * @since 5.3.1
1674 1850 *
@@ -1675,8 +1851,14 @@
1675 1851 * @param array<string,string> $pro_cap
1676 1852 */
1677 1853 $pro_cap = apply_filters( 'frm_pro_capabilities', $pro_cap );
1678 1854
1855 + if ( ! array_key_exists( 'frm_edit_displays', $pro_cap ) && is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed() ) {
1856 + // For backward compatibility, add the Add/Edit Views permission if Pro is not up to date.
1857 + // This was added in 6.5.4. Remove this in the future.
1858 + $pro_cap['frm_edit_displays'] = __( 'Add/Edit Views', 'formidable' );
1859 + }
1860 +
1679 1861 if ( 'pro_only' === $type ) {
1680 1862 return $pro_cap;
1681 1863 }
1682 1864
@@ -1691,9 +1873,9 @@
1691 1873 * @return array<string,string>
1692 1874 */
1693 1875 private static function get_lite_capabilities() {
1694 1876 return array(
1695 - 'frm_view_forms' => __( 'View Forms', 'formidable' ),
1877 + 'frm_view_forms' => __( 'View Forms List', 'formidable' ),
1696 1878 'frm_edit_forms' => __( 'Add and Edit Forms', 'formidable' ),
1697 1879 'frm_delete_forms' => __( 'Delete Forms', 'formidable' ),
1698 1880 'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1699 1881 'frm_view_entries' => __( 'View Entries from Admin Area', 'formidable' ),
@@ -1734,9 +1916,9 @@
1734 1916 return current_user_can( $role );
1735 1917 }
1736 1918
1737 1919 /**
1738 - * @param string|array $needed_role
1920 + * @param array|string $needed_role
1739 1921 * @return bool
1740 1922 */
1741 1923 public static function user_has_permission( $needed_role ) {
1742 1924 if ( is_array( $needed_role ) ) {
@@ -1792,8 +1974,11 @@
1792 1974 /**
1793 1975 * Make sure admins have permission to see the menu items
1794 1976 *
1795 1977 * @since 2.0.6
1978 + *
1979 + * @param string $cap
1980 + * @return void
1796 1981 */
1797 1982 public static function force_capability( $cap = 'frm_change_settings' ) {
1798 1983 if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1799 1984 $role = get_role( 'administrator' );
@@ -1804,9 +1989,9 @@
1804 1989 }
1805 1990 }
1806 1991
1807 1992 /**
1808 - * Check if the user has permision for action.
1993 + * Check if the user has permission for action.
1809 1994 * Return permission message and stop the action if no permission
1810 1995 *
1811 1996 * @since 2.0
1812 1997 *
@@ -1842,9 +2027,9 @@
1842 2027 if ( empty( $nonce_name ) ) {
1843 2028 return $error;
1844 2029 }
1845 2030
1846 - $nonce_value = ( $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
2031 + $nonce_value = $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
1847 2032 if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1848 2033 $frm_settings = self::get_settings();
1849 2034 $error = $frm_settings->admin_permission;
1850 2035 }
@@ -1858,12 +2043,13 @@
1858 2043 }
1859 2044 }
1860 2045
1861 2046 public static function check_selected( $values, $current ) {
1862 - $values = self::recursive_function_map( $values, 'trim' );
1863 - $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1864 - $current = htmlspecialchars_decode( trim( $current ) );
2047 + $values = self::recursive_function_map( $values, 'trim' );
2048 + $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1865 2049
2050 + $current = is_null( $current ) ? '' : htmlspecialchars_decode( trim( $current ) );
2051 +
1866 2052 return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1867 2053 }
1868 2054
1869 2055 public static function recursive_function_map( $value, $function ) {
@@ -1883,8 +2069,9 @@
1883 2069 }
1884 2070 }
1885 2071 }
1886 2072 } else {
2073 + $value = self::maybe_update_value_if_null( $value, $function );
1887 2074 $value = call_user_func( $function, $value );
1888 2075 }
1889 2076
1890 2077 return $value;
@@ -1889,8 +2076,24 @@
1889 2076
1890 2077 return $value;
1891 2078 }
1892 2079
2080 + /**
2081 + * Updates value to empty string if it is null and being passed to a string function.
2082 + *
2083 + * @since 6.8.4
2084 + * @param mixed $value
2085 + * @param string $function
2086 + * @return mixed
2087 + */
2088 + private static function maybe_update_value_if_null( $value, $function ) {
2089 + if ( null === $value && in_array( $function, array( 'trim', 'strlen' ), true ) ) {
2090 + $value = '';
2091 + }
2092 +
2093 + return $value;
2094 + }
2095 +
1893 2096 public static function is_assoc( $array ) {
1894 2097 return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1895 2098 }
1896 2099
@@ -1901,14 +2104,12 @@
1901 2104 $return = array();
1902 2105 foreach ( $array as $key => $value ) {
1903 2106 if ( is_array( $value ) ) {
1904 2107 $return = array_merge( $return, self::array_flatten( $value, $keys ) );
2108 + } elseif ( $keys === 'keep' ) {
2109 + $return[ $key ] = $value;
1905 2110 } else {
1906 - if ( $keys === 'keep' ) {
1907 - $return[ $key ] = $value;
1908 - } else {
1909 - $return[] = $value;
1910 - }
2111 + $return[] = $value;
1911 2112 }
1912 2113 }
1913 2114
1914 2115 return $return;
@@ -1913,8 +2114,27 @@
1913 2114
1914 2115 return $return;
1915 2116 }
1916 2117
2118 + /**
2119 + * Flatten an array before imploding it to avoid Array to string conversion warnings.
2120 + *
2121 + * @since 6.16.1
2122 + *
2123 + * @param string $sep
2124 + * @param array $array
2125 + * @return string
2126 + */
2127 + public static function safe_implode( $sep, $array ) {
2128 + $array = self::array_flatten( $array );
2129 + return implode( $sep, $array );
2130 + }
2131 +
2132 + /**
2133 + * @param string $text
2134 + * @param bool $is_rich_text
2135 + * @return string
2136 + */
1917 2137 public static function esc_textarea( $text, $is_rich_text = false ) {
1918 2138 $safe_text = str_replace( '&quot;', '"', $text );
1919 2139 if ( ! $is_rich_text ) {
1920 2140 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
@@ -1920,9 +2140,13 @@
1920 2140 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1921 2141 }
1922 2142 $safe_text = str_replace( '&amp; ', '& ', $safe_text );
1923 2143
1924 - return apply_filters( 'esc_textarea', $safe_text, $text );
2144 + /**
2145 + * @param string $safe_text
2146 + * @param string $text
2147 + */
2148 + return (string) apply_filters( 'esc_textarea', $safe_text, $text );
1925 2149 }
1926 2150
1927 2151 /**
1928 2152 * Add auto paragraphs to text areas
@@ -1973,12 +2197,12 @@
1973 2197 * @since 5.0.13 added $echo param.
1974 2198 *
1975 2199 * @param string $url
1976 2200 * @param bool $echo
1977 - * @return string|void
2201 + * @return string|null
1978 2202 */
1979 2203 public static function js_redirect( $url, $echo = false ) {
1980 - $callback = function() use ( $url ) {
2204 + $callback = function () use ( $url ) {
1981 2205 echo '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1982 2206 };
1983 2207 return self::clip( $callback, $echo );
1984 2208 }
@@ -2006,8 +2230,13 @@
2006 2230
2007 2231 return $user_id;
2008 2232 }
2009 2233
2234 + /**
2235 + * @param string $filename
2236 + * @param array $atts
2237 + * @return false|string
2238 + */
2010 2239 public static function get_file_contents( $filename, $atts = array() ) {
2011 2240 if ( ! is_file( $filename ) ) {
2012 2241 return false;
2013 2242 }
@@ -2013,9 +2242,9 @@
2013 2242 }
2014 2243
2015 2244 extract( $atts ); // phpcs:ignore WordPress.PHP.DontExtract
2016 2245 ob_start();
2017 - include( $filename );
2246 + include $filename;
2018 2247 $contents = ob_get_contents();
2019 2248 ob_end_clean();
2020 2249
2021 2250 return $contents;
@@ -2070,9 +2299,9 @@
2070 2299 ++$suffix;
2071 2300 } while ( in_array( $key_check, $similar_keys, true ) );
2072 2301
2073 2302 $key = $key_check;
2074 - }
2303 + }//end if
2075 2304
2076 2305 return $key;
2077 2306 }
2078 2307
@@ -2116,9 +2345,11 @@
2116 2345 * @return string
2117 2346 */
2118 2347 private static function generate_new_key( $num_chars ) {
2119 2348 $max_slug_value = pow( 36, $num_chars );
2120 - $min_slug_value = 37; // we want to have at least 2 characters in the slug
2349 +
2350 + // We want to have at least 2 characters in the slug.
2351 + $min_slug_value = 37;
2121 2352 return base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
2122 2353 }
2123 2354
2124 2355 /**
@@ -2147,11 +2378,16 @@
2147 2378
2148 2379 /**
2149 2380 * Editing a Form or Entry
2150 2381 *
2151 - * @param string $table
2382 + * @param object $record
2383 + * @param string $table
2384 + * @param array|string $fields
2385 + * @param bool $default
2386 + * @param array $post_values
2387 + * @param array $args
2152 2388 *
2153 - * @return bool|array
2389 + * @return array|bool
2154 2390 */
2155 2391 public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
2156 2392 if ( ! $record ) {
2157 2393 return false;
@@ -2204,13 +2440,12 @@
2204 2440 $post_values = $args['post_values'];
2205 2441
2206 2442 if ( $args['default'] ) {
2207 2443 $meta_value = $field->default_value;
2208 - } else {
2209 - if ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2210 - if ( ! isset( $field->field_options['custom_field'] ) ) {
2211 - $field->field_options['custom_field'] = '';
2212 - }
2444 + } elseif ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2445 + if ( ! isset( $field->field_options['custom_field'] ) ) {
2446 + $field->field_options['custom_field'] = '';
2447 + }
2213 2448 $meta_value = FrmProEntryMetaHelper::get_post_value(
2214 2449 $record->post_id,
2215 2450 $field->field_options['post_field'],
2216 2451 $field->field_options['custom_field'],
@@ -2220,12 +2455,11 @@
2220 2455 'form_id' => $field->form_id,
2221 2456 'field' => $field,
2222 2457 )
2223 2458 );
2224 - } else {
2225 - $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2226 - }
2227 - }
2459 + } else {
2460 + $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2461 + }//end if
2228 2462
2229 2463 $field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
2230 2464 if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
2231 2465 $new_value = $post_values['item_meta'][ $field->id ];
@@ -2273,12 +2507,15 @@
2273 2507 );
2274 2508 }
2275 2509
2276 2510 /**
2511 + * @param object $record
2277 2512 * @param string $table
2513 + * @param array $post_values
2514 + * @param array $values
2278 2515 */
2279 2516 private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
2280 - if ( $table == 'entries' ) {
2517 + if ( $table === 'entries' ) {
2281 2518 $form = $record->form_id;
2282 2519 FrmForm::maybe_get_form( $form );
2283 2520 } else {
2284 2521 $form = $record;
@@ -2314,9 +2551,9 @@
2314 2551 $form_defaults = FrmFormsHelper::get_default_opts();
2315 2552
2316 2553 foreach ( $form_defaults as $opt => $default ) {
2317 2554 if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
2318 - $values[ $opt ] = ( $post_values && isset( $post_values['options'][ $opt ] ) ) ? $post_values['options'][ $opt ] : $default;
2555 + $values[ $opt ] = $post_values && isset( $post_values['options'][ $opt ] ) ? $post_values['options'][ $opt ] : $default;
2319 2556 }
2320 2557
2321 2558 unset( $opt, $default );
2322 2559 }
@@ -2337,9 +2574,9 @@
2337 2574 * @since 2.2.10
2338 2575 *
2339 2576 * @param array $post_values
2340 2577 *
2341 - * @return boolean|int
2578 + * @return bool|int
2342 2579 */
2343 2580 public static function custom_style_value( $post_values ) {
2344 2581 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2345 2582 $custom_style = absint( $post_values['options']['custom_style'] );
@@ -2344,29 +2581,37 @@
2344 2581 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2345 2582 $custom_style = absint( $post_values['options']['custom_style'] );
2346 2583 } else {
2347 2584 $frm_settings = self::get_settings();
2348 - $custom_style = ( $frm_settings->load_style != 'none' );
2585 + $custom_style = ( $frm_settings->load_style !== 'none' );
2349 2586 }
2350 2587
2351 2588 return $custom_style;
2352 2589 }
2353 2590
2354 - public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
2355 - if ( is_array( $str ) ) {
2591 + /**
2592 + * @param mixed $original_string
2593 + * @param int|string $length
2594 + * @param int $minword
2595 + * @param string $continue
2596 + * @return string
2597 + */
2598 + public static function truncate( $original_string, $length, $minword = 3, $continue = '...' ) {
2599 + if ( ! is_string( $original_string ) && ! is_int( $original_string ) ) {
2356 2600 return '';
2357 2601 }
2358 2602
2359 2603 $length = (int) $length;
2360 - $str = wp_strip_all_tags( $str );
2604 + $str = wp_strip_all_tags( (string) $original_string );
2361 2605 $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
2362 2606
2363 2607 if ( $length == 0 ) {
2364 2608 return '';
2365 - } elseif ( $length <= 10 ) {
2609 + }
2610 +
2611 + if ( $length <= 10 ) {
2366 2612 $sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
2367 -
2368 - return $sub . ( ( $length < $original_len ) ? $continue : '' );
2613 + return $sub . ( $length < $original_len ? $continue : '' );
2369 2614 }
2370 2615
2371 2616 $sub = '';
2372 2617 $len = 0;
@@ -2372,10 +2617,14 @@
2372 2617 $len = 0;
2373 2618
2374 2619 $words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
2375 2620
2621 + if ( ! is_array( $words ) ) {
2622 + return $original_string;
2623 + }
2624 +
2376 2625 foreach ( $words as $word ) {
2377 - $part = ( ( $sub != '' ) ? ' ' : '' ) . $word;
2626 + $part = ( $sub != '' ? ' ' : '' ) . $word;
2378 2627 $total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
2379 2628 if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
2380 2629 break;
2381 2630 }
@@ -2389,11 +2638,37 @@
2389 2638
2390 2639 unset( $total_len, $word );
2391 2640 }
2392 2641
2393 - return $sub . ( ( $len < $original_len ) ? $continue : '' );
2642 + $sub = self::maybe_force_truncate_on_string_with_no_spaces( $sub, $length );
2643 +
2644 + return $sub . ( $len < $original_len ? $continue : '' );
2394 2645 }
2395 2646
2647 + /**
2648 + * If the string is still too long because there may not have been any spaces, force truncate.
2649 + *
2650 + * @since 6.5.4
2651 + *
2652 + * @param string $sub Current substring.
2653 + * @param int $length The length limit.
2654 + * @return string
2655 + */
2656 + private static function maybe_force_truncate_on_string_with_no_spaces( $sub, $length ) {
2657 + if ( strlen( $sub ) < $length + 50 ) {
2658 + // If the string isn't way over the limit, leave it.
2659 + return $sub;
2660 + }
2661 +
2662 + $first_space = strpos( $sub, ' ', $length );
2663 + if ( false !== $first_space ) {
2664 + // Ignore anything with spaces.
2665 + return $sub;
2666 + }
2667 +
2668 + return substr( $sub, 0, $length + 10 );
2669 + }
2670 +
2396 2671 public static function mb_function( $function_names, $args ) {
2397 2672 $mb_function_name = $function_names[0];
2398 2673 $function_name = $function_names[1];
2399 2674 if ( function_exists( $mb_function_name ) ) {
@@ -2426,8 +2701,13 @@
2426 2701
2427 2702 return $formatted;
2428 2703 }
2429 2704
2705 + /**
2706 + * @param string $time_format
2707 + * @param string $date
2708 + * @return string
2709 + */
2430 2710 private static function add_time_to_date( $time_format, $date ) {
2431 2711 if ( empty( $time_format ) ) {
2432 2712 $time_format = get_option( 'time_format' );
2433 2713 }
@@ -2450,12 +2730,12 @@
2450 2730 return date_i18n( $date_format, strtotime( $date ) );
2451 2731 }
2452 2732
2453 2733 /**
2454 - * Gets the time ago in words
2734 + * Gets the time ago in words.
2455 2735 *
2456 - * @param int $from in seconds
2457 - * @param int|string $to in seconds
2736 + * @param int $from In seconds.
2737 + * @param int|string $to In seconds.
2458 2738 *
2459 2739 * @return string $time_ago
2460 2740 */
2461 2741 public static function human_time_diff( $from, $to = '', $levels = 1 ) {
@@ -2470,9 +2750,9 @@
2470 2750 $diff_object = $now->diff( $ago );
2471 2751 $diff = get_object_vars( $diff_object );
2472 2752
2473 2753 // Add week amount and update day amount
2474 - $diff['w'] = floor( $diff['d'] / 7 );
2754 + $diff['w'] = floor( $diff['d'] / 7 );
2475 2755 $diff['d'] -= $diff['w'] * 7;
2476 2756
2477 2757 $time_strings = self::get_time_strings();
2478 2758
@@ -2479,9 +2759,9 @@
2479 2759 if ( ! is_numeric( $levels ) ) {
2480 2760 // Show time in specified unit.
2481 2761 $levels = self::get_unit( $levels );
2482 2762 if ( isset( $time_strings[ $levels ] ) ) {
2483 - $diff = array(
2763 + $diff = array(
2484 2764 $levels => self::time_format( $levels, $diff ),
2485 2765 );
2486 2766 $time_strings = array(
2487 2767 $levels => $time_strings[ $levels ],
@@ -2570,9 +2850,9 @@
2570 2850 }
2571 2851
2572 2852 /**
2573 2853 * Get the translatable time strings. The untranslated version is a failsafe
2574 - * in case langauges are changing for the unit set in the shortcode.
2854 + * in case languages are changing for the unit set in the shortcode.
2575 2855 *
2576 2856 * @since 2.0.20
2577 2857 * @return array
2578 2858 */
@@ -2618,23 +2898,28 @@
2618 2898
2619 2899 // Pagination Methods.
2620 2900
2621 2901 /**
2622 - * @param integer $current_p
2902 + * @param int $r_count
2903 + * @param int $current_p
2904 + * @param int $p_size
2905 + * @return int
2623 2906 */
2624 2907 public static function get_last_record_num( $r_count, $current_p, $p_size ) {
2625 - return ( ( $r_count < ( $current_p * $p_size ) ) ? $r_count : ( $current_p * $p_size ) );
2908 + return ( $r_count < $current_p * $p_size ? $r_count : $current_p * $p_size );
2626 2909 }
2627 2910
2628 2911 /**
2629 - * @param integer $current_p
2912 + * @param int $r_count
2913 + * @param int $current_p
2914 + * @param int $p_size
2915 + * @return int
2630 2916 */
2631 2917 public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2632 2918 if ( $current_p == 1 ) {
2633 2919 return 1;
2634 - } else {
2635 - return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2636 2920 }
2921 + return self::get_last_record_num( $r_count, $current_p - 1, $p_size ) + 1;
2637 2922 }
2638 2923
2639 2924 /**
2640 2925 * @return array
@@ -2657,9 +2942,9 @@
2657 2942 if ( ! isset( $l3 ) ) {
2658 2943 $l3 = $name;
2659 2944 }
2660 2945
2661 - $this_val = ( $p == $last ) ? $jv['value'] : array();
2946 + $this_val = $p == $last ? $jv['value'] : array();
2662 2947
2663 2948 switch ( $p ) {
2664 2949 case 0:
2665 2950 $l1 = $name;
@@ -2681,12 +2966,12 @@
2681 2966 self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2682 2967 }
2683 2968
2684 2969 unset( $this_val, $n );
2685 - }
2970 + }//end foreach
2686 2971
2687 2972 unset( $last, $jv );
2688 - }
2973 + }//end foreach
2689 2974
2690 2975 return $vars;
2691 2976 }
2692 2977
@@ -2934,8 +3219,11 @@
2934 3219 }
2935 3220
2936 3221 /**
2937 3222 * @since 4.02.03
3223 + *
3224 + * @param array|string $value
3225 + * @return string
2938 3226 */
2939 3227 public static function maybe_json_encode( $value ) {
2940 3228 if ( is_array( $value ) ) {
2941 3229 $value = wp_json_encode( $value );
@@ -2943,12 +3231,14 @@
2943 3231 return $value;
2944 3232 }
2945 3233
2946 3234 /**
3235 + * Echo The javascript to open and highlight the Formidable menu
3236 + *
2947 3237 * @since 1.07.10
2948 3238 *
2949 - * @param string $post_type The name of the post type that may need to be highlighted
2950 - * echo The javascript to open and highlight the Formidable menu
3239 + * @param string $post_type The name of the post type that may need to be highlighted.
3240 + * @return void
2951 3241 */
2952 3242 public static function maybe_highlight_menu( $post_type ) {
2953 3243 global $post;
2954 3244
@@ -2967,8 +3257,11 @@
2967 3257 /**
2968 3258 * Load the JS file on non-Formidable pages in the admin area
2969 3259 *
2970 3260 * @since 2.0
3261 + *
3262 + * @param bool $load
3263 + * @return void
2971 3264 */
2972 3265 public static function load_admin_wide_js( $load = true ) {
2973 3266 $version = self::plugin_version();
2974 3267 wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
@@ -2982,8 +3275,9 @@
2982 3275 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ),
2983 3276 'loading' => __( 'Loading&hellip;', 'formidable' ),
2984 3277 'nonce' => wp_create_nonce( 'frm_ajax' ),
2985 3278 'proIncludesSliderJs' => is_callable( 'FrmProFormsHelper::prepare_custom_currency' ),
3279 + 'inboxSlideIn' => FrmInbox::get_inbox_slide_in_value_for_js(),
2986 3280 );
2987 3281 wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
2988 3282
2989 3283 if ( $load ) {
@@ -2992,8 +3286,9 @@
2992 3286 }
2993 3287
2994 3288 /**
2995 3289 * @since 2.0.9
3290 + * @return void
2996 3291 */
2997 3292 public static function load_font_style() {
2998 3293 wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
2999 3294 }
@@ -2999,26 +3294,29 @@
2999 3294 }
3000 3295
3001 3296 /**
3002 3297 * @param string $location
3298 + * @return void
3003 3299 */
3004 3300 public static function localize_script( $location ) {
3005 - global $wp_scripts;
3301 + global $wp_scripts, $wp_version;
3006 3302
3007 3303 $script_strings = array(
3008 - 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3009 - 'images_url' => self::plugin_url() . '/images',
3010 - 'loading' => __( 'Loading&hellip;', 'formidable' ),
3011 - 'remove' => __( 'Remove', 'formidable' ),
3012 - 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3013 - 'nonce' => wp_create_nonce( 'frm_ajax' ),
3014 - 'id' => __( 'ID', 'formidable' ),
3015 - 'no_results' => __( 'No results match', 'formidable' ),
3016 - 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3017 - 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3018 - 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3019 - 'focus_first_error' => self::should_focus_first_error(),
3020 - 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3304 + 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3305 + 'images_url' => self::plugin_url() . '/images',
3306 + 'loading' => __( 'Loading&hellip;', 'formidable' ),
3307 + 'remove' => __( 'Remove', 'formidable' ),
3308 + 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3309 + 'nonce' => wp_create_nonce( 'frm_ajax' ),
3310 + 'id' => __( 'ID', 'formidable' ),
3311 + 'no_results' => __( 'No results match', 'formidable' ),
3312 + 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3313 + 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3314 + 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3315 + 'focus_first_error' => self::should_focus_first_error(),
3316 + 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3317 + // We need to keep this setting for a few versions because Pro checks for this.
3318 + 'include_resend_email' => false,
3021 3319 );
3022 3320
3023 3321 $data = $wp_scripts->get_data( 'formidable', 'data' );
3024 3322 if ( ! $data ) {
@@ -3025,59 +3323,74 @@
3025 3323 wp_localize_script( 'formidable', 'frm_js', $script_strings );
3026 3324 }
3027 3325
3028 3326 if ( $location === 'admin' ) {
3029 - $frm_settings = self::get_settings();
3030 3327 $admin_script_strings = array(
3031 - 'desc' => __( '(Click to add description)', 'formidable' ),
3032 - 'blank' => __( '(Blank)', 'formidable' ),
3033 - 'no_label' => __( '(no label)', 'formidable' ),
3034 - 'ok' => __( 'OK', 'formidable' ),
3035 - 'cancel' => __( 'Cancel', 'formidable' ),
3036 - 'default_label' => __( 'Default', 'formidable' ),
3037 - 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3038 - 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3039 - 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3040 - 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3041 - 'confirm' => __( 'Are you sure?', 'formidable' ),
3042 - 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3043 - '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' ),
3044 - 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3045 - 'default_unique' => $frm_settings->unique_msg,
3046 - 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3047 - 'enter_email' => __( 'Enter Email', 'formidable' ),
3048 - 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3049 - 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3050 - 'new_option' => __( 'New Option', 'formidable' ),
3051 - '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' ),
3052 - 'enter_password' => __( 'Enter Password', 'formidable' ),
3053 - 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3054 - 'import_complete' => __( 'Import Complete', 'formidable' ),
3055 - 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3056 - 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3057 - 'private_label' => __( 'Private', 'formidable' ),
3058 - 'jquery_ui_url' => '',
3059 - 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3060 - 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3061 - 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3062 - 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3063 - 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3064 - 'only_one_action' => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
3065 - 'unsafe_params' => FrmFormsHelper::reserved_words(),
3328 + 'desc' => __( '(Click to add description)', 'formidable' ),
3329 + 'blank' => __( '(Blank)', 'formidable' ),
3330 + 'no_label' => __( '(no label)', 'formidable' ),
3331 + 'ok' => __( 'OK', 'formidable' ),
3332 + 'cancel' => __( 'Cancel', 'formidable' ),
3333 + 'default_label' => __( 'Default', 'formidable' ),
3334 + 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3335 + 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3336 + 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3337 + 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3338 + 'confirm' => __( 'Are you sure?', 'formidable' ),
3339 + 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3340 + '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' ),
3341 + 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3342 + 'default_unique' => FrmFieldsHelper::default_unique_msg(),
3343 + 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3344 + 'enter_email' => __( 'Enter Email', 'formidable' ),
3345 + 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3346 + 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3347 + 'new_option' => __( 'New Option', 'formidable' ),
3348 + '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' ),
3349 + 'enter_password' => __( 'Enter Password', 'formidable' ),
3350 + 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3351 + 'import_complete' => __( 'Import Complete', 'formidable' ),
3352 + 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3353 + 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3354 + 'private_label' => __( 'Private', 'formidable' ),
3355 + 'jquery_ui_url' => '',
3356 + 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3357 + 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3358 + 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3359 + 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3360 + 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3361 + /* translators: %d is the number of allowed actions per form */
3362 + 'only_one_action' => sprintf( __( 'This form action is limited to %d per form.', 'formidable' ), 1 ),
3363 + 'edit_action_text' => __( 'Please edit the existing form action.', 'formidable' ),
3364 + 'unsafe_params' => FrmFormsHelper::reserved_words(),
3066 3365 /* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
3067 - 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3366 + 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3068 3367 /* 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. */
3069 - 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3070 - 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3071 - 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3072 - 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3073 - 'install' => __( 'Install', 'formidable' ),
3074 - 'active' => __( 'Active', 'formidable' ),
3075 - 'select_a_field' => __( 'Select a Field', 'formidable' ),
3076 - 'no_items_found' => __( 'No items found.', 'formidable' ),
3077 - 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3078 - 'saving' => '', // Deprecated in 6.0.
3079 - 'saved' => '', // Deprecated in 6.0.
3368 + 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3369 + 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3370 + 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3371 + 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3372 + 'install' => __( 'Install', 'formidable' ),
3373 + 'active' => __( 'Active', 'formidable' ),
3374 + 'installed' => __( 'Installed', 'formidable' ),
3375 + 'not_installed' => __( 'Not Installed', 'formidable' ),
3376 + 'select_a_field' => __( 'Select a Field', 'formidable' ),
3377 + 'no_items_found' => __( 'No items found.', 'formidable' ),
3378 + 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3379 +
3380 + // Deprecated in 6.0.
3381 + 'saving' => '',
3382 +
3383 + // Deprecated in 6.0.
3384 + 'saved' => '',
3385 +
3386 + // translators: %1$s: HTML open tag, %2$s: HTML end tag.
3387 + 'holdShiftMsg' => esc_html__( 'You can hold %1$sShift%2$s on your keyboard to select multiple fields', 'formidable' ),
3388 + 'noTitleText' => FrmFormsHelper::get_no_title_text(),
3389 +
3390 + // In older versions this event listener causes the section to immediately close again
3391 + // when the h3 element is clicked. It's only required in WP 6.7+.
3392 + 'requireAccordionTitleClickListener' => version_compare( $wp_version, '6.7', '>=' ),
3080 3393 );
3081 3394 /**
3082 3395 * @param array $admin_script_strings
3083 3396 */
@@ -3086,9 +3399,9 @@
3086 3399 $data = $wp_scripts->get_data( 'formidable_admin', 'data' );
3087 3400 if ( ! $data ) {
3088 3401 wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
3089 3402 }
3090 - }
3403 + }//end if
3091 3404 }
3092 3405
3093 3406 /**
3094 3407 * @since 6.5
@@ -3132,9 +3445,10 @@
3132 3445 * Echo the message on the plugins listing page
3133 3446 *
3134 3447 * @since 1.07.10
3135 3448 *
3136 - * @param float $min_version The version the add-on requires
3449 + * @param float $min_version The version the add-on requires.
3450 + * @return void
3137 3451 */
3138 3452 public static function min_version_notice( $min_version ) {
3139 3453 $frm_version = self::plugin_version();
3140 3454
@@ -3168,9 +3482,8 @@
3168 3482 if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
3169 3483 return;
3170 3484 }
3171 3485
3172 - $pro_version = FrmProDb::$plug_version;
3173 3486 $expired = FrmAddonsController::is_license_expired();
3174 3487 ?>
3175 3488 <div class="frm-banner-alert frm_error_style frm_previous_install">
3176 3489 <?php
@@ -3188,8 +3501,11 @@
3188 3501 /**
3189 3502 * If Pro is installed, check the version number.
3190 3503 *
3191 3504 * @since 4.0.01
3505 + *
3506 + * @param string $min_version
3507 + * @return bool
3192 3508 */
3193 3509 public static function meets_min_pro_version( $min_version ) {
3194 3510 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3195 3511 }
@@ -3194,24 +3510,19 @@
3194 3510 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3195 3511 }
3196 3512
3197 3513 /**
3198 - * Show a message if the browser or PHP version is below the recommendations.
3514 + * Show a message if the PHP version is below the recommendations.
3199 3515 *
3200 3516 * @since 4.0.02
3517 + * @return void
3201 3518 */
3202 3519 private static function php_version_notice() {
3203 3520 $message = array();
3204 - if ( version_compare( phpversion(), '5.6', '<' ) ) {
3521 + if ( version_compare( phpversion(), '7.0', '<' ) ) {
3205 3522 $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' );
3206 3523 }
3207 3524
3208 - $browser = self::get_server_value( 'HTTP_USER_AGENT' );
3209 - $is_ie = strpos( $browser, 'MSIE' ) !== false;
3210 - if ( $is_ie ) {
3211 - $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' );
3212 - }
3213 -
3214 3525 foreach ( $message as $m ) {
3215 3526 ?>
3216 3527 <div class="frm-banner-alert frm_error_style frm_previous_install">
3217 3528 <?php echo esc_html( $m ); ?>
@@ -3341,16 +3652,10 @@
3341 3652 return $locales;
3342 3653 }
3343 3654
3344 3655 /**
3345 - * Output HTML containing reference text for accessibility
3346 - *
3347 - * @deprecated 5.1
3656 + * @return string
3348 3657 */
3349 - public static function multiselect_accessibility() {
3350 - _deprecated_function( __METHOD__, '5.1' );
3351 - }
3352 -
3353 3658 public static function get_menu_icon_class() {
3354 3659 if ( is_callable( 'FrmProAppHelper::get_settings' ) ) {
3355 3660 $settings = FrmProAppHelper::get_settings();
3356 3661 if ( is_object( $settings ) && ! empty( $settings->menu_icon ) ) {
@@ -3460,8 +3765,18 @@
3460 3765 return apply_filters( 'frm_images_dropdown_input_attrs', $input_attrs_str, $args );
3461 3766 }
3462 3767
3463 3768 /**
3769 + * @since 6.7.1
3770 + */
3771 + public static function get_images_dropdown_atts( $option, $args ) {
3772 + $image = self::get_images_dropdown_option_image( $option, $args );
3773 + $classes = self::get_images_dropdown_option_classes( $option, $args );
3774 + $custom_attrs = self::get_images_dropdown_option_html_attrs( $option, $args );
3775 + return compact( 'image', 'classes', 'custom_attrs' );
3776 + }
3777 +
3778 + /**
3464 3779 * Gets the image of each option in images_dropdown() method.
3465 3780 *
3466 3781 * @since 5.0.04
3467 3782 *
@@ -3472,9 +3787,9 @@
3472 3787 private static function get_images_dropdown_option_image( $option, $args ) {
3473 3788 $image = self::icon_by_class(
3474 3789 'frmfont ' . $option['svg'],
3475 3790 array(
3476 - 'echo' => false,
3791 + 'echo' => false,
3477 3792 )
3478 3793 );
3479 3794
3480 3795 $args['option'] = $option;
@@ -3612,15 +3927,15 @@
3612 3927 return $values;
3613 3928 }
3614 3929
3615 3930 /**
3616 - * Some back end fields allow privleged users to add scripts.
3931 + * Some back end fields allow privileged users to add scripts.
3617 3932 * A site that uses the DISALLOW_UNFILTERED_HTML always remove scripts on echo.
3618 3933 *
3619 3934 * @since 5.0.13
3620 3935 *
3621 3936 * @param string $value
3622 - * @param array|string $allowed 'all' for everything included as defaults
3937 + * @param array|string $allowed 'all' for everything included as defaults.
3623 3938 * @return string
3624 3939 */
3625 3940 public static function maybe_kses( $value, $allowed = 'all' ) {
3626 3941 if ( self::should_never_allow_unfiltered_html() ) {
@@ -3629,8 +3944,64 @@
3629 3944 return $value;
3630 3945 }
3631 3946
3632 3947 /**
3948 + * Check if an option attribute used in an [input] shortcode is safe.
3949 + *
3950 + * @since 6.11.2
3951 + *
3952 + * @param string $key
3953 + * @param string $context Either 'display' or 'update'. On update, we want to allow a few keys that are never displayed.
3954 + * @return bool
3955 + */
3956 + public static function input_key_is_safe( $key, $context = 'display' ) {
3957 + if ( 'update' === $context && in_array( $key, array( 'opt', 'label' ), true ) ) {
3958 + $safe = true;
3959 + } elseif ( 0 === strpos( $key, 'data-' ) ) {
3960 + // Allow all data attributes.
3961 + $safe = true;
3962 + } elseif ( 0 === strpos( $key, 'aria-' ) ) {
3963 + // Allow all aria attributes.
3964 + $safe = true;
3965 + } else {
3966 + $safe_keys = array(
3967 + 'class',
3968 + 'required',
3969 + 'title',
3970 + 'placeholder',
3971 + 'value',
3972 + 'readonly',
3973 + 'disabled',
3974 + 'size',
3975 + 'maxlength',
3976 + 'min',
3977 + 'max',
3978 + 'pattern',
3979 + 'step',
3980 + 'autofocus',
3981 + 'width',
3982 + 'height',
3983 + 'autocomplete',
3984 + 'tabindex',
3985 + 'role',
3986 + 'style',
3987 + );
3988 + $safe = in_array( $key, $safe_keys, true );
3989 + }//end if
3990 +
3991 + /**
3992 + * Filter the $safe value so additional keys can be allowed or disallowed.
3993 + *
3994 + * @since 6.11.2
3995 + *
3996 + * @param bool $safe True if the key is considered safe.
3997 + * @param string $key
3998 + * @param string $context Either 'display' or 'update'.
3999 + */
4000 + return (bool) apply_filters( 'frm_input_key_is_safe', $safe, $key, $context );
4001 + }
4002 +
4003 + /**
3633 4004 * @since 5.0.16
3634 4005 *
3635 4006 * @return bool
3636 4007 */
@@ -3655,20 +4026,9 @@
3655 4026
3656 4027 /**
3657 4028 * @since 5.0.17
3658 4029 *
3659 - * @param string $plugin
3660 - * @return string|false
3661 - */
3662 - private static function get_plan_required( $plugin ) {
3663 - $link = FrmAddonsController::install_link( $plugin );
3664 - return FrmFormsHelper::get_plan_required( $link );
3665 - }
3666 -
3667 - /**
3668 - * @since 5.0.17
3669 - *
3670 - * @param string
4030 + * @param string $feature
3671 4031 * @return bool
3672 4032 */
3673 4033 public static function show_new_feature( $feature ) {
3674 4034 $link = FrmAddonsController::install_link( $feature );
@@ -3741,9 +4101,9 @@
3741 4101 public static function show_pill_text( $text = null ) {
3742 4102 if ( null === $text ) {
3743 4103 $text = __( 'NEW', 'formidable' );
3744 4104 }
3745 - echo '<span class="frm-new-pill">' . esc_html( $text ) . '</span>';
4105 + echo '<span class="frm-meta-tag frm-new-pill">' . esc_html( $text ) . '</span>';
3746 4106 }
3747 4107
3748 4108 /**
3749 4109 * Count the number of decimals digits.
@@ -3750,9 +4110,9 @@
3750 4110 *
3751 4111 * @since 5.2.07
3752 4112 *
3753 4113 * @param mixed $num Number.
3754 - * @return int|false Returns `false` if the passed parameter is not number.
4114 + * @return false|int Returns `false` if the passed parameter is not number.
3755 4115 */
3756 4116 public static function count_decimals( $num ) {
3757 4117 if ( ! is_numeric( $num ) ) {
3758 4118 return false;
@@ -3783,9 +4143,9 @@
3783 4143 }
3784 4144
3785 4145 add_filter(
3786 4146 'option_gmt_offset',
3787 - function( $offset ) {
4147 + function ( $offset ) {
3788 4148 if ( ! is_string( $offset ) || is_numeric( $offset ) ) {
3789 4149 // Leave a valid value alone.
3790 4150 return $offset;
3791 4151 }
@@ -3867,65 +4227,8 @@
3867 4227 return true;
3868 4228 }
3869 4229
3870 4230 /**
3871 - * @since 4.08
3872 - * @deprecated 4.09.01
3873 - */
3874 - public static function expiring_message() {
3875 - _deprecated_function( __METHOD__, '4.09.01', 'FrmProAddonsController::expiring_message' );
3876 - if ( is_callable( 'FrmProAddonsController::expiring_message' ) ) {
3877 - FrmProAddonsController::expiring_message();
3878 - }
3879 - }
3880 -
3881 - /**
3882 - * Use the WP 4.7 wp_doing_ajax function
3883 - *
3884 - * @since 2.05.07
3885 - * @deprecated 4.04.04
3886 - */
3887 - public static function wp_doing_ajax() {
3888 - _deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
3889 - return wp_doing_ajax();
3890 - }
3891 -
3892 - /**
3893 - * @deprecated 4.0
3894 - */
3895 - public static function insert_opt_html( $args ) {
3896 - _deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
3897 - FrmFormsHelper::insert_opt_html( $args );
3898 - }
3899 -
3900 - /**
3901 - * @deprecated 3.01
3902 - * @codeCoverageIgnore
3903 - */
3904 - public static function sanitize_array( &$values ) {
3905 - FrmDeprecated::sanitize_array( $values );
3906 - }
3907 -
3908 - /**
3909 - * @since 2.0
3910 - * @deprecated 5.0.13
3911 - *
3912 - * @return string The base Google APIS url for the current version of jQuery UI
3913 - */
3914 - public static function jquery_ui_base_url() {
3915 - _deprecated_function( __FUNCTION__, '5.0.13', 'FrmProAppHelper::jquery_ui_base_url' );
3916 - return is_callable( 'FrmProAppHelper::jquery_ui_base_url' ) ? FrmProAppHelper::jquery_ui_base_url() : '';
3917 - }
3918 -
3919 - /**
3920 - * @since 4.07
3921 - * @deprecated 6.0
3922 - */
3923 - public static function renewal_message() {
3924 - _deprecated_function( __METHOD__, '6.0', 'FrmProAddonsController::renewal_message' );
3925 - }
3926 -
3927 - /**
3928 4231 * Display a dismissable warning message and save its dismissal state.
3929 4232 *
3930 4233 * @since 6.3
3931 4234 *
@@ -3937,9 +4240,9 @@
3937 4240 if ( ! $message || ! $option ) {
3938 4241 return;
3939 4242 }
3940 4243
3941 - $ajax_callback = function() use ( $option ) {
4244 + $ajax_callback = function () use ( $option ) {
3942 4245 self::dismiss_warning_message( $option );
3943 4246 };
3944 4247
3945 4248 // We're handling JS codes with `doJsonPost` and it adds 'frm_' to the beginning of the action.
@@ -3947,9 +4250,9 @@
3947 4250 add_action( 'wp_ajax_frm_' . $option, $ajax_callback );
3948 4251
3949 4252 add_filter(
3950 4253 'frm_message_list',
3951 - function( $show_messages ) use ( $message, $option ) {
4254 + function ( $show_messages ) use ( $message, $option ) {
3952 4255 if ( get_option( $option, false ) ) {
3953 4256 return $show_messages;
3954 4257 }
3955 4258
@@ -3956,9 +4259,9 @@
3956 4259 $dismiss_icon = self::icon_by_class(
3957 4260 'frmfont frm_close_icon',
3958 4261 array(
3959 4262 'aria-label' => _x( 'Dismiss', 'warning message: close icon label', 'formidable' ),
3960 - 'echo' => false,
4263 + 'echo' => false,
3961 4264 )
3962 4265 );
3963 4266
3964 4267 $show_messages[] = $message;
@@ -3985,6 +4288,100 @@
3985 4288 update_option( $option, true, 'no' );
3986 4289 }
3987 4290
3988 4291 wp_send_json_success();
4292 + }
4293 +
4294 + /**
4295 + * Lite license copy.
4296 + * Used in FrmDashboardController & FrmSettingsController
4297 + *
4298 + * @since 6.8
4299 + *
4300 + * @return string
4301 + */
4302 + public static function copy_for_lite_license() {
4303 + $message = __( 'You\'re using Formidable Forms Lite - no license needed. Enjoy!', 'formidable' ) . ' 🙂';
4304 +
4305 + if ( is_callable( 'FrmProAddonsController::get_readable_license_type' ) && ! class_exists( 'FrmProDashboardController' ) ) {
4306 + // Manage PRO versions without PRO dashboard functionality.
4307 + $license_type = FrmProAddonsController::get_readable_license_type();
4308 + if ( 'lite' !== strtolower( $license_type ) ) {
4309 + $message = 'Formidable Pro ' . $license_type;
4310 + }
4311 + }
4312 +
4313 + return apply_filters( 'frm_license_type_text', $message );
4314 + }
4315 +
4316 + /**
4317 + * Removes scripts that are unnecessarily loaded across the pages!
4318 + *
4319 + * @since 6.9
4320 + * @return void
4321 + */
4322 + public static function dequeue_extra_global_scripts() {
4323 + wp_dequeue_script( 'frm-surveys-admin' );
4324 + wp_dequeue_script( 'frm-quizzes-form-action' );
4325 + }
4326 +
4327 + /**
4328 + * Shows tooltip icon.
4329 + *
4330 + * @since 6.12
4331 + *
4332 + * @param string $tooltip_text Tooltip text.
4333 + * @param array $atts Tooltip wrapper HTML attributes.
4334 + *
4335 + * @return void
4336 + */
4337 + public static function tooltip_icon( $tooltip_text, $atts = array() ) {
4338 + $atts['title'] = $tooltip_text;
4339 + if ( isset( $atts['class'] ) ) {
4340 + $atts['class'] .= ' frm_help';
4341 + } else {
4342 + $atts['class'] = 'frm_help';
4343 + }
4344 + ?>
4345 + <span <?php self::array_to_html_params( $atts, true ); ?>>
4346 + <?php self::icon_by_class( 'frmfont frm_tooltip_icon' ); ?>
4347 + </span>
4348 + <?php
4349 + }
4350 +
4351 + /**
4352 + * Prints errors for settings in onboarding wizard or template settings.
4353 + *
4354 + * @since 6.15
4355 + *
4356 + * @param array $args Args.
4357 + *
4358 + * @return void
4359 + */
4360 + public static function print_setting_error( $args ) {
4361 + $args = wp_parse_args(
4362 + $args,
4363 + array(
4364 + 'id' => '',
4365 + 'errors' => array(),
4366 + 'class' => '',
4367 + )
4368 + );
4369 +
4370 + $args['class'] .= ' frm-validation-error frm-mt-xs frm_hidden';
4371 + ?>
4372 + <span id="<?php echo esc_attr( $args['id'] ); ?>" class="<?php echo esc_attr( $args['class'] ); ?>">
4373 + <?php
4374 + if ( is_array( $args['errors'] ) ) {
4375 + foreach ( $args['errors'] as $key => $msg ) {
4376 + ?>
4377 + <span frm-error="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $msg ); ?></span>
4378 + <?php
4379 + }
4380 + } else {
4381 + echo '<span>' . esc_html( $args['errors'] ) . '</span>';
4382 + }
4383 + ?>
4384 + </span>
4385 + <?php
3989 4386 }
3990 4387 }