PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.21
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.21
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 +968 -358 6.56.21 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';
32 + public static $plug_version = '6.21';
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,32 +208,39 @@
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 - return $frm_settings->menu;
218 + return FrmAddonsController::is_license_expired() ? 'Formidable' : $frm_settings->menu;
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
@@ -394,14 +541,13 @@
394 541
395 542 /**
396 543 * Get the server OS
397 544 *
398 - * @since 6.4.x
545 + * @since 6.4.2
399 546 *
400 547 * @return string
401 548 */
402 549 public static function get_server_os() {
403 -
404 550 if ( function_exists( 'php_uname' ) ) {
405 551 return php_uname( 's' );
406 552 }
407 553
@@ -429,9 +575,10 @@
429 575 }
430 576
431 577 $key = self::get_server_value( $key );
432 578 foreach ( explode( ',', $key ) as $ip ) {
433 - $ip = trim( $ip ); // Just to be safe.
579 + // Just to be safe.
580 + $ip = trim( $ip );
434 581
435 582 if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
436 583 return sanitize_text_field( $ip );
437 584 }
@@ -522,15 +669,24 @@
522 669
523 670 return $value;
524 671 }
525 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 + */
526 682 public static function get_post_param( $param, $default = '', $sanitize = '', $serialized = false ) {
527 683 return self::get_simple_request(
528 684 array(
529 - 'type' => 'post',
530 - 'param' => $param,
531 - 'default' => $default,
532 - 'sanitize' => $sanitize,
685 + 'type' => 'post',
686 + 'param' => $param,
687 + 'default' => $default,
688 + 'sanitize' => $sanitize,
533 689 'serialized' => $serialized,
534 690 )
535 691 );
536 692 }
@@ -541,9 +697,9 @@
541 697 * @param string $param
542 698 * @param string $sanitize
543 699 * @param string $default
544 700 *
545 - * @return string|array
701 + * @return array|string
546 702 */
547 703 public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
548 704 return self::get_simple_request(
549 705 array(
@@ -561,16 +717,16 @@
561 717 * @since 2.0.6
562 718 *
563 719 * @param array $args
564 720 *
565 - * @return string|array
721 + * @return array|string
566 722 */
567 723 public static function get_simple_request( $args ) {
568 724 $defaults = array(
569 - 'param' => '',
570 - 'default' => '',
571 - 'type' => 'get',
572 - 'sanitize' => 'sanitize_text_field',
725 + 'param' => '',
726 + 'default' => '',
727 + 'type' => 'get',
728 + 'sanitize' => 'sanitize_text_field',
573 729 'serialized' => false,
574 730 );
575 731 $args = wp_parse_args( $args, $defaults );
576 732
@@ -587,13 +743,12 @@
587 743 if ( $args['serialized'] === true && is_serialized_string( $value ) && is_serialized( $value ) ) {
588 744 self::unserialize_or_decode( $value );
589 745 }
590 746 }
591 - } else {
592 - if ( isset( $_REQUEST[ $args['param'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
747 + } elseif ( isset( $_REQUEST[ $args['param'] ] ) ) {
748 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
593 749 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
594 750 $value = wp_unslash( $_REQUEST[ $args['param'] ] );
595 - }
596 751 }
597 752
598 753 self::sanitize_value( $args['sanitize'], $value );
599 754
@@ -617,19 +772,35 @@
617 772
618 773 return $value;
619 774 }
620 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 + */
621 784 public static function sanitize_value( $sanitize, &$value ) {
622 - if ( ! empty( $sanitize ) ) {
623 - if ( is_array( $value ) ) {
624 - $temp_values = $value;
625 - foreach ( $temp_values as $k => $v ) {
626 - self::sanitize_value( $sanitize, $value[ $k ] );
627 - }
628 - } else {
629 - $value = call_user_func( $sanitize, $value );
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 ] );
630 798 }
799 + return;
631 800 }
801 +
802 + $value = call_user_func( $sanitize, $value );
632 803 }
633 804
634 805 public static function sanitize_request( $sanitize_method, &$values ) {
635 806 $temp_values = $values;
@@ -641,15 +812,52 @@
641 812 }
642 813
643 814 /**
644 815 * @since 4.0.04
816 + *
817 + * @param mixed $value
818 + * @return void
645 819 */
646 820 public static function sanitize_with_html( &$value ) {
647 - 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 + }
648 827 self::decode_specialchars( $value );
649 828 }
650 829
651 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 + /**
652 860 * Do wp_specialchars_decode to get back '&' that wp_kses_post might have turned to '&amp;'
653 861 * this MUST be done, else we'll be back to the '& entity' problem.
654 862 *
655 863 * @since 4.0.04
@@ -683,10 +891,12 @@
683 891 $translation = array(
684 892 '&quot;' => '"',
685 893 '&#034;' => '"',
686 894 '&#x22;' => '"',
687 - '&lt; ' => '< ', // The space preserves the HTML.
688 - '&#060; ' => '< ', // The space preserves the HTML.
895 + // The space preserves the HTML.
896 + '&lt; ' => '< ',
897 + // The space preserves the HTML.
898 + '&#060; ' => '< ',
689 899 '&gt;' => '>',
690 900 '&#062;' => '>',
691 901 '&amp;' => '&',
692 902 '&#038;' => '&',
@@ -713,10 +923,10 @@
713 923 * Sanitize the value, and allow some HTML
714 924 *
715 925 * @since 2.0
716 926 *
717 - * @param string $value
718 - * @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.
719 929 *
720 930 * @return string
721 931 */
722 932 public static function kses( $value, $allowed = array() ) {
@@ -725,8 +935,21 @@
725 935 return wp_kses( $value, $allowed_html );
726 936 }
727 937
728 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 + /**
729 952 * The regular kses function strips [button_action] from submit button HTML.
730 953 *
731 954 * @since 5.0.13
732 955 *
@@ -817,9 +1040,9 @@
817 1040 'id' => true,
818 1041 );
819 1042
820 1043 return array(
821 - 'a' => array(
1044 + 'a' => array(
822 1045 'class' => true,
823 1046 'href' => true,
824 1047 'id' => true,
825 1048 'rel' => true,
@@ -888,16 +1111,16 @@
888 1111 'cite' => true,
889 1112 'title' => true,
890 1113 ),
891 1114 'rect' => array(
892 - 'class' => true,
893 - 'fill' => true,
894 - 'height' => true,
895 - 'width' => true,
896 - 'x' => true,
897 - 'y' => true,
898 - 'rx' => true,
899 - 'stroke' => true,
1115 + 'class' => true,
1116 + 'fill' => true,
1117 + 'height' => true,
1118 + 'width' => true,
1119 + 'x' => true,
1120 + 'y' => true,
1121 + 'rx' => true,
1122 + 'stroke' => true,
900 1123 'stroke-opacity' => true,
901 1124 'stroke-width' => true,
902 1125 ),
903 1126 'section' => $allow_class,
@@ -932,9 +1155,9 @@
932 1155 'xlink:href' => true,
933 1156 ),
934 1157 'ul' => $allow_class,
935 1158 'label' => array(
936 - 'for' => true,
1159 + 'for' => true,
937 1160 'class' => true,
938 1161 'id' => true,
939 1162 ),
940 1163 'button' => array(
@@ -943,8 +1166,13 @@
943 1166 ),
944 1167 'legend' => array(
945 1168 'class' => true,
946 1169 ),
1170 + 'option' => array(
1171 + 'class' => true,
1172 + 'value' => true,
1173 + 'selected' => true,
1174 + ),
947 1175 );
948 1176 }
949 1177
950 1178 /**
@@ -952,9 +1180,9 @@
952 1180 *
953 1181 * @since 2.0
954 1182 */
955 1183 public static function remove_get_action() {
956 - if ( ! isset( $_GET ) ) {
1184 + if ( empty( $_GET ) ) {
957 1185 return;
958 1186 }
959 1187
960 1188 $action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
@@ -971,9 +1199,9 @@
971 1199 /**
972 1200 * Check the WP query for a parameter
973 1201 *
974 1202 * @since 2.0
975 - * @return string|array
1203 + * @return array|string
976 1204 */
977 1205 public static function get_query_var( $value, $param ) {
978 1206 if ( $value != '' ) {
979 1207 return $value;
@@ -990,10 +1218,12 @@
990 1218 /**
991 1219 * Try to show the SVG if possible. Otherwise, use the font icon.
992 1220 *
993 1221 * @since 4.0.02
1222 + *
994 1223 * @param string $class
995 1224 * @param array $atts
1225 + * @return string|null
996 1226 */
997 1227 public static function icon_by_class( $class, $atts = array() ) {
998 1228 $echo = ! isset( $atts['echo'] ) || $atts['echo'];
999 1229 if ( isset( $atts['echo'] ) ) {
@@ -1003,14 +1233,16 @@
1003 1233 $html_atts = self::array_to_html_params( $atts );
1004 1234
1005 1235 $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
1006 1236
1007 - // Replace icons that have been removed.
1237 + // Replace icons that have been removed or renamed.
1008 1238 $deprecated = array(
1009 - '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',
1010 1242 );
1011 1243 if ( isset( $deprecated[ $icon ] ) ) {
1012 - $icon = $deprecated[ $icon ];
1244 + $icon = $deprecated[ $icon ];
1013 1245 $class = str_replace( $icon, $deprecated[ $icon ], $class );
1014 1246 }
1015 1247
1016 1248 if ( $icon === $class ) {
@@ -1020,11 +1252,9 @@
1020 1252 if ( strpos( $icon, ' ' ) ) {
1021 1253 $icon = explode( ' ', $icon );
1022 1254 $icon = reset( $icon );
1023 1255 }
1024 - $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '>
1025 - <use xlink:href="#' . esc_attr( $icon ) . '" />
1026 - </svg>';
1256 + $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use xlink:href="#' . esc_attr( $icon ) . '" /></svg>';
1027 1257 }
1028 1258
1029 1259 if ( $echo ) {
1030 1260 echo self::kses_icon( $icon ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
@@ -1110,11 +1340,18 @@
1110 1340 /**
1111 1341 * Include svg images.
1112 1342 *
1113 1343 * @since 4.0.02
1344 + * @return void
1114 1345 */
1115 1346 public static function include_svg() {
1116 - 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;
1117 1354 }
1118 1355
1119 1356 /**
1120 1357 * Convert an associative array to HTML values.
@@ -1126,9 +1363,9 @@
1126 1363 * @param bool $echo
1127 1364 * @return string|void
1128 1365 */
1129 1366 public static function array_to_html_params( $atts, $echo = false ) {
1130 - $callback = function() use ( $atts ) {
1367 + $callback = function () use ( $atts ) {
1131 1368 if ( $atts ) {
1132 1369 foreach ( $atts as $key => $value ) {
1133 1370 echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1134 1371 }
@@ -1143,9 +1380,9 @@
1143 1380 * @since 5.0.13
1144 1381 *
1145 1382 * @param Closure $echo_function
1146 1383 * @param bool $echo
1147 - * @return string|void
1384 + * @return string|null
1148 1385 */
1149 1386 public static function clip( $echo_function, $echo = false ) {
1150 1387 if ( ! $echo ) {
1151 1388 ob_start();
@@ -1163,12 +1400,15 @@
1163 1400 }
1164 1401
1165 1402 /**
1166 1403 * @since 3.0
1404 + *
1405 + * @param array $atts
1406 + * @return void
1167 1407 */
1168 1408 public static function get_admin_header( $atts ) {
1169 - $has_nav = ( isset( $atts['form'] ) && ! empty( $atts['form'] ) && ( ! isset( $atts['is_template'] ) || ! $atts['is_template'] ) );
1170 - if ( ! isset( $atts['close'] ) || empty( $atts['close'] ) ) {
1409 + $has_nav = ! empty( $atts['form'] ) && empty( $atts['is_template'] );
1410 + if ( empty( $atts['close'] ) ) {
1171 1411 $atts['close'] = admin_url( 'admin.php?page=formidable' );
1172 1412 }
1173 1413 if ( ! isset( $atts['import_link'] ) ) {
1174 1414 $atts['import_link'] = false;
@@ -1173,9 +1413,9 @@
1173 1413 if ( ! isset( $atts['import_link'] ) ) {
1174 1414 $atts['import_link'] = false;
1175 1415 }
1176 1416
1177 - include( self::plugin_path() . '/classes/views/shared/admin-header.php' );
1417 + include self::plugin_path() . '/classes/views/shared/admin-header.php';
1178 1418 }
1179 1419
1180 1420 /**
1181 1421 * @since 6.0
@@ -1204,9 +1444,9 @@
1204 1444 FrmInbox::maybe_show_banner();
1205 1445 return;
1206 1446 }
1207 1447
1208 - 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() ) {
1209 1449 // Print license warning or inbox banner and exit if either prints.
1210 1450 // And exit before printing the upgrade bar if it shouldn't be shown.
1211 1451 return;
1212 1452 }
@@ -1211,10 +1451,36 @@
1211 1451 return;
1212 1452 }
1213 1453 ?>
1214 1454 <div class="frm-upgrade-bar">
1215 - <span>You're using Formidable Forms Lite. To unlock more features consider</span>
1216 - <a href="<?php echo esc_url( self::admin_upgrade_link( 'top-bar' ) ); ?>" target="_blank" rel="noopener">upgrading to Pro</a>.
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>
1217 1483 </div>
1218 1484 <?php
1219 1485 }
1220 1486
@@ -1231,8 +1497,10 @@
1231 1497 * Render a button for a new item (Form, Application, etc).
1232 1498 *
1233 1499 * @since 3.0
1234 1500 * @param array $atts {
1501 + * Details about the button.
1502 + *
1235 1503 * @type array $link_hook Custom link hook, calls do_action and exits early.
1236 1504 * @type string $new_link Href value, default #.
1237 1505 * @type string $class Custom class names, space separated.
1238 1506 * @type string $button_text Button text. Default "Add New".
@@ -1244,9 +1512,9 @@
1244 1512 do_action( $atts['link_hook']['hook'], $atts['link_hook']['param'] );
1245 1513 return;
1246 1514 }
1247 1515
1248 - 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'] ) ) {
1249 1517 // Do not render a button if none of these attributes are set.
1250 1518 return;
1251 1519 }
1252 1520
@@ -1252,12 +1520,8 @@
1252 1520
1253 1521 $href = ! empty( $atts['new_link'] ) ? esc_url( $atts['new_link'] ) : '#';
1254 1522 $class = 'button button-primary frm-button-primary';
1255 1523
1256 - if ( ! empty( $atts['trigger_new_form_modal'] ) ) {
1257 - $class .= ' frm-trigger-new-form-modal';
1258 - }
1259 -
1260 1524 if ( ! empty( $atts['class'] ) ) {
1261 1525 $class .= ' ' . $atts['class'];
1262 1526 }
1263 1527
@@ -1274,10 +1538,11 @@
1274 1538 'placeholder' => '',
1275 1539 'tosearch' => '',
1276 1540 'text' => __( 'Search', 'formidable' ),
1277 1541 'input_id' => '',
1542 + 'value' => false,
1278 1543 );
1279 - $atts = array_merge( $defaults, $atts );
1544 + $atts = array_merge( $defaults, $atts );
1280 1545
1281 1546 if ( $atts['input_id'] === 'template' && empty( $atts['tosearch'] ) ) {
1282 1547 $atts['tosearch'] = 'frm-card';
1283 1548 }
@@ -1288,8 +1553,27 @@
1288 1553 }
1289 1554
1290 1555 $input_id = $atts['input_id'] . '-search-input';
1291 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 + }
1292 1576 ?>
1293 1577 <p class="frm-search">
1294 1578 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1295 1579 <?php echo esc_html( $atts['text'] ); ?>:
@@ -1294,15 +1578,9 @@
1294 1578 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1295 1579 <?php echo esc_html( $atts['text'] ); ?>:
1296 1580 </label>
1297 1581 <span class="frmfont frm_search_icon"></span>
1298 - <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
1299 - value="<?php _admin_search_query(); ?>" placeholder="<?php echo esc_attr( $atts['placeholder'] ); ?>"
1300 - class="<?php echo esc_attr( $class ); ?>" data-tosearch="<?php echo esc_attr( $atts['tosearch'] ); ?>"
1301 - <?php if ( ! empty( $atts['tosearch'] ) ) { ?>
1302 - autocomplete="off"
1303 - <?php } ?>
1304 - />
1582 + <input <?php self::array_to_html_params( $input_atts, true ); ?> />
1305 1583 <?php
1306 1584 if ( empty( $atts['tosearch'] ) ) {
1307 1585 submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
1308 1586 }
@@ -1312,8 +1590,9 @@
1312 1590 }
1313 1591
1314 1592 /**
1315 1593 * @param string $type
1594 + * @return void
1316 1595 */
1317 1596 public static function trigger_hook_load( $type, $object = null ) {
1318 1597 // Only load the form hooks once.
1319 1598 $hooks_loaded = apply_filters( 'frm_' . $type . '_hooks_loaded', false, $object );
@@ -1357,9 +1636,9 @@
1357 1636 'new_file_path' => self::plugin_path() . '/js',
1358 1637 )
1359 1638 );
1360 1639 $new_file = new FrmCreateFile( $file_atts );
1361 - $files = array(
1640 + $files = array(
1362 1641 FrmStrpLiteAppHelper::plugin_path() . 'js/frmstrp.min.js',
1363 1642 );
1364 1643
1365 1644 /**
@@ -1376,14 +1655,14 @@
1376 1655 * True when value is 1, true, 'true', 'yes'
1377 1656 *
1378 1657 * @since 1.07.10
1379 1658 *
1380 - * @param string $value The value to compare
1659 + * @param string $value The value to compare.
1381 1660 *
1382 - * @return boolean True or False
1661 + * @return bool
1383 1662 */
1384 1663 public static function is_true( $value ) {
1385 - return ( true === $value || 1 == $value || 'true' == $value || 'yes' == $value );
1664 + return true === $value || 1 == $value || 'true' === $value || 'yes' === $value;
1386 1665 }
1387 1666
1388 1667 /**
1389 1668 * Gets all post from a specific post type.
@@ -1441,9 +1720,9 @@
1441 1720 $args = self::preformat_selection_args( $args );
1442 1721
1443 1722 $pages_count = wp_count_posts( $args['post_type'] );
1444 1723
1445 - if ( $pages_count->publish <= 50 ) {
1724 + if ( ! isset( $pages_count->publish ) || $pages_count->publish <= 50 ) {
1446 1725 self::wp_pages_dropdown( $args );
1447 1726 return;
1448 1727 }
1449 1728
@@ -1449,9 +1728,9 @@
1449 1728
1450 1729 wp_enqueue_script( 'jquery-ui-autocomplete' );
1451 1730
1452 1731 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1453 - $title = '';
1732 + $title = '';
1454 1733
1455 1734 if ( $selected ) {
1456 1735 $title = get_the_title( $selected );
1457 1736 }
@@ -1467,18 +1746,112 @@
1467 1746 <?php
1468 1747 }
1469 1748
1470 1749 /**
1471 - * @param array $args
1472 - * @param string $page_id Deprecated.
1473 - * @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.
1474 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 + */
1475 1849 public static function wp_pages_dropdown( $args = array(), $page_id = '', $truncate = false ) {
1476 1850 self::prep_page_dropdown_params( $page_id, $truncate, $args );
1477 1851
1478 1852 $pages = self::get_post_ids_and_titles( $args['post_type'] );
1479 1853 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
1480 -
1481 1854 ?>
1482 1855 <select name="<?php echo esc_attr( $args['field_name'] ); ?>" id="<?php echo esc_attr( $args['field_name'] ); ?>" class="frm-pages-dropdown">
1483 1856 <option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
1484 1857 <?php foreach ( $pages as $page ) { ?>
@@ -1515,13 +1888,13 @@
1515 1888 * @since 4.10.01 Added `post_type` and `autocomplete_placeholder` to the arguments array.
1516 1889 */
1517 1890 private static function preformat_selection_args( $args ) {
1518 1891 $defaults = array(
1519 - 'truncate' => false,
1520 - 'placeholder' => ' ',
1521 - 'field_name' => '',
1522 - 'page_id' => '',
1523 - 'post_type' => 'page',
1892 + 'truncate' => false,
1893 + 'placeholder' => ' ',
1894 + 'field_name' => '',
1895 + 'page_id' => '',
1896 + 'post_type' => 'page',
1524 1897 'autocomplete_placeholder' => __( 'Select a Page', 'formidable' ),
1525 1898 );
1526 1899
1527 1900 return array_merge( $defaults, $args );
@@ -1592,25 +1965,16 @@
1592 1965 return self::is_admin_page( 'formidable-views-editor' );
1593 1966 }
1594 1967
1595 1968 /**
1596 - * @since 4.0
1597 - * @deprecated 5.5.3
1969 + * @param string $field_name
1970 + * @param array|string $capability
1971 + * @param string $multiple 'single' and 'multiple'.
1598 1972 */
1599 - public static function maybe_full_screen_link( $link ) {
1600 - _deprecated_function( __METHOD__, '5.5.3' );
1601 - return $link;
1602 - }
1603 -
1604 - /**
1605 - * @param string $field_name
1606 - * @param string|array $capability
1607 - * @param string $multiple 'single' and 'multiple'
1608 - */
1609 1973 public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
1610 1974 ?>
1611 1975 <select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
1612 - <?php echo ( 'multiple' === $multiple ) ? 'multiple="multiple"' : ''; ?>
1976 + <?php echo 'multiple' === $multiple ? 'multiple="multiple"' : ''; ?>
1613 1977 class="frm_multiselect">
1614 1978 <?php self::roles_options( $capability ); ?>
1615 1979 </select>
1616 1980 <?php
@@ -1618,9 +1982,9 @@
1618 1982
1619 1983 /**
1620 1984 * @since 4.07
1621 1985 * @param array|string $selected
1622 - * @param string $current
1986 + * @param string $current
1623 1987 */
1624 1988 private static function selected( $selected, $current ) {
1625 1989 if ( is_callable( 'FrmProAppHelper::selected' ) ) {
1626 1990 FrmProAppHelper::selected( $selected, $current );
@@ -1629,9 +1993,9 @@
1629 1993 }
1630 1994 }
1631 1995
1632 1996 /**
1633 - * @param string|array $capability
1997 + * @param array|string $capability
1634 1998 */
1635 1999 public static function roles_options( $capability ) {
1636 2000 global $frm_vars;
1637 2001 if ( isset( $frm_vars['editable_roles'] ) ) {
@@ -1643,9 +2007,9 @@
1643 2007
1644 2008 foreach ( $editable_roles as $role => $details ) {
1645 2009 $name = translate_user_role( $details['name'] );
1646 2010 ?>
1647 - <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>
1648 2012 <?php
1649 2013 unset( $role, $details );
1650 2014 }
1651 2015 }
@@ -1666,9 +2030,8 @@
1666 2030 $pro_cap = array(
1667 2031 'frm_create_entries' => __( 'Add Entries from Admin Area', 'formidable' ),
1668 2032 'frm_edit_entries' => __( 'Edit Entries from Admin Area', 'formidable' ),
1669 2033 'frm_view_reports' => __( 'View Reports', 'formidable' ),
1670 - 'frm_edit_displays' => __( 'Add/Edit Views', 'formidable' ),
1671 2034 );
1672 2035 /**
1673 2036 * @since 5.3.1
1674 2037 *
@@ -1675,8 +2038,14 @@
1675 2038 * @param array<string,string> $pro_cap
1676 2039 */
1677 2040 $pro_cap = apply_filters( 'frm_pro_capabilities', $pro_cap );
1678 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 +
1679 2048 if ( 'pro_only' === $type ) {
1680 2049 return $pro_cap;
1681 2050 }
1682 2051
@@ -1691,9 +2060,9 @@
1691 2060 * @return array<string,string>
1692 2061 */
1693 2062 private static function get_lite_capabilities() {
1694 2063 return array(
1695 - 'frm_view_forms' => __( 'View Forms', 'formidable' ),
2064 + 'frm_view_forms' => __( 'View Forms List', 'formidable' ),
1696 2065 'frm_edit_forms' => __( 'Add and Edit Forms', 'formidable' ),
1697 2066 'frm_delete_forms' => __( 'Delete Forms', 'formidable' ),
1698 2067 'frm_change_settings' => __( 'Access this Settings Page', 'formidable' ),
1699 2068 'frm_view_entries' => __( 'View Entries from Admin Area', 'formidable' ),
@@ -1734,9 +2103,9 @@
1734 2103 return current_user_can( $role );
1735 2104 }
1736 2105
1737 2106 /**
1738 - * @param string|array $needed_role
2107 + * @param array|string $needed_role
1739 2108 * @return bool
1740 2109 */
1741 2110 public static function user_has_permission( $needed_role ) {
1742 2111 if ( is_array( $needed_role ) ) {
@@ -1792,8 +2161,11 @@
1792 2161 /**
1793 2162 * Make sure admins have permission to see the menu items
1794 2163 *
1795 2164 * @since 2.0.6
2165 + *
2166 + * @param string $cap
2167 + * @return void
1796 2168 */
1797 2169 public static function force_capability( $cap = 'frm_change_settings' ) {
1798 2170 if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
1799 2171 $role = get_role( 'administrator' );
@@ -1804,9 +2176,9 @@
1804 2176 }
1805 2177 }
1806 2178
1807 2179 /**
1808 - * Check if the user has permision for action.
2180 + * Check if the user has permission for action.
1809 2181 * Return permission message and stop the action if no permission
1810 2182 *
1811 2183 * @since 2.0
1812 2184 *
@@ -1842,9 +2214,9 @@
1842 2214 if ( empty( $nonce_name ) ) {
1843 2215 return $error;
1844 2216 }
1845 2217
1846 - $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 ] ) ) : '';
1847 2219 if ( $_REQUEST && ( ! isset( $_REQUEST[ $nonce_name ] ) || ! wp_verify_nonce( $nonce_value, $nonce ) ) ) {
1848 2220 $frm_settings = self::get_settings();
1849 2221 $error = $frm_settings->admin_permission;
1850 2222 }
@@ -1858,12 +2230,13 @@
1858 2230 }
1859 2231 }
1860 2232
1861 2233 public static function check_selected( $values, $current ) {
1862 - $values = self::recursive_function_map( $values, 'trim' );
1863 - $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1864 - $current = htmlspecialchars_decode( trim( $current ) );
2234 + $values = self::recursive_function_map( $values, 'trim' );
2235 + $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
1865 2236
2237 + $current = is_null( $current ) ? '' : htmlspecialchars_decode( trim( $current ) );
2238 +
1866 2239 return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
1867 2240 }
1868 2241
1869 2242 public static function recursive_function_map( $value, $function ) {
@@ -1883,8 +2256,9 @@
1883 2256 }
1884 2257 }
1885 2258 }
1886 2259 } else {
2260 + $value = self::maybe_update_value_if_null( $value, $function );
1887 2261 $value = call_user_func( $function, $value );
1888 2262 }
1889 2263
1890 2264 return $value;
@@ -1889,8 +2263,24 @@
1889 2263
1890 2264 return $value;
1891 2265 }
1892 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 +
1893 2283 public static function is_assoc( $array ) {
1894 2284 return (bool) count( array_filter( array_keys( $array ), 'is_string' ) );
1895 2285 }
1896 2286
@@ -1901,14 +2291,12 @@
1901 2291 $return = array();
1902 2292 foreach ( $array as $key => $value ) {
1903 2293 if ( is_array( $value ) ) {
1904 2294 $return = array_merge( $return, self::array_flatten( $value, $keys ) );
2295 + } elseif ( $keys === 'keep' ) {
2296 + $return[ $key ] = $value;
1905 2297 } else {
1906 - if ( $keys === 'keep' ) {
1907 - $return[ $key ] = $value;
1908 - } else {
1909 - $return[] = $value;
1910 - }
2298 + $return[] = $value;
1911 2299 }
1912 2300 }
1913 2301
1914 2302 return $return;
@@ -1913,8 +2301,27 @@
1913 2301
1914 2302 return $return;
1915 2303 }
1916 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 + */
1917 2324 public static function esc_textarea( $text, $is_rich_text = false ) {
1918 2325 $safe_text = str_replace( '&quot;', '"', $text );
1919 2326 if ( ! $is_rich_text ) {
1920 2327 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
@@ -1920,9 +2327,13 @@
1920 2327 $safe_text = htmlspecialchars( $safe_text, ENT_NOQUOTES );
1921 2328 }
1922 2329 $safe_text = str_replace( '&amp; ', '& ', $safe_text );
1923 2330
1924 - 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 );
1925 2336 }
1926 2337
1927 2338 /**
1928 2339 * Add auto paragraphs to text areas
@@ -1929,9 +2340,9 @@
1929 2340 *
1930 2341 * @since 2.0
1931 2342 */
1932 2343 public static function use_wpautop( $content ) {
1933 - if ( apply_filters( 'frm_use_wpautop', true ) && ! is_array( $content ) ) {
2344 + if ( apply_filters( 'frm_use_wpautop', true ) && is_string( $content ) ) {
1934 2345 $content = wpautop( str_replace( '<br>', '<br />', $content ) );
1935 2346 }
1936 2347
1937 2348 return $content;
@@ -1973,12 +2384,12 @@
1973 2384 * @since 5.0.13 added $echo param.
1974 2385 *
1975 2386 * @param string $url
1976 2387 * @param bool $echo
1977 - * @return string|void
2388 + * @return string|null
1978 2389 */
1979 2390 public static function js_redirect( $url, $echo = false ) {
1980 - $callback = function() use ( $url ) {
2391 + $callback = function () use ( $url ) {
1981 2392 echo '<script type="text/javascript">window.location="' . esc_url_raw( $url ) . '"</script>';
1982 2393 };
1983 2394 return self::clip( $callback, $echo );
1984 2395 }
@@ -2006,8 +2417,13 @@
2006 2417
2007 2418 return $user_id;
2008 2419 }
2009 2420
2421 + /**
2422 + * @param string $filename
2423 + * @param array $atts
2424 + * @return false|string
2425 + */
2010 2426 public static function get_file_contents( $filename, $atts = array() ) {
2011 2427 if ( ! is_file( $filename ) ) {
2012 2428 return false;
2013 2429 }
@@ -2013,9 +2429,9 @@
2013 2429 }
2014 2430
2015 2431 extract( $atts ); // phpcs:ignore WordPress.PHP.DontExtract
2016 2432 ob_start();
2017 - include( $filename );
2433 + include $filename;
2018 2434 $contents = ob_get_contents();
2019 2435 ob_end_clean();
2020 2436
2021 2437 return $contents;
@@ -2070,9 +2486,9 @@
2070 2486 ++$suffix;
2071 2487 } while ( in_array( $key_check, $similar_keys, true ) );
2072 2488
2073 2489 $key = $key_check;
2074 - }
2490 + }//end if
2075 2491
2076 2492 return $key;
2077 2493 }
2078 2494
@@ -2111,14 +2527,18 @@
2111 2527 return $key;
2112 2528 }
2113 2529
2114 2530 /**
2531 + * @since 6.21 This is changed from `private` to `public`.
2532 + *
2115 2533 * @param int $num_chars
2116 2534 * @return string
2117 2535 */
2118 - private static function generate_new_key( $num_chars ) {
2536 + public static function generate_new_key( $num_chars ) {
2119 2537 $max_slug_value = pow( 36, $num_chars );
2120 - $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;
2121 2541 return base_convert( rand( $min_slug_value, $max_slug_value ), 10, 36 );
2122 2542 }
2123 2543
2124 2544 /**
@@ -2147,11 +2567,16 @@
2147 2567
2148 2568 /**
2149 2569 * Editing a Form or Entry
2150 2570 *
2151 - * @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
2152 2577 *
2153 - * @return bool|array
2578 + * @return array|bool
2154 2579 */
2155 2580 public static function setup_edit_vars( $record, $table, $fields = '', $default = false, $post_values = array(), $args = array() ) {
2156 2581 if ( ! $record ) {
2157 2582 return false;
@@ -2204,13 +2629,12 @@
2204 2629 $post_values = $args['post_values'];
2205 2630
2206 2631 if ( $args['default'] ) {
2207 2632 $meta_value = $field->default_value;
2208 - } else {
2209 - if ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2210 - if ( ! isset( $field->field_options['custom_field'] ) ) {
2211 - $field->field_options['custom_field'] = '';
2212 - }
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 + }
2213 2637 $meta_value = FrmProEntryMetaHelper::get_post_value(
2214 2638 $record->post_id,
2215 2639 $field->field_options['post_field'],
2216 2640 $field->field_options['custom_field'],
@@ -2220,12 +2644,11 @@
2220 2644 'form_id' => $field->form_id,
2221 2645 'field' => $field,
2222 2646 )
2223 2647 );
2224 - } else {
2225 - $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2226 - }
2227 - }
2648 + } else {
2649 + $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2650 + }//end if
2228 2651
2229 2652 $field_type = isset( $post_values['field_options'][ 'type_' . $field->id ] ) ? $post_values['field_options'][ 'type_' . $field->id ] : $field->type;
2230 2653 if ( isset( $post_values['item_meta'][ $field->id ] ) ) {
2231 2654 $new_value = $post_values['item_meta'][ $field->id ];
@@ -2273,12 +2696,15 @@
2273 2696 );
2274 2697 }
2275 2698
2276 2699 /**
2700 + * @param object $record
2277 2701 * @param string $table
2702 + * @param array $post_values
2703 + * @param array $values
2278 2704 */
2279 2705 private static function fill_form_opts( $record, $table, $post_values, array &$values ) {
2280 - if ( $table == 'entries' ) {
2706 + if ( $table === 'entries' ) {
2281 2707 $form = $record->form_id;
2282 2708 FrmForm::maybe_get_form( $form );
2283 2709 } else {
2284 2710 $form = $record;
@@ -2314,9 +2740,9 @@
2314 2740 $form_defaults = FrmFormsHelper::get_default_opts();
2315 2741
2316 2742 foreach ( $form_defaults as $opt => $default ) {
2317 2743 if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
2318 - $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;
2319 2745 }
2320 2746
2321 2747 unset( $opt, $default );
2322 2748 }
@@ -2337,9 +2763,9 @@
2337 2763 * @since 2.2.10
2338 2764 *
2339 2765 * @param array $post_values
2340 2766 *
2341 - * @return boolean|int
2767 + * @return bool|int
2342 2768 */
2343 2769 public static function custom_style_value( $post_values ) {
2344 2770 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2345 2771 $custom_style = absint( $post_values['options']['custom_style'] );
@@ -2344,29 +2770,37 @@
2344 2770 if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
2345 2771 $custom_style = absint( $post_values['options']['custom_style'] );
2346 2772 } else {
2347 2773 $frm_settings = self::get_settings();
2348 - $custom_style = ( $frm_settings->load_style != 'none' );
2774 + $custom_style = ( $frm_settings->load_style !== 'none' );
2349 2775 }
2350 2776
2351 2777 return $custom_style;
2352 2778 }
2353 2779
2354 - public static function truncate( $str, $length, $minword = 3, $continue = '...' ) {
2355 - 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 ) ) {
2356 2789 return '';
2357 2790 }
2358 2791
2359 2792 $length = (int) $length;
2360 - $str = wp_strip_all_tags( $str );
2793 + $str = wp_strip_all_tags( (string) $original_string );
2361 2794 $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
2362 2795
2363 2796 if ( $length == 0 ) {
2364 2797 return '';
2365 - } elseif ( $length <= 10 ) {
2798 + }
2799 +
2800 + if ( $length <= 10 ) {
2366 2801 $sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
2367 -
2368 - return $sub . ( ( $length < $original_len ) ? $continue : '' );
2802 + return $sub . ( $length < $original_len ? $continue : '' );
2369 2803 }
2370 2804
2371 2805 $sub = '';
2372 2806 $len = 0;
@@ -2372,10 +2806,14 @@
2372 2806 $len = 0;
2373 2807
2374 2808 $words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
2375 2809
2810 + if ( ! is_array( $words ) ) {
2811 + return $original_string;
2812 + }
2813 +
2376 2814 foreach ( $words as $word ) {
2377 - $part = ( ( $sub != '' ) ? ' ' : '' ) . $word;
2815 + $part = ( $sub != '' ? ' ' : '' ) . $word;
2378 2816 $total_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub . $part ) );
2379 2817 if ( $total_len > $length && substr_count( $sub, ' ' ) ) {
2380 2818 break;
2381 2819 }
@@ -2389,11 +2827,37 @@
2389 2827
2390 2828 unset( $total_len, $word );
2391 2829 }
2392 2830
2393 - 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 : '' );
2394 2834 }
2395 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 +
2396 2860 public static function mb_function( $function_names, $args ) {
2397 2861 $mb_function_name = $function_names[0];
2398 2862 $function_name = $function_names[1];
2399 2863 if ( function_exists( $mb_function_name ) ) {
@@ -2426,8 +2890,13 @@
2426 2890
2427 2891 return $formatted;
2428 2892 }
2429 2893
2894 + /**
2895 + * @param string $time_format
2896 + * @param string $date
2897 + * @return string
2898 + */
2430 2899 private static function add_time_to_date( $time_format, $date ) {
2431 2900 if ( empty( $time_format ) ) {
2432 2901 $time_format = get_option( 'time_format' );
2433 2902 }
@@ -2450,12 +2919,12 @@
2450 2919 return date_i18n( $date_format, strtotime( $date ) );
2451 2920 }
2452 2921
2453 2922 /**
2454 - * Gets the time ago in words
2923 + * Gets the time ago in words.
2455 2924 *
2456 - * @param int $from in seconds
2457 - * @param int|string $to in seconds
2925 + * @param int $from In seconds.
2926 + * @param int|string $to In seconds.
2458 2927 *
2459 2928 * @return string $time_ago
2460 2929 */
2461 2930 public static function human_time_diff( $from, $to = '', $levels = 1 ) {
@@ -2470,9 +2939,9 @@
2470 2939 $diff_object = $now->diff( $ago );
2471 2940 $diff = get_object_vars( $diff_object );
2472 2941
2473 2942 // Add week amount and update day amount
2474 - $diff['w'] = floor( $diff['d'] / 7 );
2943 + $diff['w'] = floor( $diff['d'] / 7 );
2475 2944 $diff['d'] -= $diff['w'] * 7;
2476 2945
2477 2946 $time_strings = self::get_time_strings();
2478 2947
@@ -2479,9 +2948,9 @@
2479 2948 if ( ! is_numeric( $levels ) ) {
2480 2949 // Show time in specified unit.
2481 2950 $levels = self::get_unit( $levels );
2482 2951 if ( isset( $time_strings[ $levels ] ) ) {
2483 - $diff = array(
2952 + $diff = array(
2484 2953 $levels => self::time_format( $levels, $diff ),
2485 2954 );
2486 2955 $time_strings = array(
2487 2956 $levels => $time_strings[ $levels ],
@@ -2570,9 +3039,9 @@
2570 3039 }
2571 3040
2572 3041 /**
2573 3042 * Get the translatable time strings. The untranslated version is a failsafe
2574 - * 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.
2575 3044 *
2576 3045 * @since 2.0.20
2577 3046 * @return array
2578 3047 */
@@ -2618,23 +3087,28 @@
2618 3087
2619 3088 // Pagination Methods.
2620 3089
2621 3090 /**
2622 - * @param integer $current_p
3091 + * @param int $r_count
3092 + * @param int $current_p
3093 + * @param int $p_size
3094 + * @return int
2623 3095 */
2624 3096 public static function get_last_record_num( $r_count, $current_p, $p_size ) {
2625 - return ( ( $r_count < ( $current_p * $p_size ) ) ? $r_count : ( $current_p * $p_size ) );
3097 + return ( $r_count < $current_p * $p_size ? $r_count : $current_p * $p_size );
2626 3098 }
2627 3099
2628 3100 /**
2629 - * @param integer $current_p
3101 + * @param int $r_count
3102 + * @param int $current_p
3103 + * @param int $p_size
3104 + * @return int
2630 3105 */
2631 3106 public static function get_first_record_num( $r_count, $current_p, $p_size ) {
2632 3107 if ( $current_p == 1 ) {
2633 3108 return 1;
2634 - } else {
2635 - return ( self::get_last_record_num( $r_count, ( $current_p - 1 ), $p_size ) + 1 );
2636 3109 }
3110 + return self::get_last_record_num( $r_count, $current_p - 1, $p_size ) + 1;
2637 3111 }
2638 3112
2639 3113 /**
2640 3114 * @return array
@@ -2657,9 +3131,9 @@
2657 3131 if ( ! isset( $l3 ) ) {
2658 3132 $l3 = $name;
2659 3133 }
2660 3134
2661 - $this_val = ( $p == $last ) ? $jv['value'] : array();
3135 + $this_val = $p == $last ? $jv['value'] : array();
2662 3136
2663 3137 switch ( $p ) {
2664 3138 case 0:
2665 3139 $l1 = $name;
@@ -2681,12 +3155,12 @@
2681 3155 self::add_value_to_array( $name, $l4, $this_val, $vars[ $l1 ][ $l2 ][ $l3 ] );
2682 3156 }
2683 3157
2684 3158 unset( $this_val, $n );
2685 - }
3159 + }//end foreach
2686 3160
2687 3161 unset( $last, $jv );
2688 - }
3162 + }//end foreach
2689 3163
2690 3164 return $vars;
2691 3165 }
2692 3166
@@ -2934,8 +3408,11 @@
2934 3408 }
2935 3409
2936 3410 /**
2937 3411 * @since 4.02.03
3412 + *
3413 + * @param array|string $value
3414 + * @return string
2938 3415 */
2939 3416 public static function maybe_json_encode( $value ) {
2940 3417 if ( is_array( $value ) ) {
2941 3418 $value = wp_json_encode( $value );
@@ -2943,12 +3420,14 @@
2943 3420 return $value;
2944 3421 }
2945 3422
2946 3423 /**
3424 + * Echo The javascript to open and highlight the Formidable menu
3425 + *
2947 3426 * @since 1.07.10
2948 3427 *
2949 - * @param string $post_type The name of the post type that may need to be highlighted
2950 - * echo The javascript to open and highlight the Formidable menu
3428 + * @param string $post_type The name of the post type that may need to be highlighted.
3429 + * @return void
2951 3430 */
2952 3431 public static function maybe_highlight_menu( $post_type ) {
2953 3432 global $post;
2954 3433
@@ -2967,8 +3446,11 @@
2967 3446 /**
2968 3447 * Load the JS file on non-Formidable pages in the admin area
2969 3448 *
2970 3449 * @since 2.0
3450 + *
3451 + * @param bool $load
3452 + * @return void
2971 3453 */
2972 3454 public static function load_admin_wide_js( $load = true ) {
2973 3455 $version = self::plugin_version();
2974 3456 wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
@@ -2982,8 +3464,9 @@
2982 3464 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ),
2983 3465 'loading' => __( 'Loading&hellip;', 'formidable' ),
2984 3466 'nonce' => wp_create_nonce( 'frm_ajax' ),
2985 3467 'proIncludesSliderJs' => is_callable( 'FrmProFormsHelper::prepare_custom_currency' ),
3468 + 'inboxSlideIn' => FrmInbox::get_inbox_slide_in_value_for_js(),
2986 3469 );
2987 3470 wp_localize_script( 'formidable_admin_global', 'frmGlobal', $global_strings );
2988 3471
2989 3472 if ( $load ) {
@@ -2992,8 +3475,9 @@
2992 3475 }
2993 3476
2994 3477 /**
2995 3478 * @since 2.0.9
3479 + * @return void
2996 3480 */
2997 3481 public static function load_font_style() {
2998 3482 wp_enqueue_style( 'frm_fonts', self::plugin_url() . '/css/frm_fonts.css', array(), self::plugin_version() );
2999 3483 }
@@ -2999,26 +3483,29 @@
2999 3483 }
3000 3484
3001 3485 /**
3002 3486 * @param string $location
3487 + * @return void
3003 3488 */
3004 3489 public static function localize_script( $location ) {
3005 - global $wp_scripts;
3490 + global $wp_scripts, $wp_version;
3006 3491
3007 3492 $script_strings = array(
3008 - 'ajax_url' => esc_url_raw( self::get_ajax_url() ),
3009 - 'images_url' => self::plugin_url() . '/images',
3010 - 'loading' => __( 'Loading&hellip;', 'formidable' ),
3011 - 'remove' => __( 'Remove', 'formidable' ),
3012 - 'offset' => apply_filters( 'frm_scroll_offset', 4 ),
3013 - 'nonce' => wp_create_nonce( 'frm_ajax' ),
3014 - 'id' => __( 'ID', 'formidable' ),
3015 - 'no_results' => __( 'No results match', 'formidable' ),
3016 - 'file_spam' => __( 'That file looks like Spam.', 'formidable' ),
3017 - 'calc_error' => __( 'There is an error in the calculation in the field with key', 'formidable' ),
3018 - 'empty_fields' => __( 'Please complete the preceding required fields before uploading a file.', 'formidable' ),
3019 - 'focus_first_error' => self::should_focus_first_error(),
3020 - 'include_alert_role' => self::should_include_alert_role_on_field_errors(),
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,
3021 3508 );
3022 3509
3023 3510 $data = $wp_scripts->get_data( 'formidable', 'data' );
3024 3511 if ( ! $data ) {
@@ -3025,59 +3512,74 @@
3025 3512 wp_localize_script( 'formidable', 'frm_js', $script_strings );
3026 3513 }
3027 3514
3028 3515 if ( $location === 'admin' ) {
3029 - $frm_settings = self::get_settings();
3030 3516 $admin_script_strings = array(
3031 - 'desc' => __( '(Click to add description)', 'formidable' ),
3032 - 'blank' => __( '(Blank)', 'formidable' ),
3033 - 'no_label' => __( '(no label)', 'formidable' ),
3034 - 'ok' => __( 'OK', 'formidable' ),
3035 - 'cancel' => __( 'Cancel', 'formidable' ),
3036 - 'default_label' => __( 'Default', 'formidable' ),
3037 - 'clear_default' => __( 'Clear default value when typing', 'formidable' ),
3038 - 'no_clear_default' => __( 'Do not clear default value when typing', 'formidable' ),
3039 - 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3040 - 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3041 - 'confirm' => __( 'Are you sure?', 'formidable' ),
3042 - 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3043 - 'conf_delete_sec' => __( 'All fields inside this Section will be deleted along with their data. Are you sure you want to delete this group of fields?', 'formidable' ),
3044 - 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3045 - 'default_unique' => $frm_settings->unique_msg,
3046 - 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3047 - 'enter_email' => __( 'Enter Email', 'formidable' ),
3048 - 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3049 - 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3050 - 'new_option' => __( 'New Option', 'formidable' ),
3051 - 'css_invalid_size' => __( 'In certain browsers (e.g. Firefox) text will not display correctly if the field height is too small relative to the field padding and text size. Please increase your field height or decrease your field padding.', 'formidable' ),
3052 - 'enter_password' => __( 'Enter Password', 'formidable' ),
3053 - 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3054 - 'import_complete' => __( 'Import Complete', 'formidable' ),
3055 - 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
3056 - 'no_save_warning' => __( 'Warning: There is no way to retrieve unsaved entries.', 'formidable' ),
3057 - 'private_label' => __( 'Private', 'formidable' ),
3058 - 'jquery_ui_url' => '',
3059 - 'pro_url' => is_callable( 'FrmProAppHelper::plugin_url' ) ? FrmProAppHelper::plugin_url() : '',
3060 - 'no_licenses' => __( 'No new licenses were found', 'formidable' ),
3061 - 'unmatched_parens' => __( 'This calculation has at least one unmatched ( ) { } [ ].', 'formidable' ),
3062 - 'view_shortcodes' => __( 'This calculation may have shortcodes that work in Views but not forms.', 'formidable' ),
3063 - 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3064 - 'only_one_action' => __( 'This form action is limited to one per form. Please edit the existing form action.', 'formidable' ),
3065 - 'unsafe_params' => FrmFormsHelper::reserved_words(),
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(),
3066 3554 /* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
3067 - 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3555 + 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3068 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. */
3069 - 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3070 - 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3071 - 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3072 - 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3073 - 'install' => __( 'Install', 'formidable' ),
3074 - 'active' => __( 'Active', 'formidable' ),
3075 - 'select_a_field' => __( 'Select a Field', 'formidable' ),
3076 - 'no_items_found' => __( 'No items found.', 'formidable' ),
3077 - 'field_already_used' => __( 'Oops. You have already used that field.', 'formidable' ),
3078 - 'saving' => '', // Deprecated in 6.0.
3079 - 'saved' => '', // Deprecated in 6.0.
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', '>=' ),
3080 3582 );
3081 3583 /**
3082 3584 * @param array $admin_script_strings
3083 3585 */
@@ -3086,9 +3588,9 @@
3086 3588 $data = $wp_scripts->get_data( 'formidable_admin', 'data' );
3087 3589 if ( ! $data ) {
3088 3590 wp_localize_script( 'formidable_admin', 'frm_admin_js', $admin_script_strings );
3089 3591 }
3090 - }
3592 + }//end if
3091 3593 }
3092 3594
3093 3595 /**
3094 3596 * @since 6.5
@@ -3132,9 +3634,10 @@
3132 3634 * Echo the message on the plugins listing page
3133 3635 *
3134 3636 * @since 1.07.10
3135 3637 *
3136 - * @param float $min_version The version the add-on requires
3638 + * @param float $min_version The version the add-on requires.
3639 + * @return void
3137 3640 */
3138 3641 public static function min_version_notice( $min_version ) {
3139 3642 $frm_version = self::plugin_version();
3140 3643
@@ -3168,9 +3671,8 @@
3168 3671 if ( ! $is_pro || self::meets_min_pro_version( $min_version ) ) {
3169 3672 return;
3170 3673 }
3171 3674
3172 - $pro_version = FrmProDb::$plug_version;
3173 3675 $expired = FrmAddonsController::is_license_expired();
3174 3676 ?>
3175 3677 <div class="frm-banner-alert frm_error_style frm_previous_install">
3176 3678 <?php
@@ -3188,8 +3690,11 @@
3188 3690 /**
3189 3691 * If Pro is installed, check the version number.
3190 3692 *
3191 3693 * @since 4.0.01
3694 + *
3695 + * @param string $min_version
3696 + * @return bool
3192 3697 */
3193 3698 public static function meets_min_pro_version( $min_version ) {
3194 3699 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3195 3700 }
@@ -3194,24 +3699,19 @@
3194 3699 return ! class_exists( 'FrmProDb' ) || version_compare( FrmProDb::$plug_version, $min_version, '>=' );
3195 3700 }
3196 3701
3197 3702 /**
3198 - * 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.
3199 3704 *
3200 3705 * @since 4.0.02
3706 + * @return void
3201 3707 */
3202 3708 private static function php_version_notice() {
3203 3709 $message = array();
3204 - if ( version_compare( phpversion(), '5.6', '<' ) ) {
3710 + if ( version_compare( phpversion(), '7.0', '<' ) ) {
3205 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' );
3206 3712 }
3207 3713
3208 - $browser = self::get_server_value( 'HTTP_USER_AGENT' );
3209 - $is_ie = strpos( $browser, 'MSIE' ) !== false;
3210 - if ( $is_ie ) {
3211 - $message[] = __( 'You are using an outdated browser that is not compatible with Formidable Forms. Please update to a more current browser (we recommend Chrome).', 'formidable' );
3212 - }
3213 -
3214 3714 foreach ( $message as $m ) {
3215 3715 ?>
3216 3716 <div class="frm-banner-alert frm_error_style frm_previous_install">
3217 3717 <?php echo esc_html( $m ); ?>
@@ -3341,16 +3841,10 @@
3341 3841 return $locales;
3342 3842 }
3343 3843
3344 3844 /**
3345 - * Output HTML containing reference text for accessibility
3346 - *
3347 - * @deprecated 5.1
3845 + * @return string
3348 3846 */
3349 - public static function multiselect_accessibility() {
3350 - _deprecated_function( __METHOD__, '5.1' );
3351 - }
3352 -
3353 3847 public static function get_menu_icon_class() {
3354 3848 if ( is_callable( 'FrmProAppHelper::get_settings' ) ) {
3355 3849 $settings = FrmProAppHelper::get_settings();
3356 3850 if ( is_object( $settings ) && ! empty( $settings->menu_icon ) ) {
@@ -3460,8 +3954,18 @@
3460 3954 return apply_filters( 'frm_images_dropdown_input_attrs', $input_attrs_str, $args );
3461 3955 }
3462 3956
3463 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 + /**
3464 3968 * Gets the image of each option in images_dropdown() method.
3465 3969 *
3466 3970 * @since 5.0.04
3467 3971 *
@@ -3472,9 +3976,9 @@
3472 3976 private static function get_images_dropdown_option_image( $option, $args ) {
3473 3977 $image = self::icon_by_class(
3474 3978 'frmfont ' . $option['svg'],
3475 3979 array(
3476 - 'echo' => false,
3980 + 'echo' => false,
3477 3981 )
3478 3982 );
3479 3983
3480 3984 $args['option'] = $option;
@@ -3612,15 +4116,15 @@
3612 4116 return $values;
3613 4117 }
3614 4118
3615 4119 /**
3616 - * Some back end fields allow privleged users to add scripts.
4120 + * Some back end fields allow privileged users to add scripts.
3617 4121 * A site that uses the DISALLOW_UNFILTERED_HTML always remove scripts on echo.
3618 4122 *
3619 4123 * @since 5.0.13
3620 4124 *
3621 4125 * @param string $value
3622 - * @param array|string $allowed 'all' for everything included as defaults
4126 + * @param array|string $allowed 'all' for everything included as defaults.
3623 4127 * @return string
3624 4128 */
3625 4129 public static function maybe_kses( $value, $allowed = 'all' ) {
3626 4130 if ( self::should_never_allow_unfiltered_html() ) {
@@ -3629,8 +4133,64 @@
3629 4133 return $value;
3630 4134 }
3631 4135
3632 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 + /**
3633 4193 * @since 5.0.16
3634 4194 *
3635 4195 * @return bool
3636 4196 */
@@ -3655,20 +4215,9 @@
3655 4215
3656 4216 /**
3657 4217 * @since 5.0.17
3658 4218 *
3659 - * @param string $plugin
3660 - * @return string|false
3661 - */
3662 - private static function get_plan_required( $plugin ) {
3663 - $link = FrmAddonsController::install_link( $plugin );
3664 - return FrmFormsHelper::get_plan_required( $link );
3665 - }
3666 -
3667 - /**
3668 - * @since 5.0.17
3669 - *
3670 - * @param string
4219 + * @param string $feature
3671 4220 * @return bool
3672 4221 */
3673 4222 public static function show_new_feature( $feature ) {
3674 4223 $link = FrmAddonsController::install_link( $feature );
@@ -3741,9 +4290,9 @@
3741 4290 public static function show_pill_text( $text = null ) {
3742 4291 if ( null === $text ) {
3743 4292 $text = __( 'NEW', 'formidable' );
3744 4293 }
3745 - echo '<span class="frm-new-pill">' . esc_html( $text ) . '</span>';
4294 + echo '<span class="frm-meta-tag frm-new-pill">' . esc_html( $text ) . '</span>';
3746 4295 }
3747 4296
3748 4297 /**
3749 4298 * Count the number of decimals digits.
@@ -3750,9 +4299,9 @@
3750 4299 *
3751 4300 * @since 5.2.07
3752 4301 *
3753 4302 * @param mixed $num Number.
3754 - * @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.
3755 4304 */
3756 4305 public static function count_decimals( $num ) {
3757 4306 if ( ! is_numeric( $num ) ) {
3758 4307 return false;
@@ -3783,9 +4332,9 @@
3783 4332 }
3784 4333
3785 4334 add_filter(
3786 4335 'option_gmt_offset',
3787 - function( $offset ) {
4336 + function ( $offset ) {
3788 4337 if ( ! is_string( $offset ) || is_numeric( $offset ) ) {
3789 4338 // Leave a valid value alone.
3790 4339 return $offset;
3791 4340 }
@@ -3867,65 +4416,8 @@
3867 4416 return true;
3868 4417 }
3869 4418
3870 4419 /**
3871 - * @since 4.08
3872 - * @deprecated 4.09.01
3873 - */
3874 - public static function expiring_message() {
3875 - _deprecated_function( __METHOD__, '4.09.01', 'FrmProAddonsController::expiring_message' );
3876 - if ( is_callable( 'FrmProAddonsController::expiring_message' ) ) {
3877 - FrmProAddonsController::expiring_message();
3878 - }
3879 - }
3880 -
3881 - /**
3882 - * Use the WP 4.7 wp_doing_ajax function
3883 - *
3884 - * @since 2.05.07
3885 - * @deprecated 4.04.04
3886 - */
3887 - public static function wp_doing_ajax() {
3888 - _deprecated_function( __METHOD__, '4.04.04', 'wp_doing_ajax' );
3889 - return wp_doing_ajax();
3890 - }
3891 -
3892 - /**
3893 - * @deprecated 4.0
3894 - */
3895 - public static function insert_opt_html( $args ) {
3896 - _deprecated_function( __METHOD__, '4.0', 'FrmFormsHelper::insert_opt_html' );
3897 - FrmFormsHelper::insert_opt_html( $args );
3898 - }
3899 -
3900 - /**
3901 - * @deprecated 3.01
3902 - * @codeCoverageIgnore
3903 - */
3904 - public static function sanitize_array( &$values ) {
3905 - FrmDeprecated::sanitize_array( $values );
3906 - }
3907 -
3908 - /**
3909 - * @since 2.0
3910 - * @deprecated 5.0.13
3911 - *
3912 - * @return string The base Google APIS url for the current version of jQuery UI
3913 - */
3914 - public static function jquery_ui_base_url() {
3915 - _deprecated_function( __FUNCTION__, '5.0.13', 'FrmProAppHelper::jquery_ui_base_url' );
3916 - return is_callable( 'FrmProAppHelper::jquery_ui_base_url' ) ? FrmProAppHelper::jquery_ui_base_url() : '';
3917 - }
3918 -
3919 - /**
3920 - * @since 4.07
3921 - * @deprecated 6.0
3922 - */
3923 - public static function renewal_message() {
3924 - _deprecated_function( __METHOD__, '6.0', 'FrmProAddonsController::renewal_message' );
3925 - }
3926 -
3927 - /**
3928 4420 * Display a dismissable warning message and save its dismissal state.
3929 4421 *
3930 4422 * @since 6.3
3931 4423 *
@@ -3937,9 +4429,9 @@
3937 4429 if ( ! $message || ! $option ) {
3938 4430 return;
3939 4431 }
3940 4432
3941 - $ajax_callback = function() use ( $option ) {
4433 + $ajax_callback = function () use ( $option ) {
3942 4434 self::dismiss_warning_message( $option );
3943 4435 };
3944 4436
3945 4437 // We're handling JS codes with `doJsonPost` and it adds 'frm_' to the beginning of the action.
@@ -3947,9 +4439,9 @@
3947 4439 add_action( 'wp_ajax_frm_' . $option, $ajax_callback );
3948 4440
3949 4441 add_filter(
3950 4442 'frm_message_list',
3951 - function( $show_messages ) use ( $message, $option ) {
4443 + function ( $show_messages ) use ( $message, $option ) {
3952 4444 if ( get_option( $option, false ) ) {
3953 4445 return $show_messages;
3954 4446 }
3955 4447
@@ -3956,9 +4448,9 @@
3956 4448 $dismiss_icon = self::icon_by_class(
3957 4449 'frmfont frm_close_icon',
3958 4450 array(
3959 4451 'aria-label' => _x( 'Dismiss', 'warning message: close icon label', 'formidable' ),
3960 - 'echo' => false,
4452 + 'echo' => false,
3961 4453 )
3962 4454 );
3963 4455
3964 4456 $show_messages[] = $message;
@@ -3985,6 +4477,124 @@
3985 4477 update_option( $option, true, 'no' );
3986 4478 }
3987 4479
3988 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;
3989 4599 }
3990 4600 }