PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.22.3
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.22.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 +966 -355 6.5.16.22.3 View file →
@@ -3,27 +3,43 @@
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;
10 7
11 8 /**
12 - * @var bool $added_gmt_offset_filter
9 + * Version of the database we are moving to.
10 + *
11 + * @var int
13 12 */
13 + public static $db_version = 103;
14 +
15 + /**
16 + * Used by the API add-on.
17 + *
18 + * @var float
19 + */
20 + public static $font_version = 7;
21 +
22 + /**
23 + * @var bool
24 + */
14 25 private static $added_gmt_offset_filter = false;
15 26
16 27 /**
17 28 * @since 2.0
29 + *
30 + * @var string
18 31 */
19 - public static $plug_version = '6.5.1';
32 + public static $plug_version = '6.22.3';
20 33
21 34 /**
35 + * @var bool
36 + */
37 + private static $included_svg = false;
38 +
39 + /**
22 40 * @since 1.07.02
23 41 *
24 - * @param none
25 - *
26 42 * @return string The version of this plugin
27 43 */
28 44 public static function plugin_version() {
29 45 return self::$plug_version;
@@ -28,21 +44,33 @@
28 44 public static function plugin_version() {
29 45 return self::$plug_version;
30 46 }
31 47
48 + /**
49 + * @return string
50 + */
32 51 public static function plugin_folder() {
33 52 return basename( self::plugin_path() );
34 53 }
35 54
55 + /**
56 + * @return string
57 + */
36 58 public static function plugin_path() {
37 - return dirname( dirname( dirname( __FILE__ ) ) );
59 + return dirname( dirname( __DIR__ ) );
38 60 }
39 61
62 + /**
63 + * @return string
64 + */
40 65 public static function plugin_url() {
41 - // Prevously FRM_URL constant.
66 + // Previously FRM_URL constant.
42 67 return plugins_url( '', self::plugin_path() . '/formidable.php' );
43 68 }
44 69
70 + /**
71 + * @return string
72 + */
45 73 public static function relative_plugin_url() {
46 74 return str_replace( array( 'https:', 'http:' ), '', self::plugin_url() );
47 75 }
48 76
@@ -63,8 +91,12 @@
63 91 public static function site_name() {
64 92 return get_option( 'blogname' );
65 93 }
66 94
95 + /**
96 + * @param string $url
97 + * @return string
98 + */
67 99 public static function make_affiliate_url( $url ) {
68 100 $affiliate_id = self::get_affiliate();
69 101 if ( ! empty( $affiliate_id ) ) {
70 102 $url = str_replace( array( 'http://', 'https://' ), '', $url );
@@ -73,8 +105,11 @@
73 105
74 106 return $url;
75 107 }
76 108
109 + /**
110 + * @return int
111 + */
77 112 public static function get_affiliate() {
78 113 return absint( apply_filters( 'frm_affiliate_id', 0 ) );
79 114 }
80 115
@@ -92,9 +127,9 @@
92 127 }
93 128
94 129 $anchor = '';
95 130 if ( is_array( $args ) ) {
96 - $medium = $args['medium'];
131 + $medium = isset( $args['medium'] ) ? $args['medium'] : '';
97 132 if ( isset( $args['content'] ) ) {
98 133 $content = $args['content'];
99 134 }
100 135 if ( isset( $args['anchor'] ) ) {
@@ -126,14 +161,42 @@
126 161 return self::make_affiliate_url( $link );
127 162 }
128 163
129 164 /**
165 + * @since 6.21
166 + *
167 + * @param string $cta_link
168 + * @param array $utm
169 + */
170 + public static function maybe_add_missing_utm( $cta_link, $utm ) {
171 + $query_args = array();
172 +
173 + if ( false === strpos( $cta_link, 'utm_source' ) ) {
174 + $query_args['utm_source'] = 'WordPress';
175 + }
176 +
177 + if ( false === strpos( $cta_link, 'utm_campaign' ) ) {
178 + $query_args['utm_campaign'] = 'liteplugin';
179 + }
180 +
181 + if ( false === strpos( $cta_link, 'utm_medium' ) && isset( $utm['medium'] ) ) {
182 + $query_args['utm_medium'] = $utm['medium'];
183 + }
184 +
185 + if ( false === strpos( $cta_link, 'utm_content' ) && isset( $utm['content'] ) ) {
186 + $query_args['utm_content'] = $utm['content'];
187 + }
188 +
189 + return $query_args ? add_query_arg( $query_args, $cta_link ) : $cta_link;
190 + }
191 +
192 + /**
130 193 * Get the Formidable settings
131 194 *
132 195 * @since 2.0
133 196 *
134 197 * @param array $args - May include the form id when values need translation.
135 - * @return FrmSettings $frm_setings
198 + * @return FrmSettings $frm_settings
136 199 */
137 200 public static function get_settings( $args = array() ) {
138 201 global $frm_settings;
139 202 if ( empty( $frm_settings ) ) {
@@ -145,8 +208,11 @@
145 208
146 209 return $frm_settings;
147 210 }
148 211
212 + /**
213 + * @return string
214 + */
149 215 public static function get_menu_name() {
150 216 $frm_settings = self::get_settings();
151 217
152 218 return FrmAddonsController::is_license_expired() ? 'Formidable' : $frm_settings->menu;
@@ -153,24 +219,28 @@
153 219 }
154 220
155 221 /**
156 222 * Determine if the current branding is set to 'formidable'.
223 + * Checks the menu icon, and verifies if it matches the formidable branding.
157 224 *
158 - * Checks the menu title, retrieved through get_menu_name,
159 - * and verifies if it matches the 'formidable' branding.
160 - *
161 225 * @since 6.4.2
162 226 *
163 - * @return bool True if the menu title is 'formidable', false otherwise.
227 + * @return bool True if the menu icon is the logo, false otherwise.
164 228 */
165 229 public static function is_formidable_branding() {
166 - $menu_title = self::get_menu_name();
230 + if ( ! self::pro_is_installed() ) {
231 + return true;
232 + }
167 233
168 - return 'formidable' === strtolower( trim( $menu_title ) );
234 + $menu_icon = self::get_menu_icon_class();
235 + return strpos( $menu_icon, 'frm_logo_icon' ) !== false;
169 236 }
170 237
171 238 /**
172 239 * @since 3.05
240 + *
241 + * @param array $atts
242 + * @return string
173 243 */
174 244 public static function svg_logo( $atts = array() ) {
175 245 $defaults = array(
176 246 'height' => 18,
@@ -187,8 +257,11 @@
187 257 }
188 258
189 259 /**
190 260 * @since 4.0
261 + *
262 + * @param array $atts
263 + * @return void
191 264 */
192 265 public static function show_logo( $atts = array() ) {
193 266 echo self::kses( self::svg_logo( $atts ), 'all' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
194 267 }
@@ -194,8 +267,10 @@
194 267 }
195 268
196 269 /**
197 270 * @since 4.03.02
271 + *
272 + * @return void
198 273 */
199 274 public static function show_header_logo() {
200 275 $icon = self::svg_logo(
201 276 array(
@@ -217,21 +292,38 @@
217 292 }
218 293
219 294 /**
220 295 * @since 2.02.04
296 + *
297 + * @return bool
221 298 */
222 299 public static function ips_saved() {
223 300 $frm_settings = self::get_settings();
224 -
225 301 return ! $frm_settings->no_ips;
226 302 }
227 303
304 + /**
305 + * @return bool
306 + */
228 307 public static function pro_is_installed() {
229 - return apply_filters( 'frm_pro_installed', false );
308 + return (bool) apply_filters( 'frm_pro_installed', false );
230 309 }
231 310
232 311 /**
312 + * Check if the Pro plugin is installed, whether authorized or not.
313 + *
314 + * @since 6.8.3
315 + *
316 + * @return bool
317 + */
318 + public static function pro_is_included() {
319 + return function_exists( 'load_formidable_pro' );
320 + }
321 +
322 + /**
233 323 * @since 4.06.02
324 + *
325 + * @return bool
234 326 */
235 327 public static function pro_is_connected() {
236 328 global $frm_vars;
237 329 return self::pro_is_installed() && $frm_vars['pro_is_authorized'];
@@ -238,14 +330,26 @@
238 330 }
239 331
240 332 /**
241 333 * @since 4.06
334 + * @since 6.16.2 Added $check_for_settings parameter
335 + *
336 + * @param bool $check_for_settings
337 + *
338 + * @return bool
242 339 */
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' );
340 + public static function is_form_builder_page( $check_for_settings = true ) {
341 + $action = self::simple_get( 'frm_action', 'sanitize_title' );
342 + $check_actions = array( 'edit', 'duplicate' );
343 + if ( $check_for_settings ) {
344 + $check_actions[] = 'settings';
345 + }
346 + return self::is_admin_page( 'formidable' ) && in_array( $action, $check_actions, true );
246 347 }
247 348
349 + /**
350 + * @return bool
351 + */
248 352 public static function is_formidable_admin() {
249 353 $page = self::simple_get( 'page', 'sanitize_title' );
250 354 $is_formidable = strpos( $page, 'formidable' ) !== false;
251 355 if ( empty( $page ) ) {
@@ -255,15 +359,52 @@
255 359 return $is_formidable;
256 360 }
257 361
258 362 /**
363 + * Checks if is a list page.
364 + *
365 + * @since 6.19
366 + *
367 + * @param string $page The name of the page to check.
368 + * @return bool
369 + */
370 + public static function is_admin_list_page( $page = 'formidable' ) {
371 + if ( 'formidable' === $page ) {
372 + return self::on_form_listing_page();
373 + }
374 +
375 + if ( ! self::is_admin_page( $page ) ) {
376 + return false;
377 + }
378 +
379 + if ( 'formidable-entries' === $page ) {
380 + $action = self::simple_get( 'frm_action' );
381 + if ( ! $action || in_array( $action, self::get_entries_listing_page_form_actions(), true ) ) {
382 + return true;
383 + }
384 + }
385 +
386 + // Check edit or settings page.
387 + return ! self::simple_get( 'frm_action' );
388 + }
389 +
390 + /**
391 + * @since 6.20
392 + *
393 + * @return array<string>
394 + */
395 + private static function get_entries_listing_page_form_actions() {
396 + return array( 'list', 'destroy' );
397 + }
398 +
399 + /**
259 400 * Check for certain page in Formidable settings
260 401 *
261 402 * @since 2.0
262 403 *
263 - * @param string $page The name of the page to check
404 + * @param string $page The name of the page to check.
264 405 *
265 - * @return boolean
406 + * @return bool
266 407 */
267 408 public static function is_admin_page( $page = 'formidable' ) {
268 409 global $pagenow;
269 410 $get_page = self::simple_get( 'page', 'sanitize_title' );
@@ -282,8 +423,10 @@
282 423 * If the current page is for editing or creating a view.
283 424 * Returns false for the views listing page.
284 425 *
285 426 * @since 4.0
427 + *
428 + * @return bool
286 429 */
287 430 public static function is_view_builder_page() {
288 431 global $pagenow;
289 432
@@ -293,10 +436,10 @@
293 436
294 437 $post_type = self::simple_get( 'post_type', 'sanitize_title' );
295 438
296 439 if ( empty( $post_type ) ) {
297 - $post_id = self::simple_get( 'post', 'absint' );
298 - $post = get_post( $post_id );
440 + $post_id = self::simple_get( 'post', 'absint' );
441 + $post = get_post( $post_id );
299 442 $post_type = $post ? $post->post_type : '';
300 443 }
301 444
302 445 return $post_type === 'frm_display';
@@ -306,17 +449,15 @@
306 449 * Check for the form preview page
307 450 *
308 451 * @since 2.0
309 452 *
310 - * @param None
311 - *
312 - * @return boolean
453 + * @return bool
313 454 */
314 455 public static function is_preview_page() {
315 456 global $pagenow;
316 457 $action = self::simple_get( 'action', 'sanitize_title' );
317 458
318 - return $pagenow && $pagenow == 'admin-ajax.php' && $action == 'frm_forms_preview';
459 + return $pagenow && $pagenow === 'admin-ajax.php' && $action === 'frm_forms_preview';
319 460 }
320 461
321 462 /**
322 463 * Check for ajax except the form preview page
@@ -322,16 +463,17 @@
322 463 * Check for ajax except the form preview page
323 464 *
324 465 * @since 2.0
325 466 *
326 - * @param None
327 - *
328 - * @return boolean
467 + * @return bool
329 468 */
330 469 public static function doing_ajax() {
331 470 return wp_doing_ajax() && ! self::is_preview_page();
332 471 }
333 472
473 + /**
474 + * @return string
475 + */
334 476 public static function js_suffix() {
335 477 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
336 478 }
337 479
@@ -336,13 +478,13 @@
336 478 }
337 479
338 480 /**
339 481 * @since 2.0.8
482 + * @return bool
340 483 */
341 484 public static function prevent_caching() {
342 485 global $frm_vars;
343 -
344 - return isset( $frm_vars['prevent_caching'] ) && $frm_vars['prevent_caching'];
486 + return ! empty( $frm_vars['prevent_caching'] );
345 487 }
346 488
347 489 /**
348 490 * Check if on an admin page
@@ -348,9 +490,9 @@
348 490 * Check if on an admin page
349 491 *
350 492 * @since 2.0
351 493 *
352 - * @return boolean
494 + * @return bool
353 495 */
354 496 public static function is_admin() {
355 497 $is_admin = is_admin() && ! wp_doing_ajax();
356 498
@@ -365,17 +507,22 @@
365 507 * Check if value contains blank value or empty array
366 508 *
367 509 * @since 2.0
368 510 *
369 - * @param mixed $value - value to check
370 - * @param string
511 + * @param mixed $value Value to check.
512 + * @param string $empty
371 513 *
372 - * @return boolean
514 + * @return bool
373 515 */
374 516 public static function is_empty_value( $value, $empty = '' ) {
375 517 return ( is_array( $value ) && empty( $value ) ) || $value === $empty;
376 518 }
377 519
520 + /**
521 + * @param mixed $value
522 + * @param string $empty
523 + * @return bool
524 + */
378 525 public static function is_not_empty_value( $value, $empty = '' ) {
379 526 return ! self::is_empty_value( $value, $empty );
380 527 }
381 528
@@ -428,9 +575,10 @@
428 575 }
429 576
430 577 $key = self::get_server_value( $key );
431 578 foreach ( explode( ',', $key ) as $ip ) {
432 - $ip = trim( $ip ); // Just to be safe.
579 + // Just to be safe.
580 + $ip = trim( $ip );
433 581
434 582 if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
435 583 return sanitize_text_field( $ip );
436 584 }
@@ -521,15 +669,24 @@
521 669
522 670 return $value;
523 671 }
524 672
673 + /**
674 + * Get a value from $_POST data.
675 + *
676 + * @param string $param The key we are trying to access data from in $_POST.
677 + * @param mixed $default The default if nothing is being sent.
678 + * @param callable|string $sanitize Make sure to pass a sanitize method here. This function will NOT sanitize by default.
679 + * @param bool $serialized
680 + * @return mixed
681 + */
525 682 public static function get_post_param( $param, $default = '', $sanitize = '', $serialized = false ) {
526 683 return self::get_simple_request(
527 684 array(
528 - 'type' => 'post',
529 - 'param' => $param,
530 - 'default' => $default,
531 - 'sanitize' => $sanitize,
685 + 'type' => 'post',
686 + 'param' => $param,
687 + 'default' => $default,
688 + 'sanitize' => $sanitize,
532 689 'serialized' => $serialized,
533 690 )
534 691 );
535 692 }
@@ -540,9 +697,9 @@
540 697 * @param string $param
541 698 * @param string $sanitize
542 699 * @param string $default
543 700 *
544 - * @return string|array
701 + * @return array|string
545 702 */
546 703 public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
547 704 return self::get_simple_request(
548 705 array(
@@ -560,16 +717,16 @@
560 717 * @since 2.0.6
561 718 *
562 719 * @param array $args
563 720 *
564 - * @return string|array
721 + * @return array|string
565 722 */
566 723 public static function get_simple_request( $args ) {
567 724 $defaults = array(
568 - 'param' => '',
569 - 'default' => '',
570 - 'type' => 'get',
571 - 'sanitize' => 'sanitize_text_field',
725 + 'param' => '',
726 + 'default' => '',
727 + 'type' => 'get',
728 + 'sanitize' => 'sanitize_text_field',
572 729 'serialized' => false,
573 730 );
574 731 $args = wp_parse_args( $args, $defaults );
575 732
@@ -586,13 +743,12 @@
586 743 if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
587 744 self::unserialize_or_decode( $value );
588 745 }
589 746 }
590 - } else {
591 - if ( isset( $_REQUEST[ $args['param'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
747 + } elseif ( isset( $_REQUEST[ $args['param'] ] ) ) {
748 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
592 749 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
593 750 $value = wp_unslash( $_REQUEST[ $args['param'] ] );
594 - }
595 751 }
596 752
597 753 self::sanitize_value( $args['sanitize'], $value );
598 754
@@ -616,19 +772,35 @@
616 772
617 773 return $value;
618 774 }
619 775
776 + /**
777 + * Sanitize a value in-place.
778 + * If $value is an array, the sanitize function will get called for each item.
779 + *
780 + * @param callable $sanitize
781 + * @param mixed $value
782 + * @return void
783 + */
620 784 public static function sanitize_value( $sanitize, &$value ) {
621 - if ( ! empty( $sanitize ) ) {
622 - if ( is_array( $value ) ) {
623 - $temp_values = $value;
624 - foreach ( $temp_values as $k => $v ) {
625 - self::sanitize_value( $sanitize, $value[ $k ] );
626 - }
627 - } else {
628 - $value = call_user_func( $sanitize, $value );
785 + if ( ! $sanitize ) {
786 + return;
787 + }
788 +
789 + if ( is_object( $value ) ) {
790 + $value = '';
791 + return;
792 + }
793 +
794 + if ( is_array( $value ) ) {
795 + $temp_values = $value;
796 + foreach ( $temp_values as $k => $v ) {
797 + self::sanitize_value( $sanitize, $value[ $k ] );
629 798 }
799 + return;
630 800 }
801 +
802 + $value = call_user_func( $sanitize, $value );
631 803 }
632 804
633 805 public static function sanitize_request( $sanitize_method, &$values ) {
634 806 $temp_values = $values;
@@ -640,15 +812,52 @@
640 812 }
641 813
642 814 /**
643 815 * @since 4.0.04
816 + *
817 + * @param mixed $value
818 + * @return void
644 819 */
645 820 public static function sanitize_with_html( &$value ) {
646 - self::sanitize_value( 'wp_kses_post', $value );
821 + if ( current_user_can( 'frm_edit_entries' ) || current_user_can( 'administrator' ) ) {
822 + // Only strip unsafe HTML like scripts for a privileged user submitting a form.
823 + self::sanitize_value( 'wp_kses_post', $value );
824 + } else {
825 + self::sanitize_value( self::class . '::strip_most_html', $value );
826 + }
647 827 self::decode_specialchars( $value );
648 828 }
649 829
650 830 /**
831 + * Allow only a small set of very basic HTML for unprivileged users.
832 + *
833 + * @since 6.7.1
834 + *
835 + * @param string $value
836 + */
837 + public static function strip_most_html( $value ) {
838 + $allowed_html = array(
839 + 'b' => array(),
840 + 'br' => array(),
841 + 'strong' => array(),
842 + 'p' => array(),
843 + 'i' => array(),
844 + 'ul' => array(),
845 + 'ol' => array(),
846 + 'li' => array(),
847 + );
848 +
849 + /**
850 + * @since 6.7.1
851 + *
852 + * @param array $allowed_html
853 + */
854 + $allowed_html = apply_filters( 'frm_allowed_form_input_html', $allowed_html );
855 +
856 + return wp_kses( $value, $allowed_html );
857 + }
858 +
859 + /**
651 860 * Do wp_specialchars_decode to get back '&' that wp_kses_post might have turned to '&amp;'
652 861 * this MUST be done, else we'll be back to the '& entity' problem.
653 862 *
654 863 * @since 4.0.04
@@ -682,10 +891,12 @@
682 891 $translation = array(
683 892 '&quot;' => '"',
684 893 '&#034;' => '"',
685 894 '&#x22;' => '"',
686 - '&lt; ' => '< ', // The space preserves the HTML.
687 - '&#060; ' => '< ', // The space preserves the HTML.
895 + // The space preserves the HTML.
896 + '&lt; ' => '< ',
897 + // The space preserves the HTML.
898 + '&#060; ' => '< ',
688 899 '&gt;' => '>',
689 900 '&#062;' => '>',
690 901 '&amp;' => '&',
691 902 '&#038;' => '&',
@@ -712,10 +923,10 @@
712 923 * Sanitize the value, and allow some HTML
713 924 *
714 925 * @since 2.0
715 926 *
716 - * @param string $value
717 - * @param array|string $allowed 'all' for everything included as defaults
927 + * @param string $value
928 + * @param array|string $allowed 'all' for everything included as defaults.
718 929 *
719 930 * @return string
720 931 */
721 932 public static function kses( $value, $allowed = array() ) {
@@ -724,8 +935,21 @@
724 935 return wp_kses( $value, $allowed_html );
725 936 }
726 937
727 938 /**
939 + * Sanitizes and echoes a given value.
940 + *
941 + * @since 6.18
942 + *
943 + * @param string $value The value to sanitize and output.
944 + * @param array|string $allowed Allowed HTML tags and attributes.
945 + * @return void
946 + */
947 + public static function kses_echo( $value, $allowed = array() ) {
948 + echo self::kses( $value, $allowed ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
949 + }
950 +
951 + /**
728 952 * The regular kses function strips [button_action] from submit button HTML.
729 953 *
730 954 * @since 5.0.13
731 955 *
@@ -816,9 +1040,9 @@
816 1040 'id' => true,
817 1041 );
818 1042
819 1043 return array(
820 - 'a' => array(
1044 + 'a' => array(
821 1045 'class' => true,
822 1046 'href' => true,
823 1047 'id' => true,
824 1048 'rel' => true,
@@ -887,16 +1111,16 @@
887 1111 'cite' => true,
888 1112 'title' => true,
889 1113 ),
890 1114 'rect' => array(
891 - 'class' => true,
892 - 'fill' => true,
893 - 'height' => true,
894 - 'width' => true,
895 - 'x' => true,
896 - 'y' => true,
897 - 'rx' => true,
898 - 'stroke' => true,
1115 + 'class' => true,
1116 + 'fill' => true,
1117 + 'height' => true,
1118 + 'width' => true,
1119 + 'x' => true,
1120 + 'y' => true,
1121 + 'rx' => true,
1122 + 'stroke' => true,
899 1123 'stroke-opacity' => true,
900 1124 'stroke-width' => true,
901 1125 ),
902 1126 'section' => $allow_class,
@@ -931,9 +1155,9 @@
931 1155 'xlink:href' => true,
932 1156 ),
933 1157 'ul' => $allow_class,
934 1158 'label' => array(
935 - 'for' => true,
1159 + 'for' => true,
936 1160 'class' => true,
937 1161 'id' => true,
938 1162 ),
939 1163 'button' => array(
@@ -942,8 +1166,13 @@
942 1166 ),
943 1167 'legend' => array(
944 1168 'class' => true,
945 1169 ),
1170 + 'option' => array(
1171 + 'class' => true,
1172 + 'value' => true,
1173 + 'selected' => true,
1174 + ),
946 1175 );
947 1176 }
948 1177
949 1178 /**
@@ -951,9 +1180,9 @@
951 1180 *
952 1181 * @since 2.0
953 1182 */
954 1183 public static function remove_get_action() {
955 - if ( ! isset( $_GET ) ) {
1184 + if ( empty( $_GET ) ) {
956 1185 return;
957 1186 }
958 1187
959 1188 $action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
@@ -970,9 +1199,9 @@
970 1199 /**
971 1200 * Check the WP query for a parameter
972 1201 *
973 1202 * @since 2.0
974 - * @return string|array
1203 + * @return array|string
975 1204 */
976 1205 public static function get_query_var( $value, $param ) {
977 1206 if ( $value != '' ) {
978 1207 return $value;
@@ -989,10 +1218,12 @@
989 1218 /**
990 1219 * Try to show the SVG if possible. Otherwise, use the font icon.
991 1220 *
992 1221 * @since 4.0.02
1222 + *
993 1223 * @param string $class
994 1224 * @param array $atts
1225 + * @return string|null
995 1226 */
996 1227 public static function icon_by_class( $class, $atts = array() ) {
997 1228 $echo = ! isset( $atts['echo'] ) || $atts['echo'];
998 1229 if ( isset( $atts['echo'] ) ) {
@@ -1002,14 +1233,16 @@
1002 1233 $html_atts = self::array_to_html_params( $atts );
1003 1234
1004 1235 $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
1005 1236
1006 - // Replace icons that have been removed.
1237 + // Replace icons that have been removed or renamed.
1007 1238 $deprecated = array(
1008 - 'frm_clone_solid_icon' => 'frm_clone_icon',
1239 + 'frm_clone_solid_icon' => 'frm_clone_icon',
1240 + 'frm_keyalt_icon' => 'frm_key_icon',
1241 + 'frm_keyalt_solid_icon' => 'frm_key_solid_icon',
1009 1242 );
1010 1243 if ( isset( $deprecated[ $icon ] ) ) {
1011 - $icon = $deprecated[ $icon ];
1244 + $icon = $deprecated[ $icon ];
1012 1245 $class = str_replace( $icon, $deprecated[ $icon ], $class );
1013 1246 }
1014 1247
1015 1248 if ( $icon === $class ) {
@@ -1019,11 +1252,9 @@
1019 1252 if ( strpos( $icon, ' ' ) ) {
1020 1253 $icon = explode( ' ', $icon );
1021 1254 $icon = reset( $icon );
1022 1255 }
1023 - $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '>
1024 - <use xlink:href="#' . esc_attr( $icon ) . '" />
1025 - </svg>';
1256 + $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use xlink:href="#' . esc_attr( $icon ) . '" /></svg>';
1026 1257 }
1027 1258
1028 1259 if ( $echo ) {
1029 1260 echo self::kses_icon( $icon ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
@@ -1109,11 +1340,18 @@
1109 1340 /**
1110 1341 * Include svg images.
1111 1342 *
1112 1343 * @since 4.0.02
1344 + * @return void
1113 1345 */
1114 1346 public static function include_svg() {
1115 - include_once self::plugin_path() . '/images/icons.svg';
1347 + if ( self::$included_svg ) {
1348 + return;
1349 + }
1350 +
1351 + // Use readfile instead of include_once because of a default security rule in Snuffleupagus.
1352 + readfile( self::plugin_path() . '/images/icons.svg' );
1353 + self::$included_svg = true;
1116 1354 }
1117 1355
1118 1356 /**
1119 1357 * Convert an associative array to HTML values.
@@ -1125,9 +1363,9 @@
1125 1363 * @param bool $echo
1126 1364 * @return string|void
1127 1365 */
1128 1366 public static function array_to_html_params( $atts, $echo = false ) {
1129 - $callback = function() use ( $atts ) {
1367 + $callback = function () use ( $atts ) {
1130 1368 if ( $atts ) {
1131 1369 foreach ( $atts as $key => $value ) {
1132 1370 echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1133 1371 }
@@ -1142,9 +1380,9 @@
1142 1380 * @since 5.0.13
1143 1381 *
1144 1382 * @param Closure $echo_function
1145 1383 * @param bool $echo
1146 - * @return string|void
1384 + * @return string|null
1147 1385 */
1148 1386 public static function clip( $echo_function, $echo = false ) {
1149 1387 if ( ! $echo ) {
1150 1388 ob_start();
@@ -1162,12 +1400,15 @@
1162 1400 }
1163 1401
1164 1402 /**
1165 1403 * @since 3.0
1404 + *
1405 + * @param array $atts
1406 + * @return void
1166 1407 */
1167 1408 public static function get_admin_header( $atts ) {
1168 - $has_nav = ( isset( $atts['form'] ) && ! empty( $atts['form'] ) && ( ! isset( $atts['is_template'] ) || ! $atts['is_template'] ) );
1169 - if ( ! isset( $atts['close'] ) || empty( $atts['close'] ) ) {
1409 + $has_nav = ! empty( $atts['form'] ) && empty( $atts['is_template'] );
1410 + if ( empty( $atts['close'] ) ) {
1170 1411 $atts['close'] = admin_url( 'admin.php?page=formidable' );
1171 1412 }
1172 1413 if ( ! isset( $atts['import_link'] ) ) {
1173 1414 $atts['import_link'] = false;
@@ -1172,9 +1413,9 @@
1172 1413 if ( ! isset( $atts['import_link'] ) ) {
1173 1414 $atts['import_link'] = false;
1174 1415 }
1175 1416
1176 - include( self::plugin_path() . '/classes/views/shared/admin-header.php' );
1417 + include self::plugin_path() . '/classes/views/shared/admin-header.php';
1177 1418 }
1178 1419
1179 1420 /**
1180 1421 * @since 6.0
@@ -1203,9 +1444,9 @@
1203 1444 FrmInbox::maybe_show_banner();
1204 1445 return;
1205 1446 }
1206 1447
1207 - if ( self::maybe_show_license_warning() || FrmInbox::maybe_show_banner() || ! $should_show_lite_upgrade || self::pro_is_installed() ) {
1448 + if ( FrmSalesApi::maybe_show_banner() || self::maybe_show_license_warning() || FrmInbox::maybe_show_banner() || ! $should_show_lite_upgrade || self::pro_is_installed() ) {
1208 1449 // Print license warning or inbox banner and exit if either prints.
1209 1450 // And exit before printing the upgrade bar if it shouldn't be shown.
1210 1451 return;
1211 1452 }
@@ -1210,10 +1451,36 @@
1210 1451 return;
1211 1452 }
1212 1453 ?>
1213 1454 <div class="frm-upgrade-bar">
1214 - <span>You're using Formidable Forms Lite. To unlock more features consider</span>
1215 - <a href="<?php echo esc_url( self::admin_upgrade_link( 'top-bar' ) ); ?>" target="_blank" rel="noopener">upgrading to Pro</a>.
1455 + <div class="frm-upgrade-bar-inner">
1456 + <?php
1457 + $cta_text = FrmSalesApi::get_best_sale_value( 'lite_banner_cta_text' );
1458 + if ( ! $cta_text ) {
1459 + $cta_text = __( 'upgrading to PRO', 'formidable' );
1460 + }
1461 +
1462 + $upgrade_link = FrmSalesApi::get_best_sale_value( 'lite_banner_cta_link' );
1463 + $utm = array(
1464 + 'medium' => 'settings-license',
1465 + 'content' => 'lite-banner',
1466 + );
1467 +
1468 + if ( $upgrade_link ) {
1469 + $upgrade_link = self::maybe_add_missing_utm( $upgrade_link, $utm );
1470 + } else {
1471 + $upgrade_link = self::admin_upgrade_link( $utm );
1472 + }
1473 +
1474 + printf(
1475 + /* translators: %1$s: Start link HTML, %2$s: CTA text ("upgrading to PRO" by default), %3$s: End link HTML */
1476 + esc_html__( 'You\'re using Formidable Forms Lite. To unlock more features consider %1$s%2$s%3$s.', 'formidable' ),
1477 + '<a href="' . esc_url( $upgrade_link ) . '">',
1478 + esc_html( $cta_text ),
1479 + '</a>'
1480 + );
1481 + ?>
1482 + </div>
1216 1483 </div>
1217 1484 <?php
1218 1485 }
1219 1486
@@ -1230,8 +1497,10 @@
1230 1497 * Render a button for a new item (Form, Application, etc).
1231 1498 *
1232 1499 * @since 3.0
1233 1500 * @param array $atts {
1501 + * Details about the button.
1502 + *
1234 1503 * @type array $link_hook Custom link hook, calls do_action and exits early.
1235 1504 * @type string $new_link Href value, default #.
1236 1505 * @type string $class Custom class names, space separated.
1237 1506 * @type string $button_text Button text. Default "Add New".
@@ -1243,9 +1512,9 @@
1243 1512 do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
1244 1513 return;
1245 1514 }
1246 1515
1247 - if ( empty( $atts['new_link'] ) && empty( $atts['trigger_new_form_modal'] ) && empty( $atts['class'] ) ) {
1516 + if ( empty( $atts['new_link'] ) && empty( $atts['create_form'] ) && empty( $atts['class'] ) ) {
1248 1517 // Do not render a button if none of these attributes are set.
1249 1518 return;
1250 1519 }
1251 1520
@@ -1251,12 +1520,8 @@
1251 1520
1252 1521 $href = ! empty( $atts['new_link'] ) ? esc_url( $atts['new_link'] ) : '#';
1253 1522 $class = 'button button-primary frm-button-primary';
1254 1523
1255 - if ( ! empty( $atts['trigger_new_form_modal'] ) ) {
1256 - $class .= ' frm-trigger-new-form-modal';
1257 - }
1258 -
1259 1524 if ( ! empty( $atts['class'] ) ) {
1260 1525 $class .= ' ' . $atts['class'];
1261 1526 }
1262 1527
@@ -1273,10 +1538,11 @@
1273 1538 'placeholder' => '',
1274 1539 'tosearch' => '',
1275 1540 'text' => __( 'Search', 'formidable' ),
1276 1541 'input_id' => '',
1542 + 'value' => false,
1277 1543 );
1278 - $atts = array_merge( $defaults, $atts );
1544 + $atts = array_merge( $defaults, $atts );
1279 1545
1280 1546 if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
1281 1547 $atts['tosearch'] = 'frm-card';
1282 1548 }
@@ -1287,8 +1553,27 @@
1287 1553 }
1288 1554
1289 1555 $input_id = $atts['input_id'] . '-search-input';
1290 1556
1557 + $input_atts = array(
1558 + 'type' => 'search',
1559 + 'id' => $input_id,
1560 + 'name' => 's',
1561 + 'placeholder' => $atts['placeholder'],
1562 + 'class' => $class,
1563 + 'data-tosearch' => $atts['tosearch'],
1564 + );
1565 +
1566 + if ( is_string( $atts['value'] ) ) {
1567 + $input_atts['value'] = $atts['value'];
1568 + } elseif ( isset( $_REQUEST['s'] ) ) {
1569 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1570 + $input_atts['value'] = wp_unslash( $_REQUEST['s'] );
1571 + }
1572 +
1573 + if ( ! empty( $atts['tosearch'] ) ) {
1574 + $input_atts['autocomplete'] = 'off';
1575 + }
1291 1576 ?>
1292 1577 <p class="frm-search">
1293 1578 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1294 1579 <?php echo esc_html( $atts['text'] ); ?>:
@@ -1293,15 +1578,9 @@
1293 1578 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1294 1579 <?php echo esc_html( $atts['text'] ); ?>:
1295 1580 </label>
1296 1581 <span class="frmfont frm_search_icon"></span>
1297 - <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
1298 - value="<?php _admin_search_query(); ?>" placeholder="<?php echo esc_attr( $atts['placeholder'] ); ?>"
1299 - class="<?php echo esc_attr( $class ); ?>" data-tosearch="<?php echo esc_attr( $atts['tosearch'] ); ?>"
1300 - <?php if ( ! empty( $atts['tosearch'] ) ) { ?>
1301 - autocomplete="off"
1302 - <?php } ?>
1303 - />
1582 + <input <?php self::array_to_html_params( $input_atts, true ); ?> />
1304 1583 <?php
1305 1584 if ( empty( $atts['tosearch'] ) ) {
1306 1585 submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
1307 1586 }
@@ -1311,8 +1590,9 @@
1311 1590 }
1312 1591
1313 1592 /**
1314 1593 * @param string $type
1594 + * @return void
1315 1595 */
1316 1596 public static function trigger_hook_load( $type, $object = null ) {
1317 1597 // Only load the form hooks once.
1318 1598 $hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
@@ -1356,9 +1636,9 @@
1356 1636 'new_file_path' => self::plugin_path() . '/js',
1357 1637 )
1358 1638 );
1359 1639 $new_file = new FrmCreateFile( $file_atts );
1360 - $files = array(
1640 + $files = array(
1361 1641 FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.min.js',
1362 1642 );
1363 1643
1364 1644 /**
@@ -1375,14 +1655,14 @@
1375 1655 * True when value is 1, true, 'true', 'yes'
1376 1656 *
1377 1657 * @since 1.07.10
1378 1658 *
1379 - * @param string $value The value to compare
1659 + * @param string $value The value to compare.
1380 1660 *
1381 - * @return boolean True or False
1661 + * @return bool
1382 1662 */
1383 1663 public static function is_true( $value ) {
1384 - return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1664 + return true === $value || 1 == $value || 'true' === $value || 'yes' === $value;
1385 1665 }
1386 1666
1387 1667 /**
1388 1668 * Gets all post from a specific post type.
@@ -1440,9 +1720,9 @@
1440 1720 $args = self::preformat_selection_args( $args );
1441 1721
1442 1722 $pages_count = wp_count_posts( $args['post_type'] );
1443 1723
1444 - if ( $pages_count->publish <= 50 ) {
1724 + if ( ! isset( $pages_count->publish ) || $pages_count->publish <= 50 ) {
1445 1725 self::wp_pages_dropdown( $args );
1446 1726 return;
1447 1727 }
1448 1728
@@ -1448,9 +1728,9 @@
1448 1728
1449 1729 wp_enqueue_script( 'jquery-ui-autocomplete' );
1450 1730
1451 1731 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1452 - $title = '';
1732 + $title = '';
1453 1733
1454 1734 if ( $selected ) {
1455 1735 $title = get_the_title( $selected );
1456 1736 }
@@ -1466,18 +1746,112 @@
1466 1746 <?php
1467 1747 }
1468 1748
1469 1749 /**
1470 - * @param array $args
1471 - * @param string $page_id Deprecated.
1472 - * @param boolean $truncate Deprecated.
1750 + * Maybe show an HTML select or autocomplete input based on the number of options.
1751 + *
1752 + * @since 6.21
1753 + *
1754 + * @param array $args Args. See the method for details.
1473 1755 */
1756 + public static function maybe_autocomplete_options( $args ) {
1757 + $defaults = array(
1758 + 'truncate' => false,
1759 + 'placeholder' => ' ',
1760 + 'name' => '',
1761 + 'id' => '',
1762 + 'selected' => '',
1763 + 'source' => array(),
1764 + 'dropdown_limit' => 50,
1765 + 'autocomplete_placeholder' => __( 'Select an option', 'formidable' ),
1766 + 'value_key' => 'value',
1767 + 'label_key' => 'label',
1768 + );
1769 +
1770 + $args = wp_parse_args( $args, $defaults );
1771 +
1772 + $html_attrs = array();
1773 + if ( ! empty( $args['name'] ) ) {
1774 + $html_attrs['name'] = $args['name'];
1775 + }
1776 +
1777 + if ( ! empty( $args['id'] ) ) {
1778 + $html_attrs['id'] = $args['id'];
1779 + }
1780 +
1781 + if ( count( $args['source'] ) <= $args['dropdown_limit'] ) {
1782 + ?>
1783 + <select <?php self::array_to_html_params( $html_attrs, true ); ?>>
1784 + <option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
1785 + <?php
1786 + foreach ( $args['source'] as $key => $source ) :
1787 + $value_label = self::get_dropdown_value_and_label_from_option( $source, $key, $args );
1788 + if ( ! empty( $args['truncate'] ) ) {
1789 + $value_label['label'] = self::truncate( $value_label['label'], $args['truncate'] );
1790 + }
1791 + ?>
1792 + <option value="<?php echo esc_attr( $value_label['value'] ); ?>" <?php selected( $value_label['value'], $args['selected'] ); ?>><?php echo esc_html( $value_label['label'] ); ?></option>
1793 + <?php endforeach; ?>
1794 + </select>
1795 + <?php
1796 + } else {
1797 + $options = array();
1798 + $autocomplete_value = '';
1799 + foreach ( $args['source'] as $key => $source ) {
1800 + $value_label = self::get_dropdown_value_and_label_from_option( $source, $key, $args );
1801 +
1802 + if ( $value_label['value'] === $args['selected'] ) {
1803 + $autocomplete_value = $value_label['label'];
1804 + }
1805 +
1806 + $options[] = $value_label;
1807 + }
1808 +
1809 + $html_attrs['type'] = 'hidden';
1810 + $html_attrs['class'] = 'frm_autocomplete_value_input';
1811 + $html_attrs['value'] = $args['selected'];
1812 + ?>
1813 + <input type="text" class="frm-custom-search"
1814 + data-source="<?php echo esc_attr( wp_json_encode( $options ) ); ?>"
1815 + placeholder="<?php echo esc_attr( $args['autocomplete_placeholder'] ); ?>"
1816 + value="<?php echo esc_attr( $autocomplete_value ); ?>" />
1817 + <input <?php self::array_to_html_params( $html_attrs, true ); ?> />
1818 + <?php
1819 + }//end if
1820 + }
1821 +
1822 + /**
1823 + * Gets dropdown value and label from autodropdown option.
1824 + *
1825 + * @since 6.21
1826 + *
1827 + * @param array|string $option Autocomplete option.
1828 + * @param string $key Array key of the option.
1829 + * @param array $args See {@see FrmAppHelper::maybe_autocomplete_options()}.
1830 + * @return array
1831 + */
1832 + private static function get_dropdown_value_and_label_from_option( $option, $key, $args ) {
1833 + if ( is_array( $option ) ) {
1834 + $value = isset( $option[ $args['value_key'] ] ) ? $option[ $args['value_key'] ] : '';
1835 + $label = isset( $option[ $args['label_key'] ] ) ? $option[ $args['label_key'] ] : '';
1836 + } else {
1837 + $value = $key;
1838 + $label = $option;
1839 + }
1840 +
1841 + return compact( 'value', 'label' );
1842 + }
1843 +
1844 + /**
1845 + * @param array $args
1846 + * @param string $page_id Deprecated.
1847 + * @param bool $truncate Deprecated.
1848 + */
1474 1849 public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1475 1850 self::prep_page_dropdown_params( $page_id, $truncate, $args );
1476 1851
1477 1852 $pages = self::get_post_ids_and_titles( $args['post_type'] );
1478 1853 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1479 -
1480 1854 ?>
1481 1855 <select name="<?php echo esc_attr( $args['field_name'] ); ?>" id="<?php echo esc_attr( $args['field_name'] ); ?>" class="frm-pages-dropdown">
1482 1856 <option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
1483 1857 <?php foreach ( $pages as $page ) { ?>
@@ -1514,13 +1888,13 @@
1514 1888 * @since 4.10.01 Added `post_type` and `autocomplete_placeholder` to the arguments array.
1515 1889 */
1516 1890 private static function preformat_selection_args( $args ) {
1517 1891 $defaults = array(
1518 - 'truncate' => false,
1519 - 'placeholder' => ' ',
1520 - 'field_name' => '',
1521 - 'page_id' => '',
1522 - 'post_type' => 'page',
1892 + 'truncate' => false,
1893 + 'placeholder' => ' ',
1894 + 'field_name' => '',
1895 + 'page_id' => '',
1896 + 'post_type' => 'page',
1523 1897 'autocomplete_placeholder' => __( 'Select a Page', 'formidable' ),
1524 1898 );
1525 1899
1526 1900 return array_merge( $defaults, $args );
@@ -1591,25 +1965,16 @@
1591 1965 return self::is_admin_page( 'formidable-views-editor' );
1592 1966 }
1593 1967
1594 1968 /**
1595 - * @since 4.0
1596 - * @deprecated 5.5.3
1969 + * @param string $field_name
1970 + * @param array|string $capability
1971 + * @param string $multiple 'single' and 'multiple'.
1597 1972 */
1598 - public static function maybe_full_screen_link( $link ) {
1599 - _deprecated_function( __METHOD__, '5.5.3' );
1600 - return $link;
1601 - }
1602 -
1603 - /**
1604 - * @param string $field_name
1605 - * @param string|array $capability
1606 - * @param string $multiple 'single' and 'multiple'
1607 - */
1608 1973 public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1609 1974 ?>
1610 1975 <select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1611 - <?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1976 + <?php echo 'multiple' === $multiple ? 'multiple="multiple"' : ''; ?>
1612 1977 class="frm_multiselect">
1613 1978 <?php self::roles_options( $capability ); ?>
1614 1979 </select>
1615 1980 <?php
@@ -1617,9 +1982,9 @@
1617 1982
1618 1983 /**
1619 1984 * @since 4.07
1620 1985 * @param array|string $selected
1621 - * @param string $current
1986 + * @param string $current
1622 1987 */
1623 1988 private static function selected( $selected, $current ) {
1624 1989 if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1625 1990 FrmProAppHelper::selected( $selected, $current );
@@ -1628,9 +1993,9 @@
1628 1993 }
1629 1994 }
1630 1995
1631 1996 /**
1632 - * @param string|array $capability
1997 + * @param array|string $capability
1633 1998 */
1634 1999 public static function roles_options( $capability ) {
1635 2000 global $frm_vars;
1636 2001 if ( isset( $frm_vars['editable_roles'] ) ) {
@@ -1642,9 +2007,9 @@
1642 2007
1643 2008 foreach ( $editable_roles as $role => $details ) {
1644 2009 $name = translate_user_role( $details['name'] );
1645 2010 ?>
1646 - <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_attr( $name ); ?> </option>
2011 + <option value="<?php echo esc_attr( $role ); ?>" <?php self::selected( $capability, $role ); ?>><?php echo esc_html( $name ); ?> </option>
1647 2012 <?php
1648 2013 unset( $role, $details );
1649 2014 }
1650 2015 }
@@ -1665,9 +2030,8 @@
1665 2030 $pro_cap = array(
1666 2031 'frm_create_entries' => __( 'Add Entries from Admin Area', 'formidable' ),
1667 2032 'frm_edit_entries' => __( 'Edit Entries from Admin Area', 'formidable' ),
1668 2033 'frm_view_reports' => __( 'View Reports', 'formidable' ),
1669 - 'frm_edit_displays' => __( 'Add/Edit Views', 'formidable' ),
1670 2034 );
1671 2035 /**
1672 2036 * @since 5.3.1
1673 2037 *
@@ -1674,8 +2038,14 @@
1674 2038 * @param array<string,string> $pro_cap
1675 2039 */
1676 2040 $pro_cap = apply_filters( 'frm_pro_capabilities', $pro_cap );
1677 2041
2042 + if ( ! array_key_exists( 'frm_edit_displays', $pro_cap ) && is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed() ) {
2043 + // For backward compatibility, add the Add/Edit Views permission if Pro is not up to date.
2044 + // This was added in 6.5.4. Remove this in the future.
2045 + $pro_cap['frm_edit_displays'] = __( 'Add/Edit Views', 'formidable' );
2046 + }
2047 +
1678 2048 if ( 'pro_only' === $type ) {
1679 2049 return $pro_cap;
1680 2050 }
1681 2051
@@ -1690,9 +2060,9 @@
1690 2060 * @return array<string,string>
1691 2061 */
1692 2062 private static function get_lite_capabilities() {
1693 2063 return array(
1694 - 'frm_view_forms' => __( 'View Forms', 'formidable' ),
2064 + 'frm_view_forms' => __( 'View Forms List', 'formidable' ),
1695 2065 'frm_edit_forms' => __( 'Add and Edit Forms', 'formidable' ),
1696 2066 'frm_delete_forms' => __( 'Delete Forms', 'formidable' ),
1697 2067 'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1698 2068 'frm_view_entries' => __( 'View Entries from Admin Area', 'formidable' ),
@@ -1733,9 +2103,9 @@
1733 2103 return current_user_can( $role );
1734 2104 }
1735 2105
1736 2106 /**
1737 - * @param string|array $needed_role
2107 + * @param array|string $needed_role
1738 2108 * @return bool
1739 2109 */
1740 2110 public static function user_has_permission( $needed_role ) {
1741 2111 if ( is_array( $needed_role ) ) {
@@ -1791,8 +2161,11 @@
1791 2161 /**
1792 2162 * Make sure admins have permission to see the menu items
1793 2163 *
1794 2164 * @since 2.0.6
2165 + *
2166 + * @param string $cap
2167 + * @return void
1795 2168 */
1796 2169 public static function force_capability( $cap = 'frm_change_settings' ) {
1797 2170 if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1798 2171 $role = get_role( 'administrator' );
@@ -1803,9 +2176,9 @@
1803 2176 }
1804 2177 }
1805 2178
1806 2179 /**
1807 - * Check if the user has permision for action.
2180 + * Check if the user has permission for action.
1808 2181 * Return permission message and stop the action if no permission
1809 2182 *
1810 2183 * @since 2.0
1811 2184 *
@@ -1841,9 +2214,9 @@
1841 2214 if ( empty( $nonce_name ) ) {
1842 2215 return $error;
1843 2216 }
1844 2217
1845 - $nonce_value = ( $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
2218 + $nonce_value = $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
1846 2219 if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1847 2220 $frm_settings = self::get_settings();
1848 2221 $error = $frm_settings->admin_permission;
1849 2222 }
@@ -1857,12 +2230,13 @@
1857 2230 }
1858 2231 }
1859 2232
1860 2233 public static function check_selected( $values, $current ) {
1861 - $values = self::recursive_function_map( $values, 'trim' );
1862 - $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1863 - $current = htmlspecialchars_decode( trim( $current ) );
2234 + $values = self::recursive_function_map( $values, 'trim' );
2235 + $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1864 2236
2237 + $current = is_null( $current ) ? '' : htmlspecialchars_decode( trim( $current ) );
2238 +
1865 2239 return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1866 2240 }
1867 2241
1868 2242 public static function recursive_function_map( $value, $function ) {
@@ -1882,8 +2256,9 @@
1882 2256 }
1883 2257 }
1884 2258 }
1885 2259 } else {
2260 + $value = self::maybe_update_value_if_null( $value, $function );
1886 2261 $value = call_user_func( $function, $value );
1887 2262 }
1888 2263
1889 2264 return $value;
@@ -1888,8 +2263,24 @@
1888 2263
1889 2264 return $value;
1890 2265 }
1891 2266
2267 + /**
2268 + * Updates value to empty string if it is null and being passed to a string function.
2269 + *
2270 + * @since 6.8.4
2271 + * @param mixed $value
2272 + * @param string $function
2273 + * @return mixed
2274 + */
2275 + private static function maybe_update_value_if_null( $value, $function ) {
2276 + if ( null === $value && in_array( $function, array( 'trim', 'strlen' ), true ) ) {
2277 + $value = '';
2278 + }
2279 +
2280 + return $value;
2281 + }
2282 +
1892 2283 public static function is_assoc( $array ) {
1893 2284 return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1894 2285 }
1895 2286
@@ -1900,14 +2291,12 @@
1900 2291 $return = array();
1901 2292 foreach ( $array as $key => $value ) {
1902 2293 if ( is_array( $value ) ) {
1903 2294 $return = array_merge( $return, self::array_flatten( $value, $keys ) );
2295 + } elseif ( $keys === 'keep' ) {
2296 + $return[ $key ] = $value;
1904 2297 } else {
1905 - if ( $keys === 'keep' ) {
1906 - $return[ $key ] = $value;
1907 - } else {
1908 - $return[] = $value;
1909 - }
2298 + $return[] = $value;
1910 2299 }
1911 2300 }
1912 2301
1913 2302 return $return;
@@ -1912,8 +2301,27 @@
1912 2301
1913 2302 return $return;
1914 2303 }
1915 2304
2305 + /**
2306 + * Flatten an array before imploding it to avoid Array to string conversion warnings.
2307 + *
2308 + * @since 6.16.1
2309 + *
2310 + * @param string $sep
2311 + * @param array $array
2312 + * @return string
2313 + */
2314 + public static function safe_implode( $sep, $array ) {
2315 + $array = self::array_flatten( $array );
2316 + return implode( $sep, $array );
2317 + }
2318 +
2319 + /**
2320 + * @param string $text
2321 + * @param bool $is_rich_text
2322 + * @return string
2323 + */
1916 2324 public static function esc_textarea( $text, $is_rich_text = false ) {
1917 2325 $safe_text = str_replace( '&quot;', '"', $text );
1918 2326 if ( ! $is_rich_text ) {
1919 2327 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
@@ -1919,9 +2327,13 @@
1919 2327 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1920 2328 }
1921 2329 $safe_text = str_replace( '&amp; ', '& ', $safe_text );
1922 2330
1923 - return apply_filters( 'esc_textarea', $safe_text, $text );
2331 + /**
2332 + * @param string $safe_text
2333 + * @param string $text
2334 + */
2335 + return (string) apply_filters( 'esc_textarea', $safe_text, $text );
1924 2336 }
1925 2337
1926 2338 /**
1927 2339 * Add auto paragraphs to text areas
@@ -1928,9 +2340,9 @@
1928 2340 *
1929 2341 * @since 2.0
1930 2342 */
1931 2343 public static function use_wpautop( $content ) {
1932 - if ( apply_filters( 'frm_use_wpautop', true ) && ! is_array( $content ) ) {
2344 + if ( apply_filters( 'frm_use_wpautop', true ) && is_string( $content ) ) {
1933 2345 $content = wpautop( str_replace( '<br>', '<br />', $content ) );
1934 2346 }
1935 2347
1936 2348 return $content;
@@ -1972,12 +2384,12 @@
1972 2384 * @since 5.0.13 added $echo param.
1973 2385 *
1974 2386 * @param string $url
1975 2387 * @param bool $echo
1976 - * @return string|void
2388 + * @return string|null
1977 2389 */
1978 2390 public static function js_redirect( $url, $echo = false ) {
1979 - $callback = function() use ( $url ) {
2391 + $callback = function () use ( $url ) {
1980 2392 echo '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1981 2393 };
1982 2394 return self::clip( $callback, $echo );
1983 2395 }
@@ -2005,8 +2417,13 @@
2005 2417
2006 2418 return $user_id;
2007 2419 }
2008 2420
2421 + /**
2422 + * @param string $filename
2423 + * @param array $atts
2424 + * @return false|string
2425 + */
2009 2426 public static function get_file_contents( $filename, $atts = array() ) {
2010 2427 if ( ! is_file( $filename ) ) {
2011 2428 return false;
2012 2429 }
@@ -2012,9 +2429,9 @@
2012 2429 }
2013 2430
2014 2431 extract( $atts ); // phpcs:ignore WordPress.PHP.DontExtract
2015 2432 ob_start();
2016 - include( $filename );
2433 + include $filename;
2017 2434 $contents = ob_get_contents();
2018 2435 ob_end_clean();
2019 2436
2020 2437 return $contents;
@@ -2069,9 +2486,9 @@
2069 2486 ++$suffix;
2070 2487 } while ( in_array( $key_check, $similar_keys, true ) );
2071 2488
2072 2489 $key = $key_check;
2073 - }
2490 + }//end if
2074 2491
2075 2492 return $key;
2076 2493 }
2077 2494
@@ -2110,14 +2527,18 @@
2110 2527 return $key;
2111 2528 }
2112 2529
2113 2530 /**
2531 + * @since 6.21 This is changed from `private` to `public`.
2532 + *
2114 2533 * @param int $num_chars
2115 2534 * @return string
2116 2535 */
2117 - private static function generate_new_key( $num_chars ) {
2536 + public static function generate_new_key( $num_chars ) {
2118 2537 $max_slug_value = pow( 36, $num_chars );
2119 - $min_slug_value = 37; // we want to have at least 2 characters in the slug
2538 +
2539 + // We want to have at least 2 characters in the slug.
2540 + $min_slug_value = 37;
2120 2541 return base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
2121 2542 }
2122 2543
2123 2544 /**
@@ -2146,11 +2567,16 @@
2146 2567
2147 2568 /**
2148 2569 * Editing a Form or Entry
2149 2570 *
2150 - * @param string $table
2571 + * @param object $record
2572 + * @param string $table
2573 + * @param array|string $fields
2574 + * @param bool $default
2575 + * @param array $post_values
2576 + * @param array $args
2151 2577 *
2152 - * @return bool|array
2578 + * @return array|bool
2153 2579 */
2154 2580 public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
2155 2581 if ( ! $record ) {
2156 2582 return false;
@@ -2203,13 +2629,12 @@
2203 2629 $post_values = $args['post_values'];
2204 2630
2205 2631 if ( $args['default'] ) {
2206 2632 $meta_value = $field->default_value;
2207 - } else {
2208 - if ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2209 - if ( ! isset( $field->field_options['custom_field'] ) ) {
2210 - $field->field_options['custom_field'] = '';
2211 - }
2633 + } elseif ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2634 + if ( ! isset( $field->field_options['custom_field'] ) ) {
2635 + $field->field_options['custom_field'] = '';
2636 + }
2212 2637 $meta_value = FrmProEntryMetaHelper::get_post_value(
2213 2638 $record->post_id,
2214 2639 $field->field_options['post_field'],
2215 2640 $field->field_options['custom_field'],
@@ -2219,12 +2644,11 @@
2219 2644 'form_id' => $field->form_id,
2220 2645 'field' => $field,
2221 2646 )
2222 2647 );
2223 - } else {
2224 - $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2225 - }
2226 - }
2648 + } else {
2649 + $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2650 + }//end if
2227 2651
2228 2652 $field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
2229 2653 if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
2230 2654 $new_value = $post_values['item_meta'][ $field->id ];
@@ -2272,12 +2696,15 @@
2272 2696 );
2273 2697 }
2274 2698
2275 2699 /**
2700 + * @param object $record
2276 2701 * @param string $table
2702 + * @param array $post_values
2703 + * @param array $values
2277 2704 */
2278 2705 private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
2279 - if ( $table == 'entries' ) {
2706 + if ( $table === 'entries' ) {
2280 2707 $form = $record->form_id;
2281 2708 FrmForm::maybe_get_form( $form );
2282 2709 } else {
2283 2710 $form = $record;
@@ -2313,9 +2740,9 @@
2313 2740 $form_defaults = FrmFormsHelper::get_default_opts();
2314 2741
2315 2742 foreach ( $form_defaults as $opt => $default ) {
2316 2743 if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
2317 - $values[ $opt ] = ( $post_values && isset( $post_values['options'][ $opt ] ) ) ? $post_values['options'][ $opt ] : $default;
2744 + $values[ $opt ] = $post_values && isset( $post_values['options'][ $opt ] ) ? $post_values['options'][ $opt ] : $default;
2318 2745 }
2319 2746
2320 2747 unset( $opt, $default );
2321 2748 }
@@ -2336,9 +2763,9 @@
2336 2763 * @since 2.2.10
2337 2764 *
2338 2765 * @param array $post_values
2339 2766 *
2340 - * @return boolean|int
2767 + * @return bool|int
2341 2768 */
2342 2769 public static function custom_style_value( $post_values ) {
2343 2770 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2344 2771 $custom_style = absint( $post_values['options']['custom_style'] );
@@ -2343,29 +2770,37 @@
2343 2770 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2344 2771 $custom_style = absint( $post_values['options']['custom_style'] );
2345 2772 } else {
2346 2773 $frm_settings = self::get_settings();
2347 - $custom_style = ( $frm_settings->load_style != 'none' );
2774 + $custom_style = ( $frm_settings->load_style !== 'none' );
2348 2775 }
2349 2776
2350 2777 return $custom_style;
2351 2778 }
2352 2779
2353 - public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
2354 - if ( is_array( $str ) ) {
2780 + /**
2781 + * @param mixed $original_string
2782 + * @param int|string $length
2783 + * @param int $minword
2784 + * @param string $continue
2785 + * @return string
2786 + */
2787 + public static function truncate( $original_string, $length, $minword = 3, $continue = '...' ) {
2788 + if ( ! is_string( $original_string ) && ! is_int( $original_string ) ) {
2355 2789 return '';
2356 2790 }
2357 2791
2358 2792 $length = (int) $length;
2359 - $str = wp_strip_all_tags( $str );
2793 + $str = wp_strip_all_tags( (string) $original_string );
2360 2794 $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
2361 2795
2362 2796 if ( $length == 0 ) {
2363 2797 return '';
2364 - } elseif ( $length <= 10 ) {
2798 + }
2799 +
2800 + if ( $length <= 10 ) {
2365 2801 $sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
2366 -
2367 - return $sub . ( ( $length < $original_len ) ? $continue : '' );
2802 + return $sub . ( $length < $original_len ? $continue : '' );
2368 2803 }
2369 2804
2370 2805 $sub = '';
2371 2806 $len = 0;
@@ -2371,10 +2806,14 @@
2371 2806 $len = 0;
2372 2807
2373 2808 $words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
2374 2809
2810 + if ( ! is_array( $words ) ) {
2811 + return $original_string;
2812 + }
2813 +
2375 2814 foreach ( $words as $word ) {
2376 - $part = ( ( $sub != '' ) ? ' ' : '' ) . $word;
2815 + $part = ( $sub != '' ? ' ' : '' ) . $word;
2377 2816 $total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
2378 2817 if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
2379 2818 break;
2380 2819 }
@@ -2388,11 +2827,37 @@
2388 2827
2389 2828 unset( $total_len, $word );
2390 2829 }
2391 2830
2392 - return $sub . ( ( $len < $original_len ) ? $continue : '' );
2831 + $sub = self::maybe_force_truncate_on_string_with_no_spaces( $sub, $length );
2832 +
2833 + return $sub . ( $len < $original_len ? $continue : '' );
2393 2834 }
2394 2835
2836 + /**
2837 + * If the string is still too long because there may not have been any spaces, force truncate.
2838 + *
2839 + * @since 6.5.4
2840 + *
2841 + * @param string $sub Current substring.
2842 + * @param int $length The length limit.
2843 + * @return string
2844 + */
2845 + private static function maybe_force_truncate_on_string_with_no_spaces( $sub, $length ) {
2846 + if ( strlen( $sub ) < $length + 50 ) {
2847 + // If the string isn't way over the limit, leave it.
2848 + return $sub;
2849 + }
2850 +
2851 + $first_space = strpos( $sub, ' ', $length );
2852 + if ( false !== $first_space ) {
2853 + // Ignore anything with spaces.
2854 + return $sub;
2855 + }
2856 +
2857 + return substr( $sub, 0, $length + 10 );
2858 + }
2859 +
2395 2860 public static function mb_function( $function_names, $args ) {
2396 2861 $mb_function_name = $function_names[0];
2397 2862 $function_name = $function_names[1];
2398 2863 if ( function_exists( $mb_function_name ) ) {
@@ -2425,8 +2890,13 @@
2425 2890
2426 2891 return $formatted;
2427 2892 }
2428 2893
2894 + /**
2895 + * @param string $time_format
2896 + * @param string $date
2897 + * @return string
2898 + */
2429 2899 private static function add_time_to_date( $time_format, $date ) {
2430 2900 if ( empty( $time_format ) ) {
2431 2901 $time_format = get_option( 'time_format' );
2432 2902 }
@@ -2449,12 +2919,12 @@
2449 2919 return date_i18n( $date_format, strtotime( $date ) );
2450 2920 }
2451 2921
2452 2922 /**
2453 - * Gets the time ago in words
2923 + * Gets the time ago in words.
2454 2924 *
2455 - * @param int $from in seconds
2456 - * @param int|string $to in seconds
2925 + * @param int $from In seconds.
2926 + * @param int|string $to In seconds.
2457 2927 *
2458 2928 * @return string $time_ago
2459 2929 */
2460 2930 public static function human_time_diff( $from, $to = '', $levels = 1 ) {
@@ -2469,9 +2939,9 @@
2469 2939 $diff_object = $now->diff( $ago );
2470 2940 $diff = get_object_vars( $diff_object );
2471 2941
2472 2942 // Add week amount and update day amount
2473 - $diff['w'] = floor( $diff['d'] / 7 );
2943 + $diff['w'] = floor( $diff['d'] / 7 );
2474 2944 $diff['d'] -= $diff['w'] * 7;
2475 2945
2476 2946 $time_strings = self::get_time_strings();
2477 2947
@@ -2478,9 +2948,9 @@
2478 2948 if ( ! is_numeric( $levels ) ) {
2479 2949 // Show time in specified unit.
2480 2950 $levels = self::get_unit( $levels );
2481 2951 if ( isset( $time_strings[ $levels ] ) ) {
2482 - $diff = array(
2952 + $diff = array(
2483 2953 $levels => self::time_format( $levels, $diff ),
2484 2954 );
2485 2955 $time_strings = array(
2486 2956 $levels => $time_strings[ $levels ],
@@ -2569,9 +3039,9 @@
2569 3039 }
2570 3040
2571 3041 /**
2572 3042 * Get the translatable time strings. The untranslated version is a failsafe
2573 - * in case langauges are changing for the unit set in the shortcode.
3043 + * in case languages are changing for the unit set in the shortcode.
2574 3044 *
2575 3045 * @since 2.0.20
2576 3046 * @return array
2577 3047 */
@@ -2617,23 +3087,28 @@
2617 3087
2618 3088 // Pagination Methods.
2619 3089
2620 3090 /**
2621 - * @param integer $current_p
3091 + * @param int $r_count
3092 + * @param int $current_p
3093 + * @param int $p_size
3094 + * @return int
2622 3095 */
2623 3096 public static function get_last_record_num( $r_count, $current_p, $p_size ) {
2624 - return ( ( $r_count < ( $current_p * $p_size ) ) ? $r_count : ( $current_p * $p_size ) );
3097 + return ( $r_count < $current_p * $p_size ? $r_count : $current_p * $p_size );
2625 3098 }
2626 3099
2627 3100 /**
2628 - * @param integer $current_p
3101 + * @param int $r_count
3102 + * @param int $current_p
3103 + * @param int $p_size
3104 + * @return int
2629 3105 */
2630 3106 public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2631 3107 if ( $current_p == 1 ) {
2632 3108 return 1;
2633 - } else {
2634 - return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2635 3109 }
3110 + return self::get_last_record_num( $r_count, $current_p - 1, $p_size ) + 1;
2636 3111 }
2637 3112
2638 3113 /**
2639 3114 * @return array
@@ -2656,9 +3131,9 @@
2656 3131 if ( ! isset( $l3 ) ) {
2657 3132 $l3 = $name;
2658 3133 }
2659 3134
2660 - $this_val = ( $p == $last ) ? $jv['value'] : array();
3135 + $this_val = $p == $last ? $jv['value'] : array();
2661 3136
2662 3137 switch ( $p ) {
2663 3138 case 0:
2664 3139 $l1 = $name;
@@ -2680,12 +3155,12 @@
2680 3155 self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2681 3156 }
2682 3157
2683 3158 unset( $this_val, $n );
2684 - }
3159 + }//end foreach
2685 3160
2686 3161 unset( $last, $jv );
2687 - }
3162 + }//end foreach
2688 3163
2689 3164 return $vars;
2690 3165 }
2691 3166
@@ -2933,8 +3408,11 @@
2933 3408 }
2934 3409
2935 3410 /**
2936 3411 * @since 4.02.03
3412 + *
3413 + * @param array|string $value
3414 + * @return string
2937 3415 */
2938 3416 public static function maybe_json_encode( $value ) {
2939 3417 if ( is_array( $value ) ) {
2940 3418 $value = wp_json_encode( $value );
@@ -2942,12 +3420,14 @@
2942 3420 return $value;
2943 3421 }
2944 3422
2945 3423 /**
3424 + * Echo The javascript to open and highlight the Formidable menu
3425 + *
2946 3426 * @since 1.07.10
2947 3427 *
2948 - * @param string $post_type The name of the post type that may need to be highlighted
2949 - * echo The javascript to open and highlight the Formidable menu
3428 + * @param string $post_type The name of the post type that may need to be highlighted.
3429 + * @return void
2950 3430 */
2951 3431 public static function maybe_highlight_menu( $post_type ) {
2952 3432 global $post;
2953 3433
@@ -2966,8 +3446,11 @@
2966 3446 /**
2967 3447 * Load the JS file on non-Formidable pages in the admin area
2968 3448 *
2969 3449 * @since 2.0
3450 + *
3451 + * @param bool $load
3452 + * @return void
2970 3453 */
2971 3454 public static function load_admin_wide_js( $load = true ) {
2972 3455 $version = self::plugin_version();
2973 3456 wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
@@ -2981,8 +3464,9 @@
2981 3464 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ),
2982 3465 'loading' => __( 'Loading&hellip;', 'formidable' ),
2983 3466 'nonce' => wp_create_nonce( 'frm_ajax' ),
2984 3467 'proIncludesSliderJs' => is_callable( 'FrmProFormsHelper::prepare_custom_currency' ),
3468 + 'inboxSlideIn' => FrmInbox::get_inbox_slide_in_value_for_js(),
2985 3469 );
2986 3470 wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
2987 3471
2988 3472 if ( $load ) {
@@ -2991,8 +3475,9 @@
2991 3475 }
2992 3476
2993 3477 /**
2994 3478 * @since 2.0.9
3479 + * @return void
2995 3480 */
2996 3481 public static function load_font_style() {
2997 3482 wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
2998 3483 }
@@ -2998,26 +3483,29 @@
2998 3483 }
2999 3484
3000 3485 /**
3001 3486 * @param string $location
3487 + * @return void
3002 3488 */
3003 3489 public static function localize_script( $location ) {
3004 - global $wp_scripts;
3490 + global $wp_scripts, $wp_version;
3005 3491
3006 3492 $script_strings = array(
3007 - 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3008 - 'images_url' => self::plugin_url() . '/images',
3009 - 'loading' => __( 'Loading&hellip;', 'formidable' ),
3010 - 'remove' => __( 'Remove', 'formidable' ),
3011 - 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3012 - 'nonce' => wp_create_nonce( 'frm_ajax' ),
3013 - 'id' => __( 'ID', 'formidable' ),
3014 - 'no_results' => __( 'No results match', 'formidable' ),
3015 - 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3016 - 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3017 - 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3018 - 'focus_first_error' => self::should_focus_first_error(),
3019 - 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3493 + 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3494 + 'images_url' => self::plugin_url() . '/images',
3495 + 'loading' => __( 'Loading&hellip;', 'formidable' ),
3496 + 'remove' => __( 'Remove', 'formidable' ),
3497 + 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3498 + 'nonce' => wp_create_nonce( 'frm_ajax' ),
3499 + 'id' => __( 'ID', 'formidable' ),
3500 + 'no_results' => __( 'No results match', 'formidable' ),
3501 + 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3502 + 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3503 + 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3504 + 'focus_first_error' => self::should_focus_first_error(),
3505 + 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
3506 + // We need to keep this setting for a few versions because Pro checks for this.
3507 + 'include_resend_email' => false,
3020 3508 );
3021 3509
3022 3510 $data = $wp_scripts->get_data( 'formidable', 'data' );
3023 3511 if ( ! $data ) {
@@ -3024,59 +3512,74 @@
3024 3512 wp_localize_script( 'formidable', 'frm_js', $script_strings );
3025 3513 }
3026 3514
3027 3515 if ( $location === 'admin' ) {
3028 - $frm_settings = self::get_settings();
3029 3516 $admin_script_strings = array(
3030 - 'desc' => __( '(Click to add description)', 'formidable' ),
3031 - 'blank' => __( '(Blank)', 'formidable' ),
3032 - 'no_label' => __( '(no label)', 'formidable' ),
3033 - 'ok' => __( 'OK', 'formidable' ),
3034 - 'cancel' => __( 'Cancel', 'formidable' ),
3035 - 'default_label' => __( 'Default', 'formidable' ),
3036 - 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3037 - 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3038 - 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3039 - 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3040 - 'confirm' => __( 'Are you sure?', 'formidable' ),
3041 - 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3042 - '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' ),
3043 - 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3044 - 'default_unique' => $frm_settings->unique_msg,
3045 - 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3046 - 'enter_email' => __( 'Enter Email', 'formidable' ),
3047 - 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3048 - 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3049 - 'new_option' => __( 'New Option', 'formidable' ),
3050 - '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' ),
3051 - 'enter_password' => __( 'Enter Password', 'formidable' ),
3052 - 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3053 - 'import_complete' => __( 'Import Complete', 'formidable' ),
3054 - 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3055 - 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3056 - 'private_label' => __( 'Private', 'formidable' ),
3057 - 'jquery_ui_url' => '',
3058 - 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3059 - 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3060 - 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3061 - 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3062 - 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3063 - 'only_one_action' => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
3064 - 'unsafe_params' => FrmFormsHelper::reserved_words(),
3517 + 'desc' => __( '(Click to add description)', 'formidable' ),
3518 + 'blank' => __( '(Blank)', 'formidable' ),
3519 + 'no_label' => __( '(no label)', 'formidable' ),
3520 + 'ok' => __( 'OK', 'formidable' ),
3521 + 'cancel' => __( 'Cancel', 'formidable' ),
3522 + 'default_label' => __( 'Default', 'formidable' ),
3523 + 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3524 + 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3525 + 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3526 + 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3527 + 'confirm' => __( 'Are you sure?', 'formidable' ),
3528 + 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3529 + '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' ),
3530 + 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3531 + 'default_unique' => FrmFieldsHelper::default_unique_msg(),
3532 + 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3533 + 'enter_email' => __( 'Enter Email', 'formidable' ),
3534 + 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3535 + 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3536 + 'new_option' => __( 'New Option', 'formidable' ),
3537 + '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' ),
3538 + 'enter_password' => __( 'Enter Password', 'formidable' ),
3539 + 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3540 + 'import_complete' => __( 'Import Complete', 'formidable' ),
3541 + 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3542 + 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3543 + 'private_label' => __( 'Private', 'formidable' ),
3544 + 'jquery_ui_url' => '',
3545 + 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3546 + 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3547 + 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3548 + 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3549 + 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3550 + /* translators: %d is the number of allowed actions per form */
3551 + 'only_one_action' => sprintf( __( 'This form action is limited to %d per form.', 'formidable' ), 1 ),
3552 + 'edit_action_text' => __( 'Please edit the existing form action.', 'formidable' ),
3553 + 'unsafe_params' => FrmFormsHelper::reserved_words(),
3065 3554 /* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
3066 - 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3555 + 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3067 3556 /* 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. */
3068 - 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3069 - 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3070 - 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3071 - 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3072 - 'install' => __( 'Install', 'formidable' ),
3073 - 'active' => __( 'Active', 'formidable' ),
3074 - 'select_a_field' => __( 'Select a Field', 'formidable' ),
3075 - 'no_items_found' => __( 'No items found.', 'formidable' ),
3076 - 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3077 - 'saving' => '', // Deprecated in 6.0.
3078 - 'saved' => '', // Deprecated in 6.0.
3557 + 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3558 + 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3559 + 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3560 + 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3561 + 'install' => __( 'Install', 'formidable' ),
3562 + 'active' => __( 'Active', 'formidable' ),
3563 + 'installed' => __( 'Installed', 'formidable' ),
3564 + 'not_installed' => __( 'Not Installed', 'formidable' ),
3565 + 'select_a_field' => __( 'Select a Field', 'formidable' ),
3566 + 'no_items_found' => __( 'No items found.', 'formidable' ),
3567 + 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3568 +
3569 + // Deprecated in 6.0.
3570 + 'saving' => '',
3571 +
3572 + // Deprecated in 6.0.
3573 + 'saved' => '',
3574 +
3575 + // translators: %1$s: HTML open tag, %2$s: HTML end tag.
3576 + 'holdShiftMsg' => esc_html__( 'You can hold %1$sShift%2$s on your keyboard to select multiple fields', 'formidable' ),
3577 + 'noTitleText' => FrmFormsHelper::get_no_title_text(),
3578 +
3579 + // In older versions this event listener causes the section to immediately close again
3580 + // when the h3 element is clicked. It's only required in WP 6.7+.
3581 + 'requireAccordionTitleClickListener' => version_compare( $wp_version, '6.7', '>=' ),
3079 3582 );
3080 3583 /**
3081 3584 * @param array $admin_script_strings
3082 3585 */
@@ -3085,9 +3588,9 @@
3085 3588 $data = $wp_scripts->get_data( 'formidable_admin', 'data' );
3086 3589 if ( ! $data ) {
3087 3590 wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
3088 3591 }
3089 - }
3592 + }//end if
3090 3593 }
3091 3594
3092 3595 /**
3093 3596 * @since 6.5
@@ -3131,9 +3634,10 @@
3131 3634 * Echo the message on the plugins listing page
3132 3635 *
3133 3636 * @since 1.07.10
3134 3637 *
3135 - * @param float $min_version The version the add-on requires
3638 + * @param float $min_version The version the add-on requires.
3639 + * @return void
3136 3640 */
3137 3641 public static function min_version_notice( $min_version ) {
3138 3642 $frm_version = self::plugin_version();
3139 3643
@@ -3167,9 +3671,8 @@
3167 3671 if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
3168 3672 return;
3169 3673 }
3170 3674
3171 - $pro_version = FrmProDb::$plug_version;
3172 3675 $expired = FrmAddonsController::is_license_expired();
3173 3676 ?>
3174 3677 <div class="frm-banner-alert frm_error_style frm_previous_install">
3175 3678 <?php
@@ -3187,8 +3690,11 @@
3187 3690 /**
3188 3691 * If Pro is installed, check the version number.
3189 3692 *
3190 3693 * @since 4.0.01
3694 + *
3695 + * @param string $min_version
3696 + * @return bool
3191 3697 */
3192 3698 public static function meets_min_pro_version( $min_version ) {
3193 3699 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3194 3700 }
@@ -3193,24 +3699,19 @@
3193 3699 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3194 3700 }
3195 3701
3196 3702 /**
3197 - * Show a message if the browser or PHP version is below the recommendations.
3703 + * Show a message if the PHP version is below the recommendations.
3198 3704 *
3199 3705 * @since 4.0.02
3706 + * @return void
3200 3707 */
3201 3708 private static function php_version_notice() {
3202 3709 $message = array();
3203 - if ( version_compare( phpversion(), '5.6', '<' ) ) {
3710 + if ( version_compare( phpversion(), '7.0', '<' ) ) {
3204 3711 $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' );
3205 3712 }
3206 3713
3207 - $browser = self::get_server_value( 'HTTP_USER_AGENT' );
3208 - $is_ie = strpos( $browser, 'MSIE' ) !== false;
3209 - if ( $is_ie ) {
3210 - $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' );
3211 - }
3212 -
3213 3714 foreach ( $message as $m ) {
3214 3715 ?>
3215 3716 <div class="frm-banner-alert frm_error_style frm_previous_install">
3216 3717 <?php echo esc_html( $m ); ?>
@@ -3340,16 +3841,10 @@
3340 3841 return $locales;
3341 3842 }
3342 3843
3343 3844 /**
3344 - * Output HTML containing reference text for accessibility
3345 - *
3346 - * @deprecated 5.1
3845 + * @return string
3347 3846 */
3348 - public static function multiselect_accessibility() {
3349 - _deprecated_function( __METHOD__, '5.1' );
3350 - }
3351 -
3352 3847 public static function get_menu_icon_class() {
3353 3848 if ( is_callable( 'FrmProAppHelper::get_settings' ) ) {
3354 3849 $settings = FrmProAppHelper::get_settings();
3355 3850 if ( is_object( $settings ) && ! empty( $settings->menu_icon ) ) {
@@ -3459,8 +3954,18 @@
3459 3954 return apply_filters( 'frm_images_dropdown_input_attrs', $input_attrs_str, $args );
3460 3955 }
3461 3956
3462 3957 /**
3958 + * @since 6.7.1
3959 + */
3960 + public static function get_images_dropdown_atts( $option, $args ) {
3961 + $image = self::get_images_dropdown_option_image( $option, $args );
3962 + $classes = self::get_images_dropdown_option_classes( $option, $args );
3963 + $custom_attrs = self::get_images_dropdown_option_html_attrs( $option, $args );
3964 + return compact( 'image', 'classes', 'custom_attrs' );
3965 + }
3966 +
3967 + /**
3463 3968 * Gets the image of each option in images_dropdown() method.
3464 3969 *
3465 3970 * @since 5.0.04
3466 3971 *
@@ -3471,9 +3976,9 @@
3471 3976 private static function get_images_dropdown_option_image( $option, $args ) {
3472 3977 $image = self::icon_by_class(
3473 3978 'frmfont ' . $option['svg'],
3474 3979 array(
3475 - 'echo' => false,
3980 + 'echo' => false,
3476 3981 )
3477 3982 );
3478 3983
3479 3984 $args['option'] = $option;
@@ -3611,15 +4116,15 @@
3611 4116 return $values;
3612 4117 }
3613 4118
3614 4119 /**
3615 - * Some back end fields allow privleged users to add scripts.
4120 + * Some back end fields allow privileged users to add scripts.
3616 4121 * A site that uses the DISALLOW_UNFILTERED_HTML always remove scripts on echo.
3617 4122 *
3618 4123 * @since 5.0.13
3619 4124 *
3620 4125 * @param string $value
3621 - * @param array|string $allowed 'all' for everything included as defaults
4126 + * @param array|string $allowed 'all' for everything included as defaults.
3622 4127 * @return string
3623 4128 */
3624 4129 public static function maybe_kses( $value, $allowed = 'all' ) {
3625 4130 if ( self::should_never_allow_unfiltered_html() ) {
@@ -3628,8 +4133,64 @@
3628 4133 return $value;
3629 4134 }
3630 4135
3631 4136 /**
4137 + * Check if an option attribute used in an [input] shortcode is safe.
4138 + *
4139 + * @since 6.11.2
4140 + *
4141 + * @param string $key
4142 + * @param string $context Either 'display' or 'update'. On update, we want to allow a few keys that are never displayed.
4143 + * @return bool
4144 + */
4145 + public static function input_key_is_safe( $key, $context = 'display' ) {
4146 + if ( 'update' === $context && in_array( $key, array( 'opt', 'label' ), true ) ) {
4147 + $safe = true;
4148 + } elseif ( 0 === strpos( $key, 'data-' ) ) {
4149 + // Allow all data attributes.
4150 + $safe = true;
4151 + } elseif ( 0 === strpos( $key, 'aria-' ) ) {
4152 + // Allow all aria attributes.
4153 + $safe = true;
4154 + } else {
4155 + $safe_keys = array(
4156 + 'class',
4157 + 'required',
4158 + 'title',
4159 + 'placeholder',
4160 + 'value',
4161 + 'readonly',
4162 + 'disabled',
4163 + 'size',
4164 + 'maxlength',
4165 + 'min',
4166 + 'max',
4167 + 'pattern',
4168 + 'step',
4169 + 'autofocus',
4170 + 'width',
4171 + 'height',
4172 + 'autocomplete',
4173 + 'tabindex',
4174 + 'role',
4175 + 'style',
4176 + );
4177 + $safe = in_array( $key, $safe_keys, true );
4178 + }//end if
4179 +
4180 + /**
4181 + * Filter the $safe value so additional keys can be allowed or disallowed.
4182 + *
4183 + * @since 6.11.2
4184 + *
4185 + * @param bool $safe True if the key is considered safe.
4186 + * @param string $key
4187 + * @param string $context Either 'display' or 'update'.
4188 + */
4189 + return (bool) apply_filters( 'frm_input_key_is_safe', $safe, $key, $context );
4190 + }
4191 +
4192 + /**
3632 4193 * @since 5.0.16
3633 4194 *
3634 4195 * @return bool
3635 4196 */
@@ -3654,20 +4215,9 @@
3654 4215
3655 4216 /**
3656 4217 * @since 5.0.17
3657 4218 *
3658 - * @param string $plugin
3659 - * @return string|false
3660 - */
3661 - private static function get_plan_required( $plugin ) {
3662 - $link = FrmAddonsController::install_link( $plugin );
3663 - return FrmFormsHelper::get_plan_required( $link );
3664 - }
3665 -
3666 - /**
3667 - * @since 5.0.17
3668 - *
3669 - * @param string
4219 + * @param string $feature
3670 4220 * @return bool
3671 4221 */
3672 4222 public static function show_new_feature( $feature ) {
3673 4223 $link = FrmAddonsController::install_link( $feature );
@@ -3740,9 +4290,9 @@
3740 4290 public static function show_pill_text( $text = null ) {
3741 4291 if ( null === $text ) {
3742 4292 $text = __( 'NEW', 'formidable' );
3743 4293 }
3744 - echo '<span class="frm-new-pill">' . esc_html( $text ) . '</span>';
4294 + echo '<span class="frm-meta-tag frm-new-pill">' . esc_html( $text ) . '</span>';
3745 4295 }
3746 4296
3747 4297 /**
3748 4298 * Count the number of decimals digits.
@@ -3749,9 +4299,9 @@
3749 4299 *
3750 4300 * @since 5.2.07
3751 4301 *
3752 4302 * @param mixed $num Number.
3753 - * @return int|false Returns `false` if the passed parameter is not number.
4303 + * @return false|int Returns `false` if the passed parameter is not number.
3754 4304 */
3755 4305 public static function count_decimals( $num ) {
3756 4306 if ( ! is_numeric( $num ) ) {
3757 4307 return false;
@@ -3782,9 +4332,9 @@
3782 4332 }
3783 4333
3784 4334 add_filter(
3785 4335 'option_gmt_offset',
3786 - function( $offset ) {
4336 + function ( $offset ) {
3787 4337 if ( ! is_string( $offset ) || is_numeric( $offset ) ) {
3788 4338 // Leave a valid value alone.
3789 4339 return $offset;
3790 4340 }
@@ -3866,65 +4416,8 @@
3866 4416 return true;
3867 4417 }
3868 4418
3869 4419 /**
3870 - * @since 4.08
3871 - * @deprecated 4.09.01
3872 - */
3873 - public static function expiring_message() {
3874 - _deprecated_function( __METHOD__, '4.09.01', 'FrmProAddonsController::expiring_message' );
3875 - if ( is_callable( 'FrmProAddonsController::expiring_message' ) ) {
3876 - FrmProAddonsController::expiring_message();
3877 - }
3878 - }
3879 -
3880 - /**
3881 - * Use the WP 4.7 wp_doing_ajax function
3882 - *
3883 - * @since 2.05.07
3884 - * @deprecated 4.04.04
3885 - */
3886 - public static function wp_doing_ajax() {
3887 - _deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
3888 - return wp_doing_ajax();
3889 - }
3890 -
3891 - /**
3892 - * @deprecated 4.0
3893 - */
3894 - public static function insert_opt_html( $args ) {
3895 - _deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
3896 - FrmFormsHelper::insert_opt_html( $args );
3897 - }
3898 -
3899 - /**
3900 - * @deprecated 3.01
3901 - * @codeCoverageIgnore
3902 - */
3903 - public static function sanitize_array( &$values ) {
3904 - FrmDeprecated::sanitize_array( $values );
3905 - }
3906 -
3907 - /**
3908 - * @since 2.0
3909 - * @deprecated 5.0.13
3910 - *
3911 - * @return string The base Google APIS url for the current version of jQuery UI
3912 - */
3913 - public static function jquery_ui_base_url() {
3914 - _deprecated_function( __FUNCTION__, '5.0.13', 'FrmProAppHelper::jquery_ui_base_url' );
3915 - return is_callable( 'FrmProAppHelper::jquery_ui_base_url' ) ? FrmProAppHelper::jquery_ui_base_url() : '';
3916 - }
3917 -
3918 - /**
3919 - * @since 4.07
3920 - * @deprecated 6.0
3921 - */
3922 - public static function renewal_message() {
3923 - _deprecated_function( __METHOD__, '6.0', 'FrmProAddonsController::renewal_message' );
3924 - }
3925 -
3926 - /**
3927 4420 * Display a dismissable warning message and save its dismissal state.
3928 4421 *
3929 4422 * @since 6.3
3930 4423 *
@@ -3936,9 +4429,9 @@
3936 4429 if ( ! $message || ! $option ) {
3937 4430 return;
3938 4431 }
3939 4432
3940 - $ajax_callback = function() use ( $option ) {
4433 + $ajax_callback = function () use ( $option ) {
3941 4434 self::dismiss_warning_message( $option );
3942 4435 };
3943 4436
3944 4437 // We're handling JS codes with `doJsonPost` and it adds 'frm_' to the beginning of the action.
@@ -3946,9 +4439,9 @@
3946 4439 add_action( 'wp_ajax_frm_' . $option, $ajax_callback );
3947 4440
3948 4441 add_filter(
3949 4442 'frm_message_list',
3950 - function( $show_messages ) use ( $message, $option ) {
4443 + function ( $show_messages ) use ( $message, $option ) {
3951 4444 if ( get_option( $option, false ) ) {
3952 4445 return $show_messages;
3953 4446 }
3954 4447
@@ -3955,9 +4448,9 @@
3955 4448 $dismiss_icon = self::icon_by_class(
3956 4449 'frmfont frm_close_icon',
3957 4450 array(
3958 4451 'aria-label' => _x( 'Dismiss', 'warning message: close icon label', 'formidable' ),
3959 - 'echo' => false,
4452 + 'echo' => false,
3960 4453 )
3961 4454 );
3962 4455
3963 4456 $show_messages[] = $message;
@@ -3984,6 +4477,124 @@
3984 4477 update_option( $option, true, 'no' );
3985 4478 }
3986 4479
3987 4480 wp_send_json_success();
4481 + }
4482 +
4483 + /**
4484 + * Lite license copy.
4485 + * Used in FrmDashboardController & FrmSettingsController
4486 + *
4487 + * @since 6.8
4488 + *
4489 + * @return string
4490 + */
4491 + public static function copy_for_lite_license() {
4492 + $message = __( 'You\'re using Formidable Forms Lite - no license needed. Enjoy!', 'formidable' ) . ' 🙂';
4493 +
4494 + if ( is_callable( 'FrmProAddonsController::get_readable_license_type' ) && ! class_exists( 'FrmProDashboardController' ) ) {
4495 + // Manage PRO versions without PRO dashboard functionality.
4496 + $license_type = FrmProAddonsController::get_readable_license_type();
4497 + if ( 'lite' !== strtolower( $license_type ) ) {
4498 + $message = 'Formidable Pro ' . $license_type;
4499 + }
4500 + }
4501 +
4502 + return apply_filters( 'frm_license_type_text', $message );
4503 + }
4504 +
4505 + /**
4506 + * Removes scripts that are unnecessarily loaded across the pages!
4507 + *
4508 + * @since 6.9
4509 + * @return void
4510 + */
4511 + public static function dequeue_extra_global_scripts() {
4512 + wp_dequeue_script( 'frm-surveys-admin' );
4513 + wp_dequeue_script( 'frm-quizzes-form-action' );
4514 + }
4515 +
4516 + /**
4517 + * Shows tooltip icon.
4518 + *
4519 + * @since 6.12
4520 + *
4521 + * @param string $tooltip_text Tooltip text.
4522 + * @param array $atts Tooltip wrapper HTML attributes.
4523 + *
4524 + * @return void
4525 + */
4526 + public static function tooltip_icon( $tooltip_text, $atts = array() ) {
4527 + $atts['title'] = $tooltip_text;
4528 + if ( isset( $atts['class'] ) ) {
4529 + $atts['class'] .= ' frm_help';
4530 + } else {
4531 + $atts['class'] = 'frm_help';
4532 + }
4533 + ?>
4534 + <span <?php self::array_to_html_params( $atts, true ); ?>>
4535 + <?php self::icon_by_class( 'frmfont frm_tooltip_icon' ); ?>
4536 + </span>
4537 + <?php
4538 + }
4539 +
4540 + /**
4541 + * Prints errors for settings in onboarding wizard or template settings.
4542 + *
4543 + * @since 6.15
4544 + *
4545 + * @param array $args Args.
4546 + *
4547 + * @return void
4548 + */
4549 + public static function print_setting_error( $args ) {
4550 + $args = wp_parse_args(
4551 + $args,
4552 + array(
4553 + 'id' => '',
4554 + 'errors' => array(),
4555 + 'class' => '',
4556 + )
4557 + );
4558 +
4559 + $args['class'] .= ' frm-validation-error frm-mt-xs frm_hidden';
4560 + ?>
4561 + <span id="<?php echo esc_attr( $args['id'] ); ?>" class="<?php echo esc_attr( $args['class'] ); ?>">
4562 + <?php
4563 + if ( is_array( $args['errors'] ) ) {
4564 + foreach ( $args['errors'] as $key => $msg ) {
4565 + ?>
4566 + <span frm-error="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $msg ); ?></span>
4567 + <?php
4568 + }
4569 + } else {
4570 + echo '<span>' . esc_html( $args['errors'] ) . '</span>';
4571 + }
4572 + ?>
4573 + </span>
4574 + <?php
4575 + }
4576 +
4577 + /**
4578 + * Check if GDPR is enabled.
4579 + *
4580 + * @since 6.19
4581 + *
4582 + * @return bool
4583 + */
4584 + public static function is_gdpr_enabled() {
4585 + $frm_settings = self::get_settings();
4586 + return $frm_settings->enable_gdpr || $frm_settings->no_ips || $frm_settings->custom_header_ip || $frm_settings->no_gdpr_cookies;
4587 + }
4588 +
4589 + /**
4590 + * Check if GDPR cookies are disabled.
4591 + *
4592 + * @since 6.19
4593 + *
4594 + * @return bool
4595 + */
4596 + public static function no_gdpr_cookies() {
4597 + $frm_settings = self::get_settings();
4598 + return $frm_settings->enable_gdpr && $frm_settings->no_gdpr_cookies;
3988 4599 }
3989 4600 }