PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.22.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.22.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/helpers/FrmAppHelper.php +951 -354 6.5.3 → 6.22.1 View file →
@@ -3,15 +3,26 @@
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
@@ -17,9 +28,9 @@
17 28 * @since 2.0
18 29 *
19 30 * @var string
20 31 */
21 - public static $plug_version = '6.5.3';
32 + public static $plug_version = '6.22.1';
22 33
23 34 /**
24 35 * @var bool
25 36 */
@@ -27,10 +38,8 @@
27 38
28 39 /**
29 40 * @since 1.07.02
30 41 *
31 - * @param none
32 - *
33 42 * @return string The version of this plugin
34 43 */
35 44 public static function plugin_version() {
36 45 return self::$plug_version;
@@ -35,21 +44,33 @@
35 44 public static function plugin_version() {
36 45 return self::$plug_version;
37 46 }
38 47
48 + /**
49 + * @return string
50 + */
39 51 public static function plugin_folder() {
40 52 return basename( self::plugin_path() );
41 53 }
42 54
55 + /**
56 + * @return string
57 + */
43 58 public static function plugin_path() {
44 - return dirname( dirname( dirname( __FILE__ ) ) );
59 + return dirname( dirname( __DIR__ ) );
45 60 }
46 61
62 + /**
63 + * @return string
64 + */
47 65 public static function plugin_url() {
48 - // Prevously FRM_URL constant.
66 + // Previously FRM_URL constant.
49 67 return plugins_url( '', self::plugin_path() . '/formidable.php' );
50 68 }
51 69
70 + /**
71 + * @return string
72 + */
52 73 public static function relative_plugin_url() {
53 74 return str_replace( array( 'https:', 'http:' ), '', self::plugin_url() );
54 75 }
55 76
@@ -70,8 +91,12 @@
70 91 public static function site_name() {
71 92 return get_option( 'blogname' );
72 93 }
73 94
95 + /**
96 + * @param string $url
97 + * @return string
98 + */
74 99 public static function make_affiliate_url( $url ) {
75 100 $affiliate_id = self::get_affiliate();
76 101 if ( ! empty( $affiliate_id ) ) {
77 102 $url = str_replace( array( 'http://', 'https://' ), '', $url );
@@ -80,8 +105,11 @@
80 105
81 106 return $url;
82 107 }
83 108
109 + /**
110 + * @return int
111 + */
84 112 public static function get_affiliate() {
85 113 return absint( apply_filters( 'frm_affiliate_id', 0 ) );
86 114 }
87 115
@@ -99,9 +127,9 @@
99 127 }
100 128
101 129 $anchor = '';
102 130 if ( is_array( $args ) ) {
103 - $medium = $args['medium'];
131 + $medium = isset( $args['medium'] ) ? $args['medium'] : '';
104 132 if ( isset( $args['content'] ) ) {
105 133 $content = $args['content'];
106 134 }
107 135 if ( isset( $args['anchor'] ) ) {
@@ -133,14 +161,42 @@
133 161 return self::make_affiliate_url( $link );
134 162 }
135 163
136 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 + /**
137 193 * Get the Formidable settings
138 194 *
139 195 * @since 2.0
140 196 *
141 197 * @param array $args - May include the form id when values need translation.
142 - * @return FrmSettings $frm_setings
198 + * @return FrmSettings $frm_settings
143 199 */
144 200 public static function get_settings( $args = array() ) {
145 201 global $frm_settings;
146 202 if ( empty( $frm_settings ) ) {
@@ -152,8 +208,11 @@
152 208
153 209 return $frm_settings;
154 210 }
155 211
212 + /**
213 + * @return string
214 + */
156 215 public static function get_menu_name() {
157 216 $frm_settings = self::get_settings();
158 217
159 218 return FrmAddonsController::is_license_expired() ? 'Formidable' : $frm_settings->menu;
@@ -160,24 +219,28 @@
160 219 }
161 220
162 221 /**
163 222 * Determine if the current branding is set to 'formidable'.
223 + * Checks the menu icon, and verifies if it matches the formidable branding.
164 224 *
165 - * Checks the menu title, retrieved through get_menu_name,
166 - * and verifies if it matches the 'formidable' branding.
167 - *
168 225 * @since 6.4.2
169 226 *
170 - * @return bool True if the menu title is 'formidable', false otherwise.
227 + * @return bool True if the menu icon is the logo, false otherwise.
171 228 */
172 229 public static function is_formidable_branding() {
173 - $menu_title = self::get_menu_name();
230 + if ( ! self::pro_is_installed() ) {
231 + return true;
232 + }
174 233
175 - return 'formidable' === strtolower( trim( $menu_title ) );
234 + $menu_icon = self::get_menu_icon_class();
235 + return strpos( $menu_icon, 'frm_logo_icon' ) !== false;
176 236 }
177 237
178 238 /**
179 239 * @since 3.05
240 + *
241 + * @param array $atts
242 + * @return string
180 243 */
181 244 public static function svg_logo( $atts = array() ) {
182 245 $defaults = array(
183 246 'height' => 18,
@@ -194,8 +257,11 @@
194 257 }
195 258
196 259 /**
197 260 * @since 4.0
261 + *
262 + * @param array $atts
263 + * @return void
198 264 */
199 265 public static function show_logo( $atts = array() ) {
200 266 echo self::kses( self::svg_logo( $atts ), 'all' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
201 267 }
@@ -201,8 +267,10 @@
201 267 }
202 268
203 269 /**
204 270 * @since 4.03.02
271 + *
272 + * @return void
205 273 */
206 274 public static function show_header_logo() {
207 275 $icon = self::svg_logo(
208 276 array(
@@ -224,21 +292,38 @@
224 292 }
225 293
226 294 /**
227 295 * @since 2.02.04
296 + *
297 + * @return bool
228 298 */
229 299 public static function ips_saved() {
230 300 $frm_settings = self::get_settings();
231 -
232 301 return ! $frm_settings->no_ips;
233 302 }
234 303
304 + /**
305 + * @return bool
306 + */
235 307 public static function pro_is_installed() {
236 - return apply_filters( 'frm_pro_installed', false );
308 + return (bool) apply_filters( 'frm_pro_installed', false );
237 309 }
238 310
239 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 + /**
240 323 * @since 4.06.02
324 + *
325 + * @return bool
241 326 */
242 327 public static function pro_is_connected() {
243 328 global $frm_vars;
244 329 return self::pro_is_installed() && $frm_vars['pro_is_authorized'];
@@ -245,14 +330,26 @@
245 330 }
246 331
247 332 /**
248 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
249 339 */
250 - public static function is_form_builder_page() {
251 - $action = self::simple_get( 'frm_action', 'sanitize_title' );
252 - 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 );
253 347 }
254 348
349 + /**
350 + * @return bool
351 + */
255 352 public static function is_formidable_admin() {
256 353 $page = self::simple_get( 'page', 'sanitize_title' );
257 354 $is_formidable = strpos( $page, 'formidable' ) !== false;
258 355 if ( empty( $page ) ) {
@@ -262,15 +359,52 @@
262 359 return $is_formidable;
263 360 }
264 361
265 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 + /**
266 400 * Check for certain page in Formidable settings
267 401 *
268 402 * @since 2.0
269 403 *
270 - * @param string $page The name of the page to check
404 + * @param string $page The name of the page to check.
271 405 *
272 - * @return boolean
406 + * @return bool
273 407 */
274 408 public static function is_admin_page( $page = 'formidable' ) {
275 409 global $pagenow;
276 410 $get_page = self::simple_get( 'page', 'sanitize_title' );
@@ -289,8 +423,10 @@
289 423 * If the current page is for editing or creating a view.
290 424 * Returns false for the views listing page.
291 425 *
292 426 * @since 4.0
427 + *
428 + * @return bool
293 429 */
294 430 public static function is_view_builder_page() {
295 431 global $pagenow;
296 432
@@ -300,10 +436,10 @@
300 436
301 437 $post_type = self::simple_get( 'post_type', 'sanitize_title' );
302 438
303 439 if ( empty( $post_type ) ) {
304 - $post_id = self::simple_get( 'post', 'absint' );
305 - $post = get_post( $post_id );
440 + $post_id = self::simple_get( 'post', 'absint' );
441 + $post = get_post( $post_id );
306 442 $post_type = $post ? $post->post_type : '';
307 443 }
308 444
309 445 return $post_type === 'frm_display';
@@ -313,17 +449,15 @@
313 449 * Check for the form preview page
314 450 *
315 451 * @since 2.0
316 452 *
317 - * @param None
318 - *
319 - * @return boolean
453 + * @return bool
320 454 */
321 455 public static function is_preview_page() {
322 456 global $pagenow;
323 457 $action = self::simple_get( 'action', 'sanitize_title' );
324 458
325 - return $pagenow && $pagenow == 'admin-ajax.php' && $action == 'frm_forms_preview';
459 + return $pagenow && $pagenow === 'admin-ajax.php' && $action === 'frm_forms_preview';
326 460 }
327 461
328 462 /**
329 463 * Check for ajax except the form preview page
@@ -329,16 +463,17 @@
329 463 * Check for ajax except the form preview page
330 464 *
331 465 * @since 2.0
332 466 *
333 - * @param None
334 - *
335 - * @return boolean
467 + * @return bool
336 468 */
337 469 public static function doing_ajax() {
338 470 return wp_doing_ajax() && ! self::is_preview_page();
339 471 }
340 472
473 + /**
474 + * @return string
475 + */
341 476 public static function js_suffix() {
342 477 return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
343 478 }
344 479
@@ -343,13 +478,13 @@
343 478 }
344 479
345 480 /**
346 481 * @since 2.0.8
482 + * @return bool
347 483 */
348 484 public static function prevent_caching() {
349 485 global $frm_vars;
350 -
351 - return isset( $frm_vars['prevent_caching'] ) && $frm_vars['prevent_caching'];
486 + return ! empty( $frm_vars['prevent_caching'] );
352 487 }
353 488
354 489 /**
355 490 * Check if on an admin page
@@ -355,9 +490,9 @@
355 490 * Check if on an admin page
356 491 *
357 492 * @since 2.0
358 493 *
359 - * @return boolean
494 + * @return bool
360 495 */
361 496 public static function is_admin() {
362 497 $is_admin = is_admin() && ! wp_doing_ajax();
363 498
@@ -372,17 +507,22 @@
372 507 * Check if value contains blank value or empty array
373 508 *
374 509 * @since 2.0
375 510 *
376 - * @param mixed $value - value to check
377 - * @param string
511 + * @param mixed $value Value to check.
512 + * @param string $empty
378 513 *
379 - * @return boolean
514 + * @return bool
380 515 */
381 516 public static function is_empty_value( $value, $empty = '' ) {
382 517 return ( is_array( $value ) && empty( $value ) ) || $value === $empty;
383 518 }
384 519
520 + /**
521 + * @param mixed $value
522 + * @param string $empty
523 + * @return bool
524 + */
385 525 public static function is_not_empty_value( $value, $empty = '' ) {
386 526 return ! self::is_empty_value( $value, $empty );
387 527 }
388 528
@@ -435,9 +575,10 @@
435 575 }
436 576
437 577 $key = self::get_server_value( $key );
438 578 foreach ( explode( ',', $key ) as $ip ) {
439 - $ip = trim( $ip ); // Just to be safe.
579 + // Just to be safe.
580 + $ip = trim( $ip );
440 581
441 582 if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
442 583 return sanitize_text_field( $ip );
443 584 }
@@ -528,15 +669,24 @@
528 669
529 670 return $value;
530 671 }
531 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 + */
532 682 public static function get_post_param( $param, $default = '', $sanitize = '', $serialized = false ) {
533 683 return self::get_simple_request(
534 684 array(
535 - 'type' => 'post',
536 - 'param' => $param,
537 - 'default' => $default,
538 - 'sanitize' => $sanitize,
685 + 'type' => 'post',
686 + 'param' => $param,
687 + 'default' => $default,
688 + 'sanitize' => $sanitize,
539 689 'serialized' => $serialized,
540 690 )
541 691 );
542 692 }
@@ -547,9 +697,9 @@
547 697 * @param string $param
548 698 * @param string $sanitize
549 699 * @param string $default
550 700 *
551 - * @return string|array
701 + * @return array|string
552 702 */
553 703 public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
554 704 return self::get_simple_request(
555 705 array(
@@ -567,16 +717,16 @@
567 717 * @since 2.0.6
568 718 *
569 719 * @param array $args
570 720 *
571 - * @return string|array
721 + * @return array|string
572 722 */
573 723 public static function get_simple_request( $args ) {
574 724 $defaults = array(
575 - 'param' => '',
576 - 'default' => '',
577 - 'type' => 'get',
578 - 'sanitize' => 'sanitize_text_field',
725 + 'param' => '',
726 + 'default' => '',
727 + 'type' => 'get',
728 + 'sanitize' => 'sanitize_text_field',
579 729 'serialized' => false,
580 730 );
581 731 $args = wp_parse_args( $args, $defaults );
582 732
@@ -593,13 +743,12 @@
593 743 if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
594 744 self::unserialize_or_decode( $value );
595 745 }
596 746 }
597 - } else {
598 - if ( isset( $_REQUEST[ $args['param'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
747 + } elseif ( isset( $_REQUEST[ $args['param'] ] ) ) {
748 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
599 749 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
600 750 $value = wp_unslash( $_REQUEST[ $args['param'] ] );
601 - }
602 751 }
603 752
604 753 self::sanitize_value( $args['sanitize'], $value );
605 754
@@ -623,19 +772,35 @@
623 772
624 773 return $value;
625 774 }
626 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 + */
627 784 public static function sanitize_value( $sanitize, &$value ) {
628 - if ( ! empty( $sanitize ) ) {
629 - if ( is_array( $value ) ) {
630 - $temp_values = $value;
631 - foreach ( $temp_values as $k => $v ) {
632 - self::sanitize_value( $sanitize, $value[ $k ] );
633 - }
634 - } else {
635 - $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 ] );
636 798 }
799 + return;
637 800 }
801 +
802 + $value = call_user_func( $sanitize, $value );
638 803 }
639 804
640 805 public static function sanitize_request( $sanitize_method, &$values ) {
641 806 $temp_values = $values;
@@ -647,15 +812,52 @@
647 812 }
648 813
649 814 /**
650 815 * @since 4.0.04
816 + *
817 + * @param mixed $value
818 + * @return void
651 819 */
652 820 public static function sanitize_with_html( &$value ) {
653 - 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 + }
654 827 self::decode_specialchars( $value );
655 828 }
656 829
657 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 + /**
658 860 * Do wp_specialchars_decode to get back '&' that wp_kses_post might have turned to '&amp;'
659 861 * this MUST be done, else we'll be back to the '& entity' problem.
660 862 *
661 863 * @since 4.0.04
@@ -689,10 +891,12 @@
689 891 $translation = array(
690 892 '&quot;' => '"',
691 893 '&#034;' => '"',
692 894 '&#x22;' => '"',
693 - '&lt; ' => '< ', // The space preserves the HTML.
694 - '&#060; ' => '< ', // The space preserves the HTML.
895 + // The space preserves the HTML.
896 + '&lt; ' => '< ',
897 + // The space preserves the HTML.
898 + '&#060; ' => '< ',
695 899 '&gt;' => '>',
696 900 '&#062;' => '>',
697 901 '&amp;' => '&',
698 902 '&#038;' => '&',
@@ -719,10 +923,10 @@
719 923 * Sanitize the value, and allow some HTML
720 924 *
721 925 * @since 2.0
722 926 *
723 - * @param string $value
724 - * @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.
725 929 *
726 930 * @return string
727 931 */
728 932 public static function kses( $value, $allowed = array() ) {
@@ -731,8 +935,21 @@
731 935 return wp_kses( $value, $allowed_html );
732 936 }
733 937
734 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 + /**
735 952 * The regular kses function strips [button_action] from submit button HTML.
736 953 *
737 954 * @since 5.0.13
738 955 *
@@ -823,9 +1040,9 @@
823 1040 'id' => true,
824 1041 );
825 1042
826 1043 return array(
827 - 'a' => array(
1044 + 'a' => array(
828 1045 'class' => true,
829 1046 'href' => true,
830 1047 'id' => true,
831 1048 'rel' => true,
@@ -894,16 +1111,16 @@
894 1111 'cite' => true,
895 1112 'title' => true,
896 1113 ),
897 1114 'rect' => array(
898 - 'class' => true,
899 - 'fill' => true,
900 - 'height' => true,
901 - 'width' => true,
902 - 'x' => true,
903 - 'y' => true,
904 - 'rx' => true,
905 - '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,
906 1123 'stroke-opacity' => true,
907 1124 'stroke-width' => true,
908 1125 ),
909 1126 'section' => $allow_class,
@@ -938,9 +1155,9 @@
938 1155 'xlink:href' => true,
939 1156 ),
940 1157 'ul' => $allow_class,
941 1158 'label' => array(
942 - 'for' => true,
1159 + 'for' => true,
943 1160 'class' => true,
944 1161 'id' => true,
945 1162 ),
946 1163 'button' => array(
@@ -949,8 +1166,13 @@
949 1166 ),
950 1167 'legend' => array(
951 1168 'class' => true,
952 1169 ),
1170 + 'option' => array(
1171 + 'class' => true,
1172 + 'value' => true,
1173 + 'selected' => true,
1174 + ),
953 1175 );
954 1176 }
955 1177
956 1178 /**
@@ -958,9 +1180,9 @@
958 1180 *
959 1181 * @since 2.0
960 1182 */
961 1183 public static function remove_get_action() {
962 - if ( ! isset( $_GET ) ) {
1184 + if ( empty( $_GET ) ) {
963 1185 return;
964 1186 }
965 1187
966 1188 $action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
@@ -977,9 +1199,9 @@
977 1199 /**
978 1200 * Check the WP query for a parameter
979 1201 *
980 1202 * @since 2.0
981 - * @return string|array
1203 + * @return array|string
982 1204 */
983 1205 public static function get_query_var( $value, $param ) {
984 1206 if ( $value != '' ) {
985 1207 return $value;
@@ -996,10 +1218,12 @@
996 1218 /**
997 1219 * Try to show the SVG if possible. Otherwise, use the font icon.
998 1220 *
999 1221 * @since 4.0.02
1222 + *
1000 1223 * @param string $class
1001 1224 * @param array $atts
1225 + * @return string|null
1002 1226 */
1003 1227 public static function icon_by_class( $class, $atts = array() ) {
1004 1228 $echo = ! isset( $atts['echo'] ) || $atts['echo'];
1005 1229 if ( isset( $atts['echo'] ) ) {
@@ -1009,14 +1233,16 @@
1009 1233 $html_atts = self::array_to_html_params( $atts );
1010 1234
1011 1235 $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
1012 1236
1013 - // Replace icons that have been removed.
1237 + // Replace icons that have been removed or renamed.
1014 1238 $deprecated = array(
1015 - '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',
1016 1242 );
1017 1243 if ( isset( $deprecated[ $icon ] ) ) {
1018 - $icon = $deprecated[ $icon ];
1244 + $icon = $deprecated[ $icon ];
1019 1245 $class = str_replace( $icon, $deprecated[ $icon ], $class );
1020 1246 }
1021 1247
1022 1248 if ( $icon === $class ) {
@@ -1026,11 +1252,9 @@
1026 1252 if ( strpos( $icon, ' ' ) ) {
1027 1253 $icon = explode( ' ', $icon );
1028 1254 $icon = reset( $icon );
1029 1255 }
1030 - $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '>
1031 - <use xlink:href="#' . esc_attr( $icon ) . '" />
1032 - </svg>';
1256 + $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use xlink:href="#' . esc_attr( $icon ) . '" /></svg>';
1033 1257 }
1034 1258
1035 1259 if ( $echo ) {
1036 1260 echo self::kses_icon( $icon ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
@@ -1139,9 +1363,9 @@
1139 1363 * @param bool $echo
1140 1364 * @return string|void
1141 1365 */
1142 1366 public static function array_to_html_params( $atts, $echo = false ) {
1143 - $callback = function() use ( $atts ) {
1367 + $callback = function () use ( $atts ) {
1144 1368 if ( $atts ) {
1145 1369 foreach ( $atts as $key => $value ) {
1146 1370 echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1147 1371 }
@@ -1156,9 +1380,9 @@
1156 1380 * @since 5.0.13
1157 1381 *
1158 1382 * @param Closure $echo_function
1159 1383 * @param bool $echo
1160 - * @return string|void
1384 + * @return string|null
1161 1385 */
1162 1386 public static function clip( $echo_function, $echo = false ) {
1163 1387 if ( ! $echo ) {
1164 1388 ob_start();
@@ -1176,12 +1400,15 @@
1176 1400 }
1177 1401
1178 1402 /**
1179 1403 * @since 3.0
1404 + *
1405 + * @param array $atts
1406 + * @return void
1180 1407 */
1181 1408 public static function get_admin_header( $atts ) {
1182 - $has_nav = ( isset( $atts['form'] ) && ! empty( $atts['form'] ) && ( ! isset( $atts['is_template'] ) || ! $atts['is_template'] ) );
1183 - if ( ! isset( $atts['close'] ) || empty( $atts['close'] ) ) {
1409 + $has_nav = ! empty( $atts['form'] ) && empty( $atts['is_template'] );
1410 + if ( empty( $atts['close'] ) ) {
1184 1411 $atts['close'] = admin_url( 'admin.php?page=formidable' );
1185 1412 }
1186 1413 if ( ! isset( $atts['import_link'] ) ) {
1187 1414 $atts['import_link'] = false;
@@ -1186,9 +1413,9 @@
1186 1413 if ( ! isset( $atts['import_link'] ) ) {
1187 1414 $atts['import_link'] = false;
1188 1415 }
1189 1416
1190 - include( self::plugin_path() . '/classes/views/shared/admin-header.php' );
1417 + include self::plugin_path() . '/classes/views/shared/admin-header.php';
1191 1418 }
1192 1419
1193 1420 /**
1194 1421 * @since 6.0
@@ -1217,9 +1444,9 @@
1217 1444 FrmInbox::maybe_show_banner();
1218 1445 return;
1219 1446 }
1220 1447
1221 - 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() ) {
1222 1449 // Print license warning or inbox banner and exit if either prints.
1223 1450 // And exit before printing the upgrade bar if it shouldn't be shown.
1224 1451 return;
1225 1452 }
@@ -1224,10 +1451,36 @@
1224 1451 return;
1225 1452 }
1226 1453 ?>
1227 1454 <div class="frm-upgrade-bar">
1228 - <span>You're using Formidable Forms Lite. To unlock more features consider</span>
1229 - <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>
1230 1483 </div>
1231 1484 <?php
1232 1485 }
1233 1486
@@ -1244,8 +1497,10 @@
1244 1497 * Render a button for a new item (Form, Application, etc).
1245 1498 *
1246 1499 * @since 3.0
1247 1500 * @param array $atts {
1501 + * Details about the button.
1502 + *
1248 1503 * @type array $link_hook Custom link hook, calls do_action and exits early.
1249 1504 * @type string $new_link Href value, default #.
1250 1505 * @type string $class Custom class names, space separated.
1251 1506 * @type string $button_text Button text. Default "Add New".
@@ -1257,9 +1512,9 @@
1257 1512 do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
1258 1513 return;
1259 1514 }
1260 1515
1261 - 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'] ) ) {
1262 1517 // Do not render a button if none of these attributes are set.
1263 1518 return;
1264 1519 }
1265 1520
@@ -1265,12 +1520,8 @@
1265 1520
1266 1521 $href = ! empty( $atts['new_link'] ) ? esc_url( $atts['new_link'] ) : '#';
1267 1522 $class = 'button button-primary frm-button-primary';
1268 1523
1269 - if ( ! empty( $atts['trigger_new_form_modal'] ) ) {
1270 - $class .= ' frm-trigger-new-form-modal';
1271 - }
1272 -
1273 1524 if ( ! empty( $atts['class'] ) ) {
1274 1525 $class .= ' ' . $atts['class'];
1275 1526 }
1276 1527
@@ -1287,10 +1538,11 @@
1287 1538 'placeholder' => '',
1288 1539 'tosearch' => '',
1289 1540 'text' => __( 'Search', 'formidable' ),
1290 1541 'input_id' => '',
1542 + 'value' => false,
1291 1543 );
1292 - $atts = array_merge( $defaults, $atts );
1544 + $atts = array_merge( $defaults, $atts );
1293 1545
1294 1546 if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
1295 1547 $atts['tosearch'] = 'frm-card';
1296 1548 }
@@ -1301,8 +1553,27 @@
1301 1553 }
1302 1554
1303 1555 $input_id = $atts['input_id'] . '-search-input';
1304 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 + }
1305 1576 ?>
1306 1577 <p class="frm-search">
1307 1578 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1308 1579 <?php echo esc_html( $atts['text'] ); ?>:
@@ -1307,15 +1578,9 @@
1307 1578 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1308 1579 <?php echo esc_html( $atts['text'] ); ?>:
1309 1580 </label>
1310 1581 <span class="frmfont frm_search_icon"></span>
1311 - <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
1312 - value="<?php _admin_search_query(); ?>" placeholder="<?php echo esc_attr( $atts['placeholder'] ); ?>"
1313 - class="<?php echo esc_attr( $class ); ?>" data-tosearch="<?php echo esc_attr( $atts['tosearch'] ); ?>"
1314 - <?php if ( ! empty( $atts['tosearch'] ) ) { ?>
1315 - autocomplete="off"
1316 - <?php } ?>
1317 - />
1582 + <input <?php self::array_to_html_params( $input_atts, true ); ?> />
1318 1583 <?php
1319 1584 if ( empty( $atts['tosearch'] ) ) {
1320 1585 submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
1321 1586 }
@@ -1325,8 +1590,9 @@
1325 1590 }
1326 1591
1327 1592 /**
1328 1593 * @param string $type
1594 + * @return void
1329 1595 */
1330 1596 public static function trigger_hook_load( $type, $object = null ) {
1331 1597 // Only load the form hooks once.
1332 1598 $hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
@@ -1370,9 +1636,9 @@
1370 1636 'new_file_path' => self::plugin_path() . '/js',
1371 1637 )
1372 1638 );
1373 1639 $new_file = new FrmCreateFile( $file_atts );
1374 - $files = array(
1640 + $files = array(
1375 1641 FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.min.js',
1376 1642 );
1377 1643
1378 1644 /**
@@ -1389,14 +1655,14 @@
1389 1655 * True when value is 1, true, 'true', 'yes'
1390 1656 *
1391 1657 * @since 1.07.10
1392 1658 *
1393 - * @param string $value The value to compare
1659 + * @param string $value The value to compare.
1394 1660 *
1395 - * @return boolean True or False
1661 + * @return bool
1396 1662 */
1397 1663 public static function is_true( $value ) {
1398 - return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1664 + return true === $value || 1 == $value || 'true' === $value || 'yes' === $value;
1399 1665 }
1400 1666
1401 1667 /**
1402 1668 * Gets all post from a specific post type.
@@ -1454,9 +1720,9 @@
1454 1720 $args = self::preformat_selection_args( $args );
1455 1721
1456 1722 $pages_count = wp_count_posts( $args['post_type'] );
1457 1723
1458 - if ( $pages_count->publish <= 50 ) {
1724 + if ( ! isset( $pages_count->publish ) || $pages_count->publish <= 50 ) {
1459 1725 self::wp_pages_dropdown( $args );
1460 1726 return;
1461 1727 }
1462 1728
@@ -1462,9 +1728,9 @@
1462 1728
1463 1729 wp_enqueue_script( 'jquery-ui-autocomplete' );
1464 1730
1465 1731 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1466 - $title = '';
1732 + $title = '';
1467 1733
1468 1734 if ( $selected ) {
1469 1735 $title = get_the_title( $selected );
1470 1736 }
@@ -1480,18 +1746,112 @@
1480 1746 <?php
1481 1747 }
1482 1748
1483 1749 /**
1484 - * @param array $args
1485 - * @param string $page_id Deprecated.
1486 - * @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.
1487 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 + */
1488 1849 public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1489 1850 self::prep_page_dropdown_params( $page_id, $truncate, $args );
1490 1851
1491 1852 $pages = self::get_post_ids_and_titles( $args['post_type'] );
1492 1853 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1493 -
1494 1854 ?>
1495 1855 <select name="<?php echo esc_attr( $args['field_name'] ); ?>" id="<?php echo esc_attr( $args['field_name'] ); ?>" class="frm-pages-dropdown">
1496 1856 <option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
1497 1857 <?php foreach ( $pages as $page ) { ?>
@@ -1528,13 +1888,13 @@
1528 1888 * @since 4.10.01 Added `post_type` and `autocomplete_placeholder` to the arguments array.
1529 1889 */
1530 1890 private static function preformat_selection_args( $args ) {
1531 1891 $defaults = array(
1532 - 'truncate' => false,
1533 - 'placeholder' => ' ',
1534 - 'field_name' => '',
1535 - 'page_id' => '',
1536 - 'post_type' => 'page',
1892 + 'truncate' => false,
1893 + 'placeholder' => ' ',
1894 + 'field_name' => '',
1895 + 'page_id' => '',
1896 + 'post_type' => 'page',
1537 1897 'autocomplete_placeholder' => __( 'Select a Page', 'formidable' ),
1538 1898 );
1539 1899
1540 1900 return array_merge( $defaults, $args );
@@ -1605,25 +1965,16 @@
1605 1965 return self::is_admin_page( 'formidable-views-editor' );
1606 1966 }
1607 1967
1608 1968 /**
1609 - * @since 4.0
1610 - * @deprecated 5.5.3
1969 + * @param string $field_name
1970 + * @param array|string $capability
1971 + * @param string $multiple 'single' and 'multiple'.
1611 1972 */
1612 - public static function maybe_full_screen_link( $link ) {
1613 - _deprecated_function( __METHOD__, '5.5.3' );
1614 - return $link;
1615 - }
1616 -
1617 - /**
1618 - * @param string $field_name
1619 - * @param string|array $capability
1620 - * @param string $multiple 'single' and 'multiple'
1621 - */
1622 1973 public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1623 1974 ?>
1624 1975 <select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1625 - <?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1976 + <?php echo 'multiple' === $multiple ? 'multiple="multiple"' : ''; ?>
1626 1977 class="frm_multiselect">
1627 1978 <?php self::roles_options( $capability ); ?>
1628 1979 </select>
1629 1980 <?php
@@ -1631,9 +1982,9 @@
1631 1982
1632 1983 /**
1633 1984 * @since 4.07
1634 1985 * @param array|string $selected
1635 - * @param string $current
1986 + * @param string $current
1636 1987 */
1637 1988 private static function selected( $selected, $current ) {
1638 1989 if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1639 1990 FrmProAppHelper::selected( $selected, $current );
@@ -1642,9 +1993,9 @@
1642 1993 }
1643 1994 }
1644 1995
1645 1996 /**
1646 - * @param string|array $capability
1997 + * @param array|string $capability
1647 1998 */
1648 1999 public static function roles_options( $capability ) {
1649 2000 global $frm_vars;
1650 2001 if ( isset( $frm_vars['editable_roles'] ) ) {
@@ -1656,9 +2007,9 @@
1656 2007
1657 2008 foreach ( $editable_roles as $role => $details ) {
1658 2009 $name = translate_user_role( $details['name'] );
1659 2010 ?>
1660 - <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>
1661 2012 <?php
1662 2013 unset( $role, $details );
1663 2014 }
1664 2015 }
@@ -1679,9 +2030,8 @@
1679 2030 $pro_cap = array(
1680 2031 'frm_create_entries' => __( 'Add Entries from Admin Area', 'formidable' ),
1681 2032 'frm_edit_entries' => __( 'Edit Entries from Admin Area', 'formidable' ),
1682 2033 'frm_view_reports' => __( 'View Reports', 'formidable' ),
1683 - 'frm_edit_displays' => __( 'Add/Edit Views', 'formidable' ),
1684 2034 );
1685 2035 /**
1686 2036 * @since 5.3.1
1687 2037 *
@@ -1688,8 +2038,14 @@
1688 2038 * @param array<string,string> $pro_cap
1689 2039 */
1690 2040 $pro_cap = apply_filters( 'frm_pro_capabilities', $pro_cap );
1691 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 +
1692 2048 if ( 'pro_only' === $type ) {
1693 2049 return $pro_cap;
1694 2050 }
1695 2051
@@ -1704,9 +2060,9 @@
1704 2060 * @return array<string,string>
1705 2061 */
1706 2062 private static function get_lite_capabilities() {
1707 2063 return array(
1708 - 'frm_view_forms' => __( 'View Forms', 'formidable' ),
2064 + 'frm_view_forms' => __( 'View Forms List', 'formidable' ),
1709 2065 'frm_edit_forms' => __( 'Add and Edit Forms', 'formidable' ),
1710 2066 'frm_delete_forms' => __( 'Delete Forms', 'formidable' ),
1711 2067 'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1712 2068 'frm_view_entries' => __( 'View Entries from Admin Area', 'formidable' ),
@@ -1747,9 +2103,9 @@
1747 2103 return current_user_can( $role );
1748 2104 }
1749 2105
1750 2106 /**
1751 - * @param string|array $needed_role
2107 + * @param array|string $needed_role
1752 2108 * @return bool
1753 2109 */
1754 2110 public static function user_has_permission( $needed_role ) {
1755 2111 if ( is_array( $needed_role ) ) {
@@ -1805,8 +2161,11 @@
1805 2161 /**
1806 2162 * Make sure admins have permission to see the menu items
1807 2163 *
1808 2164 * @since 2.0.6
2165 + *
2166 + * @param string $cap
2167 + * @return void
1809 2168 */
1810 2169 public static function force_capability( $cap = 'frm_change_settings' ) {
1811 2170 if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1812 2171 $role = get_role( 'administrator' );
@@ -1817,9 +2176,9 @@
1817 2176 }
1818 2177 }
1819 2178
1820 2179 /**
1821 - * Check if the user has permision for action.
2180 + * Check if the user has permission for action.
1822 2181 * Return permission message and stop the action if no permission
1823 2182 *
1824 2183 * @since 2.0
1825 2184 *
@@ -1855,9 +2214,9 @@
1855 2214 if ( empty( $nonce_name ) ) {
1856 2215 return $error;
1857 2216 }
1858 2217
1859 - $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 ] ) ) : '';
1860 2219 if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1861 2220 $frm_settings = self::get_settings();
1862 2221 $error = $frm_settings->admin_permission;
1863 2222 }
@@ -1871,12 +2230,13 @@
1871 2230 }
1872 2231 }
1873 2232
1874 2233 public static function check_selected( $values, $current ) {
1875 - $values = self::recursive_function_map( $values, 'trim' );
1876 - $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1877 - $current = htmlspecialchars_decode( trim( $current ) );
2234 + $values = self::recursive_function_map( $values, 'trim' );
2235 + $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1878 2236
2237 + $current = is_null( $current ) ? '' : htmlspecialchars_decode( trim( $current ) );
2238 +
1879 2239 return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1880 2240 }
1881 2241
1882 2242 public static function recursive_function_map( $value, $function ) {
@@ -1896,8 +2256,9 @@
1896 2256 }
1897 2257 }
1898 2258 }
1899 2259 } else {
2260 + $value = self::maybe_update_value_if_null( $value, $function );
1900 2261 $value = call_user_func( $function, $value );
1901 2262 }
1902 2263
1903 2264 return $value;
@@ -1902,8 +2263,24 @@
1902 2263
1903 2264 return $value;
1904 2265 }
1905 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 +
1906 2283 public static function is_assoc( $array ) {
1907 2284 return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1908 2285 }
1909 2286
@@ -1914,14 +2291,12 @@
1914 2291 $return = array();
1915 2292 foreach ( $array as $key => $value ) {
1916 2293 if ( is_array( $value ) ) {
1917 2294 $return = array_merge( $return, self::array_flatten( $value, $keys ) );
2295 + } elseif ( $keys === 'keep' ) {
2296 + $return[ $key ] = $value;
1918 2297 } else {
1919 - if ( $keys === 'keep' ) {
1920 - $return[ $key ] = $value;
1921 - } else {
1922 - $return[] = $value;
1923 - }
2298 + $return[] = $value;
1924 2299 }
1925 2300 }
1926 2301
1927 2302 return $return;
@@ -1926,8 +2301,27 @@
1926 2301
1927 2302 return $return;
1928 2303 }
1929 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 + */
1930 2324 public static function esc_textarea( $text, $is_rich_text = false ) {
1931 2325 $safe_text = str_replace( '&quot;', '"', $text );
1932 2326 if ( ! $is_rich_text ) {
1933 2327 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
@@ -1933,9 +2327,13 @@
1933 2327 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1934 2328 }
1935 2329 $safe_text = str_replace( '&amp; ', '& ', $safe_text );
1936 2330
1937 - 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 );
1938 2336 }
1939 2337
1940 2338 /**
1941 2339 * Add auto paragraphs to text areas
@@ -1942,9 +2340,9 @@
1942 2340 *
1943 2341 * @since 2.0
1944 2342 */
1945 2343 public static function use_wpautop( $content ) {
1946 - if ( apply_filters( 'frm_use_wpautop', true ) && ! is_array( $content ) ) {
2344 + if ( apply_filters( 'frm_use_wpautop', true ) && is_string( $content ) ) {
1947 2345 $content = wpautop( str_replace( '<br>', '<br />', $content ) );
1948 2346 }
1949 2347
1950 2348 return $content;
@@ -1986,12 +2384,12 @@
1986 2384 * @since 5.0.13 added $echo param.
1987 2385 *
1988 2386 * @param string $url
1989 2387 * @param bool $echo
1990 - * @return string|void
2388 + * @return string|null
1991 2389 */
1992 2390 public static function js_redirect( $url, $echo = false ) {
1993 - $callback = function() use ( $url ) {
2391 + $callback = function () use ( $url ) {
1994 2392 echo '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1995 2393 };
1996 2394 return self::clip( $callback, $echo );
1997 2395 }
@@ -2019,8 +2417,13 @@
2019 2417
2020 2418 return $user_id;
2021 2419 }
2022 2420
2421 + /**
2422 + * @param string $filename
2423 + * @param array $atts
2424 + * @return false|string
2425 + */
2023 2426 public static function get_file_contents( $filename, $atts = array() ) {
2024 2427 if ( ! is_file( $filename ) ) {
2025 2428 return false;
2026 2429 }
@@ -2026,9 +2429,9 @@
2026 2429 }
2027 2430
2028 2431 extract( $atts ); // phpcs:ignore WordPress.PHP.DontExtract
2029 2432 ob_start();
2030 - include( $filename );
2433 + include $filename;
2031 2434 $contents = ob_get_contents();
2032 2435 ob_end_clean();
2033 2436
2034 2437 return $contents;
@@ -2083,9 +2486,9 @@
2083 2486 ++$suffix;
2084 2487 } while ( in_array( $key_check, $similar_keys, true ) );
2085 2488
2086 2489 $key = $key_check;
2087 - }
2490 + }//end if
2088 2491
2089 2492 return $key;
2090 2493 }
2091 2494
@@ -2124,14 +2527,18 @@
2124 2527 return $key;
2125 2528 }
2126 2529
2127 2530 /**
2531 + * @since 6.21 This is changed from `private` to `public`.
2532 + *
2128 2533 * @param int $num_chars
2129 2534 * @return string
2130 2535 */
2131 - private static function generate_new_key( $num_chars ) {
2536 + public static function generate_new_key( $num_chars ) {
2132 2537 $max_slug_value = pow( 36, $num_chars );
2133 - $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;
2134 2541 return base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
2135 2542 }
2136 2543
2137 2544 /**
@@ -2160,11 +2567,16 @@
2160 2567
2161 2568 /**
2162 2569 * Editing a Form or Entry
2163 2570 *
2164 - * @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
2165 2577 *
2166 - * @return bool|array
2578 + * @return array|bool
2167 2579 */
2168 2580 public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
2169 2581 if ( ! $record ) {
2170 2582 return false;
@@ -2217,13 +2629,12 @@
2217 2629 $post_values = $args['post_values'];
2218 2630
2219 2631 if ( $args['default'] ) {
2220 2632 $meta_value = $field->default_value;
2221 - } else {
2222 - if ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2223 - if ( ! isset( $field->field_options['custom_field'] ) ) {
2224 - $field->field_options['custom_field'] = '';
2225 - }
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 + }
2226 2637 $meta_value = FrmProEntryMetaHelper::get_post_value(
2227 2638 $record->post_id,
2228 2639 $field->field_options['post_field'],
2229 2640 $field->field_options['custom_field'],
@@ -2233,12 +2644,11 @@
2233 2644 'form_id' => $field->form_id,
2234 2645 'field' => $field,
2235 2646 )
2236 2647 );
2237 - } else {
2238 - $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2239 - }
2240 - }
2648 + } else {
2649 + $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2650 + }//end if
2241 2651
2242 2652 $field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
2243 2653 if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
2244 2654 $new_value = $post_values['item_meta'][ $field->id ];
@@ -2286,12 +2696,15 @@
2286 2696 );
2287 2697 }
2288 2698
2289 2699 /**
2700 + * @param object $record
2290 2701 * @param string $table
2702 + * @param array $post_values
2703 + * @param array $values
2291 2704 */
2292 2705 private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
2293 - if ( $table == 'entries' ) {
2706 + if ( $table === 'entries' ) {
2294 2707 $form = $record->form_id;
2295 2708 FrmForm::maybe_get_form( $form );
2296 2709 } else {
2297 2710 $form = $record;
@@ -2327,9 +2740,9 @@
2327 2740 $form_defaults = FrmFormsHelper::get_default_opts();
2328 2741
2329 2742 foreach ( $form_defaults as $opt => $default ) {
2330 2743 if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
2331 - $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;
2332 2745 }
2333 2746
2334 2747 unset( $opt, $default );
2335 2748 }
@@ -2350,9 +2763,9 @@
2350 2763 * @since 2.2.10
2351 2764 *
2352 2765 * @param array $post_values
2353 2766 *
2354 - * @return boolean|int
2767 + * @return bool|int
2355 2768 */
2356 2769 public static function custom_style_value( $post_values ) {
2357 2770 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2358 2771 $custom_style = absint( $post_values['options']['custom_style'] );
@@ -2357,29 +2770,37 @@
2357 2770 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2358 2771 $custom_style = absint( $post_values['options']['custom_style'] );
2359 2772 } else {
2360 2773 $frm_settings = self::get_settings();
2361 - $custom_style = ( $frm_settings->load_style != 'none' );
2774 + $custom_style = ( $frm_settings->load_style !== 'none' );
2362 2775 }
2363 2776
2364 2777 return $custom_style;
2365 2778 }
2366 2779
2367 - public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
2368 - 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 ) ) {
2369 2789 return '';
2370 2790 }
2371 2791
2372 2792 $length = (int) $length;
2373 - $str = wp_strip_all_tags( $str );
2793 + $str = wp_strip_all_tags( (string) $original_string );
2374 2794 $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
2375 2795
2376 2796 if ( $length == 0 ) {
2377 2797 return '';
2378 - } elseif ( $length <= 10 ) {
2798 + }
2799 +
2800 + if ( $length <= 10 ) {
2379 2801 $sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
2380 -
2381 - return $sub . ( ( $length < $original_len ) ? $continue : '' );
2802 + return $sub . ( $length < $original_len ? $continue : '' );
2382 2803 }
2383 2804
2384 2805 $sub = '';
2385 2806 $len = 0;
@@ -2385,10 +2806,14 @@
2385 2806 $len = 0;
2386 2807
2387 2808 $words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
2388 2809
2810 + if ( ! is_array( $words ) ) {
2811 + return $original_string;
2812 + }
2813 +
2389 2814 foreach ( $words as $word ) {
2390 - $part = ( ( $sub != '' ) ? ' ' : '' ) . $word;
2815 + $part = ( $sub != '' ? ' ' : '' ) . $word;
2391 2816 $total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
2392 2817 if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
2393 2818 break;
2394 2819 }
@@ -2402,11 +2827,37 @@
2402 2827
2403 2828 unset( $total_len, $word );
2404 2829 }
2405 2830
2406 - 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 : '' );
2407 2834 }
2408 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 +
2409 2860 public static function mb_function( $function_names, $args ) {
2410 2861 $mb_function_name = $function_names[0];
2411 2862 $function_name = $function_names[1];
2412 2863 if ( function_exists( $mb_function_name ) ) {
@@ -2439,8 +2890,13 @@
2439 2890
2440 2891 return $formatted;
2441 2892 }
2442 2893
2894 + /**
2895 + * @param string $time_format
2896 + * @param string $date
2897 + * @return string
2898 + */
2443 2899 private static function add_time_to_date( $time_format, $date ) {
2444 2900 if ( empty( $time_format ) ) {
2445 2901 $time_format = get_option( 'time_format' );
2446 2902 }
@@ -2463,12 +2919,12 @@
2463 2919 return date_i18n( $date_format, strtotime( $date ) );
2464 2920 }
2465 2921
2466 2922 /**
2467 - * Gets the time ago in words
2923 + * Gets the time ago in words.
2468 2924 *
2469 - * @param int $from in seconds
2470 - * @param int|string $to in seconds
2925 + * @param int $from In seconds.
2926 + * @param int|string $to In seconds.
2471 2927 *
2472 2928 * @return string $time_ago
2473 2929 */
2474 2930 public static function human_time_diff( $from, $to = '', $levels = 1 ) {
@@ -2483,9 +2939,9 @@
2483 2939 $diff_object = $now->diff( $ago );
2484 2940 $diff = get_object_vars( $diff_object );
2485 2941
2486 2942 // Add week amount and update day amount
2487 - $diff['w'] = floor( $diff['d'] / 7 );
2943 + $diff['w'] = floor( $diff['d'] / 7 );
2488 2944 $diff['d'] -= $diff['w'] * 7;
2489 2945
2490 2946 $time_strings = self::get_time_strings();
2491 2947
@@ -2492,9 +2948,9 @@
2492 2948 if ( ! is_numeric( $levels ) ) {
2493 2949 // Show time in specified unit.
2494 2950 $levels = self::get_unit( $levels );
2495 2951 if ( isset( $time_strings[ $levels ] ) ) {
2496 - $diff = array(
2952 + $diff = array(
2497 2953 $levels => self::time_format( $levels, $diff ),
2498 2954 );
2499 2955 $time_strings = array(
2500 2956 $levels => $time_strings[ $levels ],
@@ -2583,9 +3039,9 @@
2583 3039 }
2584 3040
2585 3041 /**
2586 3042 * Get the translatable time strings. The untranslated version is a failsafe
2587 - * 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.
2588 3044 *
2589 3045 * @since 2.0.20
2590 3046 * @return array
2591 3047 */
@@ -2631,23 +3087,28 @@
2631 3087
2632 3088 // Pagination Methods.
2633 3089
2634 3090 /**
2635 - * @param integer $current_p
3091 + * @param int $r_count
3092 + * @param int $current_p
3093 + * @param int $p_size
3094 + * @return int
2636 3095 */
2637 3096 public static function get_last_record_num( $r_count, $current_p, $p_size ) {
2638 - 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 );
2639 3098 }
2640 3099
2641 3100 /**
2642 - * @param integer $current_p
3101 + * @param int $r_count
3102 + * @param int $current_p
3103 + * @param int $p_size
3104 + * @return int
2643 3105 */
2644 3106 public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2645 3107 if ( $current_p == 1 ) {
2646 3108 return 1;
2647 - } else {
2648 - return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2649 3109 }
3110 + return self::get_last_record_num( $r_count, $current_p - 1, $p_size ) + 1;
2650 3111 }
2651 3112
2652 3113 /**
2653 3114 * @return array
@@ -2670,9 +3131,9 @@
2670 3131 if ( ! isset( $l3 ) ) {
2671 3132 $l3 = $name;
2672 3133 }
2673 3134
2674 - $this_val = ( $p == $last ) ? $jv['value'] : array();
3135 + $this_val = $p == $last ? $jv['value'] : array();
2675 3136
2676 3137 switch ( $p ) {
2677 3138 case 0:
2678 3139 $l1 = $name;
@@ -2694,12 +3155,12 @@
2694 3155 self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2695 3156 }
2696 3157
2697 3158 unset( $this_val, $n );
2698 - }
3159 + }//end foreach
2699 3160
2700 3161 unset( $last, $jv );
2701 - }
3162 + }//end foreach
2702 3163
2703 3164 return $vars;
2704 3165 }
2705 3166
@@ -2947,8 +3408,11 @@
2947 3408 }
2948 3409
2949 3410 /**
2950 3411 * @since 4.02.03
3412 + *
3413 + * @param array|string $value
3414 + * @return string
2951 3415 */
2952 3416 public static function maybe_json_encode( $value ) {
2953 3417 if ( is_array( $value ) ) {
2954 3418 $value = wp_json_encode( $value );
@@ -2956,12 +3420,14 @@
2956 3420 return $value;
2957 3421 }
2958 3422
2959 3423 /**
3424 + * Echo The javascript to open and highlight the Formidable menu
3425 + *
2960 3426 * @since 1.07.10
2961 3427 *
2962 - * @param string $post_type The name of the post type that may need to be highlighted
2963 - * 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
2964 3430 */
2965 3431 public static function maybe_highlight_menu( $post_type ) {
2966 3432 global $post;
2967 3433
@@ -2980,8 +3446,11 @@
2980 3446 /**
2981 3447 * Load the JS file on non-Formidable pages in the admin area
2982 3448 *
2983 3449 * @since 2.0
3450 + *
3451 + * @param bool $load
3452 + * @return void
2984 3453 */
2985 3454 public static function load_admin_wide_js( $load = true ) {
2986 3455 $version = self::plugin_version();
2987 3456 wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
@@ -2995,8 +3464,9 @@
2995 3464 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ),
2996 3465 'loading' => __( 'Loading&hellip;', 'formidable' ),
2997 3466 'nonce' => wp_create_nonce( 'frm_ajax' ),
2998 3467 'proIncludesSliderJs' => is_callable( 'FrmProFormsHelper::prepare_custom_currency' ),
3468 + 'inboxSlideIn' => FrmInbox::get_inbox_slide_in_value_for_js(),
2999 3469 );
3000 3470 wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
3001 3471
3002 3472 if ( $load ) {
@@ -3005,8 +3475,9 @@
3005 3475 }
3006 3476
3007 3477 /**
3008 3478 * @since 2.0.9
3479 + * @return void
3009 3480 */
3010 3481 public static function load_font_style() {
3011 3482 wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
3012 3483 }
@@ -3012,26 +3483,29 @@
3012 3483 }
3013 3484
3014 3485 /**
3015 3486 * @param string $location
3487 + * @return void
3016 3488 */
3017 3489 public static function localize_script( $location ) {
3018 - global $wp_scripts;
3490 + global $wp_scripts, $wp_version;
3019 3491
3020 3492 $script_strings = array(
3021 - 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3022 - 'images_url' => self::plugin_url() . '/images',
3023 - 'loading' => __( 'Loading&hellip;', 'formidable' ),
3024 - 'remove' => __( 'Remove', 'formidable' ),
3025 - 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3026 - 'nonce' => wp_create_nonce( 'frm_ajax' ),
3027 - 'id' => __( 'ID', 'formidable' ),
3028 - 'no_results' => __( 'No results match', 'formidable' ),
3029 - 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3030 - 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3031 - 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3032 - 'focus_first_error' => self::should_focus_first_error(),
3033 - '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,
3034 3508 );
3035 3509
3036 3510 $data = $wp_scripts->get_data( 'formidable', 'data' );
3037 3511 if ( ! $data ) {
@@ -3038,59 +3512,74 @@
3038 3512 wp_localize_script( 'formidable', 'frm_js', $script_strings );
3039 3513 }
3040 3514
3041 3515 if ( $location === 'admin' ) {
3042 - $frm_settings = self::get_settings();
3043 3516 $admin_script_strings = array(
3044 - 'desc' => __( '(Click to add description)', 'formidable' ),
3045 - 'blank' => __( '(Blank)', 'formidable' ),
3046 - 'no_label' => __( '(no label)', 'formidable' ),
3047 - 'ok' => __( 'OK', 'formidable' ),
3048 - 'cancel' => __( 'Cancel', 'formidable' ),
3049 - 'default_label' => __( 'Default', 'formidable' ),
3050 - 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3051 - 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3052 - 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3053 - 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3054 - 'confirm' => __( 'Are you sure?', 'formidable' ),
3055 - 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3056 - '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' ),
3057 - 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3058 - 'default_unique' => $frm_settings->unique_msg,
3059 - 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3060 - 'enter_email' => __( 'Enter Email', 'formidable' ),
3061 - 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3062 - 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3063 - 'new_option' => __( 'New Option', 'formidable' ),
3064 - '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' ),
3065 - 'enter_password' => __( 'Enter Password', 'formidable' ),
3066 - 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3067 - 'import_complete' => __( 'Import Complete', 'formidable' ),
3068 - 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3069 - 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3070 - 'private_label' => __( 'Private', 'formidable' ),
3071 - 'jquery_ui_url' => '',
3072 - 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3073 - 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3074 - 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3075 - 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3076 - 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3077 - 'only_one_action' => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
3078 - '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(),
3079 3554 /* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
3080 - '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' ), '****' ),
3081 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. */
3082 - 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3083 - 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3084 - 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3085 - 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3086 - 'install' => __( 'Install', 'formidable' ),
3087 - 'active' => __( 'Active', 'formidable' ),
3088 - 'select_a_field' => __( 'Select a Field', 'formidable' ),
3089 - 'no_items_found' => __( 'No items found.', 'formidable' ),
3090 - 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3091 - 'saving' => '', // Deprecated in 6.0.
3092 - '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', '>=' ),
3093 3582 );
3094 3583 /**
3095 3584 * @param array $admin_script_strings
3096 3585 */
@@ -3099,9 +3588,9 @@
3099 3588 $data = $wp_scripts->get_data( 'formidable_admin', 'data' );
3100 3589 if ( ! $data ) {
3101 3590 wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
3102 3591 }
3103 - }
3592 + }//end if
3104 3593 }
3105 3594
3106 3595 /**
3107 3596 * @since 6.5
@@ -3145,9 +3634,10 @@
3145 3634 * Echo the message on the plugins listing page
3146 3635 *
3147 3636 * @since 1.07.10
3148 3637 *
3149 - * @param float $min_version The version the add-on requires
3638 + * @param float $min_version The version the add-on requires.
3639 + * @return void
3150 3640 */
3151 3641 public static function min_version_notice( $min_version ) {
3152 3642 $frm_version = self::plugin_version();
3153 3643
@@ -3181,9 +3671,8 @@
3181 3671 if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
3182 3672 return;
3183 3673 }
3184 3674
3185 - $pro_version = FrmProDb::$plug_version;
3186 3675 $expired = FrmAddonsController::is_license_expired();
3187 3676 ?>
3188 3677 <div class="frm-banner-alert frm_error_style frm_previous_install">
3189 3678 <?php
@@ -3201,8 +3690,11 @@
3201 3690 /**
3202 3691 * If Pro is installed, check the version number.
3203 3692 *
3204 3693 * @since 4.0.01
3694 + *
3695 + * @param string $min_version
3696 + * @return bool
3205 3697 */
3206 3698 public static function meets_min_pro_version( $min_version ) {
3207 3699 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3208 3700 }
@@ -3207,24 +3699,19 @@
3207 3699 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3208 3700 }
3209 3701
3210 3702 /**
3211 - * 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.
3212 3704 *
3213 3705 * @since 4.0.02
3706 + * @return void
3214 3707 */
3215 3708 private static function php_version_notice() {
3216 3709 $message = array();
3217 - if ( version_compare( phpversion(), '5.6', '<' ) ) {
3710 + if ( version_compare( phpversion(), '7.0', '<' ) ) {
3218 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' );
3219 3712 }
3220 3713
3221 - $browser = self::get_server_value( 'HTTP_USER_AGENT' );
3222 - $is_ie = strpos( $browser, 'MSIE' ) !== false;
3223 - if ( $is_ie ) {
3224 - $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' );
3225 - }
3226 -
3227 3714 foreach ( $message as $m ) {
3228 3715 ?>
3229 3716 <div class="frm-banner-alert frm_error_style frm_previous_install">
3230 3717 <?php echo esc_html( $m ); ?>
@@ -3354,16 +3841,10 @@
3354 3841 return $locales;
3355 3842 }
3356 3843
3357 3844 /**
3358 - * Output HTML containing reference text for accessibility
3359 - *
3360 - * @deprecated 5.1
3845 + * @return string
3361 3846 */
3362 - public static function multiselect_accessibility() {
3363 - _deprecated_function( __METHOD__, '5.1' );
3364 - }
3365 -
3366 3847 public static function get_menu_icon_class() {
3367 3848 if ( is_callable( 'FrmProAppHelper::get_settings' ) ) {
3368 3849 $settings = FrmProAppHelper::get_settings();
3369 3850 if ( is_object( $settings ) && ! empty( $settings->menu_icon ) ) {
@@ -3473,8 +3954,18 @@
3473 3954 return apply_filters( 'frm_images_dropdown_input_attrs', $input_attrs_str, $args );
3474 3955 }
3475 3956
3476 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 + /**
3477 3968 * Gets the image of each option in images_dropdown() method.
3478 3969 *
3479 3970 * @since 5.0.04
3480 3971 *
@@ -3485,9 +3976,9 @@
3485 3976 private static function get_images_dropdown_option_image( $option, $args ) {
3486 3977 $image = self::icon_by_class(
3487 3978 'frmfont ' . $option['svg'],
3488 3979 array(
3489 - 'echo' => false,
3980 + 'echo' => false,
3490 3981 )
3491 3982 );
3492 3983
3493 3984 $args['option'] = $option;
@@ -3625,15 +4116,15 @@
3625 4116 return $values;
3626 4117 }
3627 4118
3628 4119 /**
3629 - * Some back end fields allow privleged users to add scripts.
4120 + * Some back end fields allow privileged users to add scripts.
3630 4121 * A site that uses the DISALLOW_UNFILTERED_HTML always remove scripts on echo.
3631 4122 *
3632 4123 * @since 5.0.13
3633 4124 *
3634 4125 * @param string $value
3635 - * @param array|string $allowed 'all' for everything included as defaults
4126 + * @param array|string $allowed 'all' for everything included as defaults.
3636 4127 * @return string
3637 4128 */
3638 4129 public static function maybe_kses( $value, $allowed = 'all' ) {
3639 4130 if ( self::should_never_allow_unfiltered_html() ) {
@@ -3642,8 +4133,64 @@
3642 4133 return $value;
3643 4134 }
3644 4135
3645 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 + /**
3646 4193 * @since 5.0.16
3647 4194 *
3648 4195 * @return bool
3649 4196 */
@@ -3668,20 +4215,9 @@
3668 4215
3669 4216 /**
3670 4217 * @since 5.0.17
3671 4218 *
3672 - * @param string $plugin
3673 - * @return string|false
3674 - */
3675 - private static function get_plan_required( $plugin ) {
3676 - $link = FrmAddonsController::install_link( $plugin );
3677 - return FrmFormsHelper::get_plan_required( $link );
3678 - }
3679 -
3680 - /**
3681 - * @since 5.0.17
3682 - *
3683 - * @param string
4219 + * @param string $feature
3684 4220 * @return bool
3685 4221 */
3686 4222 public static function show_new_feature( $feature ) {
3687 4223 $link = FrmAddonsController::install_link( $feature );
@@ -3754,9 +4290,9 @@
3754 4290 public static function show_pill_text( $text = null ) {
3755 4291 if ( null === $text ) {
3756 4292 $text = __( 'NEW', 'formidable' );
3757 4293 }
3758 - echo '<span class="frm-new-pill">' . esc_html( $text ) . '</span>';
4294 + echo '<span class="frm-meta-tag frm-new-pill">' . esc_html( $text ) . '</span>';
3759 4295 }
3760 4296
3761 4297 /**
3762 4298 * Count the number of decimals digits.
@@ -3763,9 +4299,9 @@
3763 4299 *
3764 4300 * @since 5.2.07
3765 4301 *
3766 4302 * @param mixed $num Number.
3767 - * @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.
3768 4304 */
3769 4305 public static function count_decimals( $num ) {
3770 4306 if ( ! is_numeric( $num ) ) {
3771 4307 return false;
@@ -3796,9 +4332,9 @@
3796 4332 }
3797 4333
3798 4334 add_filter(
3799 4335 'option_gmt_offset',
3800 - function( $offset ) {
4336 + function ( $offset ) {
3801 4337 if ( ! is_string( $offset ) || is_numeric( $offset ) ) {
3802 4338 // Leave a valid value alone.
3803 4339 return $offset;
3804 4340 }
@@ -3880,65 +4416,8 @@
3880 4416 return true;
3881 4417 }
3882 4418
3883 4419 /**
3884 - * @since 4.08
3885 - * @deprecated 4.09.01
3886 - */
3887 - public static function expiring_message() {
3888 - _deprecated_function( __METHOD__, '4.09.01', 'FrmProAddonsController::expiring_message' );
3889 - if ( is_callable( 'FrmProAddonsController::expiring_message' ) ) {
3890 - FrmProAddonsController::expiring_message();
3891 - }
3892 - }
3893 -
3894 - /**
3895 - * Use the WP 4.7 wp_doing_ajax function
3896 - *
3897 - * @since 2.05.07
3898 - * @deprecated 4.04.04
3899 - */
3900 - public static function wp_doing_ajax() {
3901 - _deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
3902 - return wp_doing_ajax();
3903 - }
3904 -
3905 - /**
3906 - * @deprecated 4.0
3907 - */
3908 - public static function insert_opt_html( $args ) {
3909 - _deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
3910 - FrmFormsHelper::insert_opt_html( $args );
3911 - }
3912 -
3913 - /**
3914 - * @deprecated 3.01
3915 - * @codeCoverageIgnore
3916 - */
3917 - public static function sanitize_array( &$values ) {
3918 - FrmDeprecated::sanitize_array( $values );
3919 - }
3920 -
3921 - /**
3922 - * @since 2.0
3923 - * @deprecated 5.0.13
3924 - *
3925 - * @return string The base Google APIS url for the current version of jQuery UI
3926 - */
3927 - public static function jquery_ui_base_url() {
3928 - _deprecated_function( __FUNCTION__, '5.0.13', 'FrmProAppHelper::jquery_ui_base_url' );
3929 - return is_callable( 'FrmProAppHelper::jquery_ui_base_url' ) ? FrmProAppHelper::jquery_ui_base_url() : '';
3930 - }
3931 -
3932 - /**
3933 - * @since 4.07
3934 - * @deprecated 6.0
3935 - */
3936 - public static function renewal_message() {
3937 - _deprecated_function( __METHOD__, '6.0', 'FrmProAddonsController::renewal_message' );
3938 - }
3939 -
3940 - /**
3941 4420 * Display a dismissable warning message and save its dismissal state.
3942 4421 *
3943 4422 * @since 6.3
3944 4423 *
@@ -3950,9 +4429,9 @@
3950 4429 if ( ! $message || ! $option ) {
3951 4430 return;
3952 4431 }
3953 4432
3954 - $ajax_callback = function() use ( $option ) {
4433 + $ajax_callback = function () use ( $option ) {
3955 4434 self::dismiss_warning_message( $option );
3956 4435 };
3957 4436
3958 4437 // We're handling JS codes with `doJsonPost` and it adds 'frm_' to the beginning of the action.
@@ -3960,9 +4439,9 @@
3960 4439 add_action( 'wp_ajax_frm_' . $option, $ajax_callback );
3961 4440
3962 4441 add_filter(
3963 4442 'frm_message_list',
3964 - function( $show_messages ) use ( $message, $option ) {
4443 + function ( $show_messages ) use ( $message, $option ) {
3965 4444 if ( get_option( $option, false ) ) {
3966 4445 return $show_messages;
3967 4446 }
3968 4447
@@ -3969,9 +4448,9 @@
3969 4448 $dismiss_icon = self::icon_by_class(
3970 4449 'frmfont frm_close_icon',
3971 4450 array(
3972 4451 'aria-label' => _x( 'Dismiss', 'warning message: close icon label', 'formidable' ),
3973 - 'echo' => false,
4452 + 'echo' => false,
3974 4453 )
3975 4454 );
3976 4455
3977 4456 $show_messages[] = $message;
@@ -3998,6 +4477,124 @@
3998 4477 update_option( $option, true, 'no' );
3999 4478 }
4000 4479
4001 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;
4002 4599 }
4003 4600 }