PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
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 +504 -397 6.26 → trunk View file →
@@ -9,9 +9,9 @@
9 9 * Version of the database we are moving to.
10 10 *
11 11 * @var int
12 12 */
13 - public static $db_version = 104;
13 + public static $db_version = 106;
14 14
15 15 /**
16 16 * Used by the API add-on.
17 17 *
@@ -28,9 +28,9 @@
28 28 * @since 2.0
29 29 *
30 30 * @var string
31 31 */
32 - public static $plug_version = '6.26';
32 + public static $plug_version = '6.35';
33 33
34 34 /**
35 35 * @var bool
36 36 */
@@ -100,9 +100,9 @@
100 100 */
101 101 public static function make_affiliate_url( $url ) {
102 102 $affiliate_id = self::get_affiliate();
103 103
104 - if ( ! empty( $affiliate_id ) ) {
104 + if ( $affiliate_id ) {
105 105 $url = str_replace( array( 'http://', 'https://' ), '', $url );
106 106 $url = 'http://www.shareasale.com/r.cfm?u=' . absint( $affiliate_id ) . '&b=841990&m=64739&afftrack=plugin&urllink=' . urlencode( $url );
107 107 }
108 108
@@ -129,13 +129,9 @@
129 129 } else {
130 130 $page = 'https://formidableforms.com/lite-upgrade/';
131 131 }
132 132
133 - if ( is_array( $args ) ) {
134 - $args = self::adjust_legacy_utm_args( $args );
135 - } else {
136 - $args = array( 'campaign' => $args );
137 - }
133 + $args = is_array( $args ) ? self::adjust_legacy_utm_args( $args ) : array( 'campaign' => $args );
138 134
139 135 $query_args = array(
140 136 'utm_source' => 'plugin',
141 137 'utm_medium' => self::get_utm_medium(),
@@ -177,13 +173,9 @@
177 173 *
178 174 * @return array
179 175 */
180 176 private static function maybe_add_utm_license( $query_args, $link = '' ) {
181 - if ( isset( $query_args['utm_medium'] ) ) {
182 - $medium = $query_args['utm_medium'];
183 - } else {
184 - $medium = self::pull_medium_from_link( $link );
185 - }
177 + $medium = $query_args['utm_medium'] ?? self::pull_medium_from_link( $link );
186 178
187 179 if ( 'pro' === $medium && is_callable( 'FrmProAddonsController::get_readable_license_type' ) ) {
188 180 $query_args['utm_license'] = strtolower( FrmProAddonsController::get_readable_license_type() );
189 181 }
@@ -210,13 +202,9 @@
210 202 }
211 203
212 204 $query_args = wp_parse_args( $parsed['query'] );
213 205
214 - if ( empty( $query_args['utm_medium'] ) ) {
215 - return '';
216 - }
217 -
218 - return $query_args['utm_medium'];
206 + return ! empty( $query_args['utm_medium'] ) ? $query_args['utm_medium'] : '';
219 207 }
220 208
221 209 /**
222 210 * @since 6.25.1
@@ -254,21 +242,21 @@
254 242 public static function maybe_add_missing_utm( $cta_link, $utm ) {
255 243 $utm = self::adjust_legacy_utm_args( $utm );
256 244 $query_args = array();
257 245
258 - if ( false === strpos( $cta_link, 'utm_source' ) ) {
246 + if ( ! str_contains( $cta_link, 'utm_source' ) ) {
259 247 $query_args['utm_source'] = 'plugin';
260 248 }
261 249
262 - if ( false === strpos( $cta_link, 'utm_medium' ) ) {
250 + if ( ! str_contains( $cta_link, 'utm_medium' ) ) {
263 251 $query_args['utm_medium'] = self::get_utm_medium();
264 252 }
265 253
266 - if ( false === strpos( $cta_link, 'utm_campaign' ) && isset( $utm['campaign'] ) ) {
254 + if ( ! str_contains( $cta_link, 'utm_campaign' ) && isset( $utm['campaign'] ) ) {
267 255 $query_args['utm_campaign'] = $utm['campaign'];
268 256 }
269 257
270 - if ( false === strpos( $cta_link, 'utm_content' ) && isset( $utm['content'] ) ) {
258 + if ( ! str_contains( $cta_link, 'utm_content' ) && isset( $utm['content'] ) ) {
271 259 $query_args['utm_content'] = $utm['content'];
272 260 }
273 261
274 262 $query_args = self::maybe_add_utm_license( $query_args, $cta_link );
@@ -282,14 +270,14 @@
282 270 * @since 2.0
283 271 *
284 272 * @param array $args - May include the form id when values need translation.
285 273 *
286 - * @return FrmSettings $frm_settings
274 + * @return FrmSettings
287 275 */
288 276 public static function get_settings( $args = array() ) {
289 277 global $frm_settings;
290 278
291 - if ( empty( $frm_settings ) ) {
279 + if ( ! $frm_settings ) {
292 280 $frm_settings = new FrmSettings( $args );
293 281 } elseif ( isset( $args['current_form'] ) ) {
294 282 // If the global has already been set, allow strings to be filtered.
295 283 $frm_settings->maybe_filter_for_form( $args );
@@ -301,11 +289,13 @@
301 289 /**
302 290 * @return string
303 291 */
304 292 public static function get_menu_name() {
305 - $frm_settings = self::get_settings();
293 + if ( ! self::pro_is_installed() || FrmAddonsController::is_license_expired() ) {
294 + return 'Formidable';
295 + }
306 296
307 - return FrmAddonsController::is_license_expired() || ! self::pro_is_installed() ? 'Formidable' : $frm_settings->menu;
297 + return self::get_settings()->menu;
308 298 }
309 299
310 300 /**
311 301 * Determine if the current branding is set to 'formidable'.
@@ -319,10 +309,9 @@
319 309 if ( ! self::pro_is_installed() ) {
320 310 return true;
321 311 }
322 312
323 - $menu_icon = self::get_menu_icon_class();
324 - return strpos( $menu_icon, 'frm_logo_icon' ) !== false;
313 + return str_contains( self::get_menu_icon_class(), 'frm_logo_icon' );
325 314 }
326 315
327 316 /**
328 317 * @since 3.05
@@ -339,12 +328,14 @@
339 328 'orange' => '#f05a24',
340 329 );
341 330 $atts = array_merge( $defaults, $atts );
342 331
332 + // phpcs:disable SlevomatCodingStandard.Files.LineLength.LineTooLong
343 333 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 599.68 601.37" width="' . esc_attr( $atts['width'] ) . '" height="' . esc_attr( $atts['height'] ) . '">
344 334 <path fill="' . esc_attr( $atts['orange'] ) . '" d="M289.6 384h140v76h-140z"/>
345 335 <path fill="' . esc_attr( $atts['fill'] ) . '" d="M400.2 147h-200c-17 0-30.6 12.2-30.6 29.3V218h260v-71zM397.9 264H169.6v196h75V340H398a32.2 32.2 0 0 0 30.1-21.4 24.3 24.3 0 0 0 1.7-8.7V264zM299.8 601.4A300.3 300.3 0 0 1 0 300.7a299.8 299.8 0 1 1 511.9 212.6 297.4 297.4 0 0 1-212 88zm0-563A262 262 0 0 0 38.3 300.7a261.6 261.6 0 1 0 446.5-185.5 259.5 259.5 0 0 0-185-76.8z"/>
346 336 </svg>';
337 + // phpcs:enable SlevomatCodingStandard.Files.LineLength.LineTooLong
347 338 }
348 339
349 340 /**
350 341 * @since 4.0
@@ -353,9 +344,9 @@
353 344 *
354 345 * @return void
355 346 */
356 347 public static function show_logo( $atts = array() ) {
357 - echo self::kses( self::svg_logo( $atts ), 'all' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
348 + self::kses_echo( self::svg_logo( $atts ), 'all' );
358 349 }
359 350
360 351 /**
361 352 * @since 4.03.02
@@ -372,9 +363,9 @@
372 363
373 364 $new_icon = apply_filters( 'frm_icon', $icon, true );
374 365
375 366 if ( $new_icon !== $icon ) {
376 - if ( strpos( $new_icon, '<svg' ) === 0 ) {
367 + if ( str_starts_with( $new_icon, '<svg' ) ) {
377 368 $icon = str_replace( 'viewBox="0 0 20', 'width="30" height="35" style="color:#929699" viewBox="0 0 20', $new_icon );
378 369 } else {
379 370 // Show nothing if it isn't an SVG.
380 371 $icon = '<div style="height:39px"></div>';
@@ -379,9 +370,9 @@
379 370 // Show nothing if it isn't an SVG.
380 371 $icon = '<div style="height:39px"></div>';
381 372 }
382 373 }
383 - echo self::kses( $icon, 'all' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
374 + self::kses_echo( $icon, 'all' );
384 375 }
385 376
386 377 /**
387 378 * @since 2.02.04
@@ -435,8 +426,9 @@
435 426
436 427 if ( $check_for_settings ) {
437 428 $check_actions[] = 'settings';
438 429 }
430 +
439 431 return self::is_admin_page( 'formidable' ) && in_array( $action, $check_actions, true );
440 432 }
441 433
442 434 /**
@@ -442,16 +434,15 @@
442 434 /**
443 435 * @return bool
444 436 */
445 437 public static function is_formidable_admin() {
446 - $page = self::simple_get( 'page', 'sanitize_title' );
447 - $is_formidable = strpos( $page, 'formidable' ) !== false;
438 + $page = self::simple_get( 'page', 'sanitize_title' );
448 439
449 - if ( empty( $page ) ) {
450 - $is_formidable = self::is_view_builder_page();
440 + if ( ! $page ) {
441 + return self::is_view_builder_page();
451 442 }
452 443
453 - return $is_formidable;
444 + return str_contains( $page, 'formidable' );
454 445 }
455 446
456 447 /**
457 448 * Checks if is a list page.
@@ -505,9 +496,9 @@
505 496 global $pagenow;
506 497 $get_page = self::simple_get( 'page', 'sanitize_title' );
507 498
508 499 if ( $pagenow ) {
509 - // allow this to be true during ajax load i.e. ajax form builder loading
500 + // Allow this to be true during ajax load i.e. ajax form builder loading
510 501 $is_page = ( $pagenow === 'admin.php' || $pagenow === 'admin-ajax.php' ) && $get_page === $page;
511 502
512 503 if ( $is_page ) {
513 504 return true;
@@ -527,15 +518,15 @@
527 518 */
528 519 public static function is_view_builder_page() {
529 520 global $pagenow;
530 521
531 - if ( $pagenow !== 'post.php' && $pagenow !== 'post-new.php' && $pagenow !== 'edit.php' ) {
522 + if ( ! in_array( $pagenow, array( 'post.php', 'post-new.php', 'edit.php' ), true ) ) {
532 523 return false;
533 524 }
534 525
535 526 $post_type = self::simple_get( 'post_type', 'sanitize_title' );
536 527
537 - if ( empty( $post_type ) ) {
528 + if ( ! $post_type ) {
538 529 $post_id = self::simple_get( 'post', 'absint' );
539 530 $post = get_post( $post_id );
540 531 $post_type = $post ? $post->post_type : '';
541 532 }
@@ -553,9 +544,9 @@
553 544 public static function is_preview_page() {
554 545 global $pagenow;
555 546 $action = self::simple_get( 'action', 'sanitize_title' );
556 547
557 - return $pagenow && $pagenow === 'admin-ajax.php' && $action === 'frm_forms_preview';
548 + return $pagenow === 'admin-ajax.php' && $action === 'frm_forms_preview';
558 549 }
559 550
560 551 /**
561 552 * Check for ajax except the form preview page
@@ -613,9 +604,9 @@
613 604 *
614 605 * @return bool
615 606 */
616 607 public static function is_empty_value( $value, $empty = '' ) {
617 - return ( is_array( $value ) && empty( $value ) ) || $value === $empty;
608 + return $value === array() || $value === $empty;
618 609 }
619 610
620 611 /**
621 612 * @param mixed $value
@@ -742,15 +733,16 @@
742 733 *
743 734 * @return mixed
744 735 */
745 736 public static function get_param( $param, $default = '', $src = 'get', $sanitize = '' ) {
746 - if ( strpos( $param, '[' ) ) {
737 + if ( str_contains( $param, '[' ) ) {
747 738 $params = explode( '[', $param );
748 739 $param = $params[0];
749 740 }
750 741
751 742 if ( $src === 'get' ) {
752 - $value = isset( $_POST[ $param ] ) ? wp_unslash( $_POST[ $param ] ) : ( isset( $_GET[ $param ] ) ? wp_unslash( $_GET[ $param ] ) : $default ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
743 + // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
744 + $value = isset( $_POST[ $param ] ) ? wp_unslash( $_POST[ $param ] ) : ( isset( $_GET[ $param ] ) ? wp_unslash( $_GET[ $param ] ) : $default );
753 745
754 746 if ( ! isset( $_POST[ $param ] ) && isset( $_GET[ $param ] ) && ! is_array( $value ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
755 747 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
756 748 $value = htmlspecialchars_decode( wp_unslash( $_GET[ $param ] ) );
@@ -766,17 +758,19 @@
766 758 )
767 759 );
768 760 }
769 761
770 - if ( isset( $params ) && is_array( $value ) && ! empty( $value ) ) {
771 - foreach ( $params as $k => $p ) {
772 - if ( ! $k || ! is_array( $value ) ) {
773 - continue;
774 - }
762 + if ( ! isset( $params ) || ! is_array( $value ) || ! $value ) {
763 + return $value;
764 + }
775 765
776 - $p = trim( $p, ']' );
777 - $value = $value[ $p ] ?? $default;
766 + foreach ( $params as $k => $p ) {
767 + if ( ! $k || ! is_array( $value ) ) {
768 + continue;
778 769 }
770 +
771 + $p = trim( $p, ']' );
772 + $value = $value[ $p ] ?? $default;
779 773 }
780 774
781 775 return $value;
782 776 }
@@ -809,9 +803,9 @@
809 803 * @param string $param
810 804 * @param string $sanitize
811 805 * @param string $default
812 806 *
813 - * @return array|string
807 + * @return array|int|string
814 808 */
815 809 public static function simple_get( $param, $sanitize = 'sanitize_text_field', $default = '' ) {
816 810 return self::get_simple_request(
817 811 array(
@@ -840,11 +834,10 @@
840 834 'sanitize' => 'sanitize_text_field',
841 835 'serialized' => false,
842 836 );
843 837 $args = wp_parse_args( $args, $defaults );
838 + $value = $args['default'];
844 839
845 - $value = $args['default'];
846 -
847 840 if ( $args['type'] === 'get' ) {
848 841 if ( $_GET && isset( $_GET[ $args['param'] ] ) ) {
849 842 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
850 843 $value = wp_unslash( $_GET[ $args['param'] ] );
@@ -858,11 +851,10 @@
858 851 self::unserialize_or_decode( $value );
859 852 }
860 853 }
861 854 } elseif ( isset( $_REQUEST[ $args['param'] ] ) ) {
862 - // phpcs:ignore WordPress.Security.NonceVerification.Missing
863 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
864 - $value = wp_unslash( $_REQUEST[ $args['param'] ] );
855 + // phpcs:ignore phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
856 + $value = wp_unslash( $_REQUEST[ $args['param'] ] );
865 857 }
866 858
867 859 self::sanitize_value( $args['sanitize'], $value );
868 860
@@ -875,17 +867,13 @@
875 867 * @since 2.0.8
876 868 *
877 869 * @param string $value
878 870 *
879 - * @return string $value
871 + * @return string Value.
880 872 */
881 873 public static function preserve_backslashes( $value ) {
882 874 // If backslashes have already been added, don't add them again
883 - if ( strpos( $value, '\\\\' ) === false ) {
884 - $value = addslashes( $value );
885 - }
886 -
887 - return $value;
875 + return str_contains( $value, '\\\\' ) ? $value : addslashes( $value );
888 876 }
889 877
890 878 /**
891 879 * Sanitize a value in-place.
@@ -911,8 +899,9 @@
911 899
912 900 foreach ( $temp_values as $k => $v ) {
913 901 self::sanitize_value( $sanitize, $value[ $k ] );
914 902 }
903 +
915 904 return;
916 905 }
917 906
918 907 $value = call_user_func( $sanitize, $value );
@@ -948,8 +937,9 @@
948 937 } else {
949 938 self::sanitize_value( self::class . '::strip_most_html', $value );
950 939 }
951 940 self::decode_specialchars( $value );
941 + self::sanitize_value( 'FrmHtmlSanitizer::sanitize_url_attributes', $value );
952 942 }
953 943
954 944 /**
955 945 * Allow only a small set of very basic HTML for unprivileged users.
@@ -958,8 +948,12 @@
958 948 *
959 949 * @param string $value
960 950 */
961 951 public static function strip_most_html( $value ) {
952 + if ( '' === $value ) {
953 + return $value;
954 + }
955 +
962 956 $allowed_html = array(
963 957 'b' => array(),
964 958 'br' => array(),
965 959 'strong' => array(),
@@ -1010,9 +1004,9 @@
1010 1004 * @param string $string The string to prep, passed by reference.
1011 1005 */
1012 1006 private static function decode_amp( &$string ) {
1013 1007 // Don't bother if there are no entities - saves a lot of processing
1014 - if ( empty( $string ) || strpos( $string, '&' ) === false ) {
1008 + if ( ! $string || ! str_contains( $string, '&' ) ) {
1015 1009 return;
1016 1010 }
1017 1011
1018 1012 $translation = array(
@@ -1056,11 +1050,9 @@
1056 1050 *
1057 1051 * @return string
1058 1052 */
1059 1053 public static function kses( $value, $allowed = array() ) {
1060 - $allowed_html = self::allowed_html( $allowed );
1061 -
1062 - return wp_kses( $value, $allowed_html );
1054 + return wp_kses( $value, self::allowed_html( $allowed ) );
1063 1055 }
1064 1056
1065 1057 /**
1066 1058 * Sanitizes and echoes a given value.
@@ -1085,11 +1077,11 @@
1085 1077 *
1086 1078 * @return string
1087 1079 */
1088 1080 public static function kses_submit_button( $html ) {
1089 - $included_button_action = false !== strpos( $html, '[button_action]' );
1090 - $included_back_hook = false !== strpos( $html, '[back_hook]' );
1091 - $included_draft_hook = false !== strpos( $html, '[draft_hook]' );
1081 + $included_button_action = str_contains( $html, '[button_action]' );
1082 + $included_back_hook = str_contains( $html, '[back_hook]' );
1083 + $included_draft_hook = str_contains( $html, '[draft_hook]' );
1092 1084 add_filter( 'safe_style_css', 'FrmAppHelper::allow_visibility_style' );
1093 1085 add_filter( 'frm_striphtml_allowed_tags', 'FrmAppHelper::add_allowed_submit_button_tags' );
1094 1086 $html = self::kses( $html, 'all' );
1095 1087 remove_filter( 'safe_style_css', 'FrmAppHelper::allow_visibility_style' );
@@ -1095,9 +1087,9 @@
1095 1087 remove_filter( 'safe_style_css', 'FrmAppHelper::allow_visibility_style' );
1096 1088 remove_filter( 'frm_striphtml_allowed_tags', 'FrmAppHelper::add_allowed_submit_button_tags' );
1097 1089
1098 1090 if ( $included_button_action ) {
1099 - if ( false !== strpos( $html, '<input type="submit"' ) ) {
1091 + if ( str_contains( $html, '<input type="submit"' ) ) {
1100 1092 $pattern = '/(<input type="submit")([^>]*)(\/>)/';
1101 1093 $html = preg_replace( $pattern, '$1$2[button_action] $3', $html, 1 );
1102 1094 } else {
1103 1095 $pattern = '/(<button)(.*)(class=")(.*)(frm_button_submit)(.*)(")(.*)([^>]+)(>)/';
@@ -1109,10 +1101,11 @@
1109 1101 $html = str_replace( 'class="frm_prev_page"', 'class="frm_prev_page" [back_hook]', $html );
1110 1102 }
1111 1103
1112 1104 if ( $included_draft_hook ) {
1113 - $html = str_replace( 'class="frm_save_draft"', 'class="frm_save_draft" [draft_hook]', $html );
1105 + return str_replace( 'class="frm_save_draft"', 'class="frm_save_draft" [draft_hook]', $html );
1114 1106 }
1107 +
1115 1108 return $html;
1116 1109 }
1117 1110
1118 1111 /**
@@ -1160,9 +1153,9 @@
1160 1153 $allowed_html = array();
1161 1154
1162 1155 if ( $allowed === 'all' ) {
1163 1156 $allowed_html = $html;
1164 - } elseif ( ! empty( $allowed ) ) {
1157 + } elseif ( $allowed ) {
1165 1158 foreach ( (array) $allowed as $a ) {
1166 1159 $allowed_html[ $a ] = $html[ $a ] ?? array();
1167 1160 }
1168 1161 }
@@ -1171,8 +1164,10 @@
1171 1164 }
1172 1165
1173 1166 /**
1174 1167 * @since 2.05.03
1168 + *
1169 + * @return array
1175 1170 */
1176 1171 private static function safe_html() {
1177 1172 $allow_class = array(
1178 1173 'class' => true,
@@ -1325,15 +1320,15 @@
1325 1320 }
1326 1321
1327 1322 $action_name = isset( $_GET['action'] ) ? 'action' : ( isset( $_GET['action2'] ) ? 'action2' : '' );
1328 1323
1329 - if ( empty( $action_name ) ) {
1324 + if ( ! $action_name ) {
1330 1325 return;
1331 1326 }
1332 1327
1333 1328 $new_action = self::get_param( $action_name, '', 'get', 'sanitize_text_field' );
1334 1329
1335 - if ( ! empty( $new_action ) ) {
1330 + if ( $new_action ) {
1336 1331 $_SERVER['REQUEST_URI'] = str_replace( '&action=' . $new_action, '', self::get_server_value( 'REQUEST_URI' ) );
1337 1332 }
1338 1333 }
1339 1334
@@ -1347,8 +1342,9 @@
1347 1342 *
1348 1343 * @return array|string
1349 1344 */
1350 1345 public static function get_query_var( $value, $param ) {
1346 + // phpcs:ignore Universal.Operators.StrictComparisons
1351 1347 if ( $value != '' ) {
1352 1348 return $value;
1353 1349 }
1354 1350
@@ -1353,13 +1349,9 @@
1353 1349 }
1354 1350
1355 1351 global $wp_query;
1356 1352
1357 - if ( isset( $wp_query->query_vars[ $param ] ) ) {
1358 - $value = $wp_query->query_vars[ $param ];
1359 - }
1360 -
1361 - return $value;
1353 + return $wp_query->query_vars[ $param ] ?? $value;
1362 1354 }
1363 1355
1364 1356 /**
1365 1357 * Try to show the SVG if possible. Otherwise, use the font icon.
@@ -1377,10 +1369,8 @@
1377 1369 if ( isset( $atts['echo'] ) ) {
1378 1370 unset( $atts['echo'] );
1379 1371 }
1380 1372
1381 - $html_atts = self::array_to_html_params( $atts );
1382 -
1383 1373 $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
1384 1374
1385 1375 // Replace icons that have been removed or renamed.
1386 1376 $deprecated = array(
@@ -1393,26 +1383,55 @@
1393 1383 $icon = $deprecated[ $icon ];
1394 1384 $class = str_replace( $icon, $deprecated[ $icon ], $class );
1395 1385 }
1396 1386
1397 - if ( $icon === $class ) {
1398 - $icon = '<i class="' . esc_attr( $class ) . '"' . $html_atts . '></i>';
1399 - } else {
1400 - $class = strpos( $icon, ' ' ) === false ? '' : ' ' . $icon;
1387 + $is_font_icon = $icon === $class;
1401 1388
1402 - if ( strpos( $icon, ' ' ) ) {
1389 + if ( ! $is_font_icon ) {
1390 + $class = str_contains( $icon, ' ' ) ? ' ' . $icon : '';
1391 +
1392 + if ( str_contains( $icon, ' ' ) ) {
1403 1393 $icon = explode( ' ', $icon );
1404 1394 $icon = reset( $icon );
1405 1395 }
1396 + }
1406 1397
1407 - $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use xlink:href="#' . esc_attr( $icon ) . '" /></svg>';
1398 + if ( $atts ) {
1399 + // A caller passed attributes, so kses still has to decide which of them survive. Its
1400 + // allowlist comes from safe_html() through the frm_striphtml_allowed_tags filter, and
1401 + // add-ons widen it around their own icons, so there is no fixed list to check against.
1402 + $html_atts = self::array_to_html_params( $atts );
1403 + $markup = $is_font_icon
1404 + ? '<i class="' . esc_attr( $class ) . '"' . $html_atts . '></i>'
1405 + : '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use href="#' . esc_attr( $icon ) . '" /></svg>';
1406 +
1407 + if ( ! $echo ) {
1408 + return $markup;
1409 + }
1410 +
1411 + echo self::kses_icon( $markup ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1412 + return null;
1408 1413 }
1409 1414
1410 - if ( $echo ) {
1411 - echo self::kses_icon( $icon ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1412 - } else {
1413 - return $icon;
1414 - }
1415 + /**
1416 + * With no attributes from the caller, the tag is nothing but this method's own markup
1417 + * around an escaped class and icon id, so there is nothing left for kses to decide and it
1418 + * can be skipped. Echoing the pieces rather than a finished string keeps that safe to the
1419 + * escaping sniff without an annotation.
1420 + *
1421 + * This is the path the form builder takes for most of the tens of thousands of icons it
1422 + * renders on a large form, and the kses pass was most of what each one cost.
1423 + */
1424 + $callback = function () use ( $is_font_icon, $class, $icon ) {
1425 + if ( $is_font_icon ) {
1426 + echo '<i class="' . esc_attr( $class ) . '"></i>';
1427 + return;
1428 + }
1429 +
1430 + echo '<svg class="frmsvg' . esc_attr( $class ) . '"><use href="#' . esc_attr( $icon ) . '" /></svg>';
1431 + };
1432 +
1433 + return self::clip( $callback, $echo );
1415 1434 }
1416 1435
1417 1436 /**
1418 1437 * Run kses for icons. It needs to add a few filters first in order to preserve some custom style values.
@@ -1466,9 +1485,9 @@
1466 1485 * @param bool $allow_css
1467 1486 * @param string $css_string
1468 1487 */
1469 1488 public static function allow_style( $allow_css, $css_string ) {
1470 - if ( ! $allow_css && 0 === strpos( $css_string, '--primary-700:' ) ) {
1489 + if ( ! $allow_css && str_starts_with( $css_string, '--primary-700:' ) ) {
1471 1490 $split = explode( ':', $css_string, 2 );
1472 1491 $allow_css = 2 === count( $split ) && self::is_a_valid_color( $split[1] );
1473 1492 }
1474 1493 return $allow_css;
@@ -1483,15 +1502,16 @@
1483 1502 */
1484 1503 private static function is_a_valid_color( $value ) {
1485 1504 $match = 0;
1486 1505
1487 - if ( 0 === strpos( $value, 'rgba(' ) ) {
1506 + if ( str_starts_with( $value, 'rgba(' ) ) {
1488 1507 $match = preg_match( '/^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d*(?:\.\d+)?)\)$/', $value );
1489 - } elseif ( 0 === strpos( $value, 'rgb(' ) ) {
1508 + } elseif ( str_starts_with( $value, 'rgb(' ) ) {
1490 1509 $match = preg_match( '/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/', $value );
1491 - } elseif ( 0 === strpos( $value, '#' ) ) {
1510 + } elseif ( str_starts_with( $value, '#' ) ) {
1492 1511 $match = preg_match( '/^#([a-f0-9]{6}|[a-f0-9]{3})\b$/', $value );
1493 1512 }
1513 +
1494 1514 return (bool) $match;
1495 1515 }
1496 1516
1497 1517 /**
@@ -1523,13 +1543,15 @@
1523 1543 * @return string|void
1524 1544 */
1525 1545 public static function array_to_html_params( $atts, $echo = false ) {
1526 1546 $callback = function () use ( $atts ) {
1527 - if ( $atts ) {
1528 - foreach ( $atts as $key => $value ) {
1529 - echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1530 - }
1547 + if ( ! $atts ) {
1548 + return;
1531 1549 }
1550 +
1551 + foreach ( $atts as $key => $value ) {
1552 + echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1553 + }
1532 1554 };
1533 1555 return self::clip( $callback, $echo );
1534 1556 }
1535 1557
@@ -1541,8 +1563,10 @@
1541 1563 * @param Closure $echo_function
1542 1564 * @param bool $echo
1543 1565 *
1544 1566 * @return string|null
1567 + *
1568 + * @psalm-return ($echo is true ? null : string)
1545 1569 */
1546 1570 public static function clip( $echo_function, $echo = false ) {
1547 1571 if ( ! $echo ) {
1548 1572 ob_start();
@@ -1551,13 +1575,9 @@
1551 1575 if ( is_callable( $echo_function ) ) {
1552 1576 $echo_function();
1553 1577 }
1554 1578
1555 - if ( ! $echo ) {
1556 - $return = ob_get_contents();
1557 - ob_end_clean();
1558 - return $return;
1559 - }
1579 + return $echo ? null : ob_get_clean();
1560 1580 }
1561 1581
1562 1582 /**
1563 1583 * @since 3.0
@@ -1587,13 +1607,15 @@
1587 1607 *
1588 1608 * @return void
1589 1609 */
1590 1610 public static function import_link( $type = 'secondary' ) {
1611 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
1591 1612 ?>
1592 1613 <a href="<?php echo esc_url( admin_url( 'admin.php?page=formidable-import' ) ); ?>" class="button frm-button-<?php echo esc_attr( $type ); ?> frm_animate_bg">
1593 1614 <?php esc_html_e( 'Import', 'formidable' ); ?>
1594 1615 </a>
1595 1616 <?php
1617 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
1596 1618 }
1597 1619
1598 1620 /**
1599 1621 * Print applicable admin banner.
@@ -1614,8 +1636,9 @@
1614 1636 // Print license warning or inbox banner and exit if either prints.
1615 1637 // And exit before printing the upgrade bar if it shouldn't be shown.
1616 1638 return;
1617 1639 }
1640 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
1618 1641 ?>
1619 1642 <div class="frm-upgrade-bar">
1620 1643 <div class="frm-upgrade-bar-inner">
1621 1644 <?php
@@ -1630,18 +1653,14 @@
1630 1653 'campaign' => 'settings-license',
1631 1654 'content' => 'lite-banner',
1632 1655 );
1633 1656
1634 - if ( $upgrade_link ) {
1635 - $upgrade_link = self::maybe_add_missing_utm( $upgrade_link, $utm );
1636 - } else {
1637 - $upgrade_link = self::admin_upgrade_link( $utm );
1638 - }
1657 + $upgrade_link = $upgrade_link ? self::maybe_add_missing_utm( $upgrade_link, $utm ) : self::admin_upgrade_link( $utm );
1639 1658
1640 1659 printf(
1641 1660 /* translators: %1$s: Start link HTML, %2$s: CTA text ("upgrading to PRO" by default), %3$s: End link HTML */
1642 1661 esc_html__( 'You\'re using Formidable Forms Lite. To unlock more features consider %1$s%2$s%3$s.', 'formidable' ),
1643 - '<a href="' . esc_url( $upgrade_link ) . '">',
1662 + '<a href="' . esc_url( $upgrade_link ) . '" target="_blank" rel="noopener">',
1644 1663 esc_html( $cta_text ),
1645 1664 '</a>'
1646 1665 );
1647 1666 ?>
@@ -1647,8 +1666,9 @@
1647 1666 ?>
1648 1667 </div>
1649 1668 </div>
1650 1669 <?php
1670 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
1651 1671 }
1652 1672
1653 1673 /**
1654 1674 * @since 5.4.2
@@ -1746,14 +1766,15 @@
1746 1766
1747 1767 if ( ! empty( $atts['tosearch'] ) ) {
1748 1768 $input_atts['autocomplete'] = 'off';
1749 1769 }
1770 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
1750 1771 ?>
1751 1772 <p class="frm-search <?php echo esc_attr( $atts['class'] ); ?>">
1752 1773 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
1753 1774 <?php echo esc_html( $atts['text'] ); ?>:
1754 1775 </label>
1755 - <?php self::icon_by_class( 'frm_icon_font frm_search_icon frm_svg20' ); ?>
1776 + <?php self::icon_by_class( 'frmfont frm_search_icon frm_svg20' ); ?>
1756 1777 <input <?php self::array_to_html_params( $input_atts, true ); ?> />
1757 1778 <?php
1758 1779 if ( empty( $atts['tosearch'] ) ) {
1759 1780 submit_button( $atts['text'], 'button-secondary', '', false, array( 'id' => 'search-submit' ) );
@@ -1760,8 +1781,9 @@
1760 1781 }
1761 1782 ?>
1762 1783 </p>
1763 1784 <?php
1785 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
1764 1786 }
1765 1787
1766 1788 /**
1767 1789 * @param string $type Hook type slug.
@@ -1832,14 +1854,14 @@
1832 1854 * True when value is 1, true, 'true', 'yes'
1833 1855 *
1834 1856 * @since 1.07.10
1835 1857 *
1836 - * @param string $value The value to compare.
1858 + * @param bool|int|string $value The value to compare.
1837 1859 *
1838 1860 * @return bool
1839 1861 */
1840 1862 public static function is_true( $value ) {
1841 - return true === $value || 1 == $value || 'true' === $value || 'yes' === $value;
1863 + return true === $value || '1' === (string) $value || 'true' === $value || 'yes' === $value;
1842 1864 }
1843 1865
1844 1866 /**
1845 1867 * Gets all post from a specific post type.
@@ -1895,10 +1917,9 @@
1895 1917 *
1896 1918 * @param array $args Selection arguments.
1897 1919 */
1898 1920 public static function maybe_autocomplete_pages_options( $args ) {
1899 - $args = self::preformat_selection_args( $args );
1900 -
1921 + $args = self::preformat_selection_args( $args );
1901 1922 $pages_count = wp_count_posts( $args['post_type'] );
1902 1923
1903 1924 if ( ! isset( $pages_count->publish ) || $pages_count->publish <= 50 ) {
1904 1925 self::wp_pages_dropdown( $args );
@@ -1945,10 +1966,9 @@
1945 1966 'value_key' => 'value',
1946 1967 'label_key' => 'label',
1947 1968 );
1948 1969
1949 - $args = wp_parse_args( $args, $defaults );
1950 -
1970 + $args = wp_parse_args( $args, $defaults );
1951 1971 $html_attrs = array();
1952 1972
1953 1973 if ( ! empty( $args['name'] ) ) {
1954 1974 $html_attrs['name'] = $args['name'];
@@ -1957,8 +1977,9 @@
1957 1977 if ( ! empty( $args['id'] ) ) {
1958 1978 $html_attrs['id'] = $args['id'];
1959 1979 }
1960 1980
1981 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
1961 1982 if ( count( $args['source'] ) <= $args['dropdown_limit'] ) {
1962 1983 ?>
1963 1984 <select <?php self::array_to_html_params( $html_attrs, true ); ?>>
1964 1985 <option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
@@ -1969,37 +1990,39 @@
1969 1990 if ( ! empty( $args['truncate'] ) ) {
1970 1991 $value_label['label'] = self::truncate( $value_label['label'], $args['truncate'] );
1971 1992 }
1972 1993 ?>
1973 - <option value="<?php echo esc_attr( $value_label['value'] ); ?>" <?php selected( $value_label['value'], $args['selected'] ); ?>><?php echo esc_html( $value_label['label'] ); ?></option>
1994 + <option value="<?php echo esc_attr( $value_label['value'] ); ?>" <?php selected( $value_label['value'], $args['selected'] ); ?>><?php echo esc_html( $value_label['label'] ); ?></option><?php // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
1974 1995 <?php endforeach; ?>
1975 1996 </select>
1976 1997 <?php
1977 - } else {
1978 - $options = array();
1979 - $autocomplete_value = '';
1998 + return;
1999 + }
2000 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
1980 2001
1981 - foreach ( $args['source'] as $key => $source ) {
1982 - $value_label = self::get_dropdown_value_and_label_from_option( $source, $key, $args );
2002 + $options = array();
2003 + $autocomplete_value = '';
1983 2004
1984 - if ( $value_label['value'] === $args['selected'] ) {
1985 - $autocomplete_value = $value_label['label'];
1986 - }
2005 + foreach ( $args['source'] as $key => $source ) {
2006 + $value_label = self::get_dropdown_value_and_label_from_option( $source, $key, $args );
1987 2007
1988 - $options[] = $value_label;
2008 + if ( $value_label['value'] === $args['selected'] ) {
2009 + $autocomplete_value = $value_label['label'];
1989 2010 }
1990 2011
1991 - $html_attrs['type'] = 'hidden';
1992 - $html_attrs['class'] = 'frm_autocomplete_value_input';
1993 - $html_attrs['value'] = $args['selected'];
1994 - ?>
1995 - <input type="text" class="frm-custom-search"
1996 - data-source="<?php echo esc_attr( wp_json_encode( $options ) ); ?>"
1997 - placeholder="<?php echo esc_attr( $args['autocomplete_placeholder'] ); ?>"
1998 - value="<?php echo esc_attr( $autocomplete_value ); ?>" />
1999 - <input <?php self::array_to_html_params( $html_attrs, true ); ?> />
2000 - <?php
2001 - }//end if
2012 + $options[] = $value_label;
2013 + }
2014 +
2015 + $html_attrs['type'] = 'hidden';
2016 + $html_attrs['class'] = 'frm_autocomplete_value_input';
2017 + $html_attrs['value'] = $args['selected'];
2018 + ?>
2019 + <input type="text" class="frm-custom-search"
2020 + data-source="<?php echo esc_attr( wp_json_encode( $options ) ); ?>"
2021 + placeholder="<?php echo esc_attr( $args['autocomplete_placeholder'] ); ?>"
2022 + value="<?php echo esc_attr( $autocomplete_value ); ?>" />
2023 + <input <?php self::array_to_html_params( $html_attrs, true ); ?> />
2024 + <?php
2002 2025 }
2003 2026
2004 2027 /**
2005 2028 * Gets dropdown value and label from autodropdown option.
@@ -2033,8 +2056,9 @@
2033 2056 self::prep_page_dropdown_params( $page_id, $truncate, $args );
2034 2057
2035 2058 $pages = self::get_post_ids_and_titles( $args['post_type'] );
2036 2059 $selected = self::get_post_param( $args['field_name'], $args['page_id'], 'absint' );
2060 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
2037 2061 ?>
2038 2062 <select name="<?php echo esc_attr( $args['field_name'] ); ?>" id="<?php echo esc_attr( $args['field_name'] ); ?>" class="frm-pages-dropdown">
2039 2063 <option value=""><?php echo esc_html( $args['placeholder'] ); ?></option>
2040 2064 <?php foreach ( $pages as $page ) { ?>
@@ -2043,8 +2067,9 @@
2043 2067 </option>
2044 2068 <?php } ?>
2045 2069 </select>
2046 2070 <?php
2071 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
2047 2072 }
2048 2073
2049 2074 /**
2050 2075 * Fill in missing parameters passed to wp_pages_dropdown().
@@ -2102,9 +2127,8 @@
2102 2127 $post = get_post( $post_id );
2103 2128
2104 2129 if ( $post ) {
2105 2130 $post_url = admin_url( 'post.php?post=' . $post_id . '&action=edit' );
2106 -
2107 2131 return '<a href="' . esc_url( $post_url ) . '">' . self::truncate( $post->post_title, 50 ) . '</a>';
2108 2132 }
2109 2133
2110 2134 return '';
@@ -2117,11 +2141,9 @@
2117 2141 *
2118 2142 * @return bool
2119 2143 */
2120 2144 public static function is_full_screen() {
2121 - return self::is_form_builder_page() ||
2122 - self::is_style_editor_page() ||
2123 - self::is_full_screen_view_builder_page();
2145 + return self::is_form_builder_page() || self::is_style_editor_page() || self::is_full_screen_view_builder_page();
2124 2146 }
2125 2147
2126 2148 /**
2127 2149 * Check if user is on the style editor or its alternative URL.
@@ -2170,8 +2192,9 @@
2170 2192 * @param array|string $capability
2171 2193 * @param string $multiple 'single' and 'multiple'.
2172 2194 */
2173 2195 public static function wp_roles_dropdown( $field_name, $capability, $multiple = 'single' ) {
2196 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
2174 2197 ?>
2175 2198 <select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $field_name ); ?>"
2176 2199 <?php echo 'multiple' === $multiple ? 'multiple="multiple"' : ''; ?>
2177 2200 class="frm_multiselect">
@@ -2177,8 +2200,9 @@
2177 2200 class="frm_multiselect">
2178 2201 <?php self::roles_options( $capability ); ?>
2179 2202 </select>
2180 2203 <?php
2204 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
2181 2205 }
2182 2206
2183 2207 /**
2184 2208 * @since 4.07
@@ -2288,17 +2312,13 @@
2288 2312 if ( $role === 'loggedin' || ! $role ) {
2289 2313 return is_user_logged_in();
2290 2314 }
2291 2315
2292 - if ( $role == 1 ) {
2316 + if ( (int) $role === 1 ) {
2293 2317 $role = 'administrator';
2294 2318 }
2295 2319
2296 - if ( ! is_user_logged_in() ) {
2297 - return false;
2298 - }
2299 -
2300 - return current_user_can( $role );
2320 + return is_user_logged_in() ? current_user_can( $role ) : false;
2301 2321 }
2302 2322
2303 2323 /**
2304 2324 * @param array|string $needed_role
@@ -2317,9 +2337,9 @@
2317 2337 }
2318 2338
2319 2339 $can = self::current_user_can( $needed_role );
2320 2340
2321 - if ( $can || in_array( $needed_role, array( '-1', 'loggedout' ) ) ) {
2341 + if ( $can || in_array( $needed_role, array( '-1', 'loggedout' ), true ) ) {
2322 2342 return $can;
2323 2343 }
2324 2344
2325 2345 $roles = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' );
@@ -2328,9 +2348,9 @@
2328 2348 if ( current_user_can( $role ) ) {
2329 2349 return true;
2330 2350 }
2331 2351
2332 - if ( $role == $needed_role ) {
2352 + if ( $role === $needed_role ) {
2333 2353 break;
2334 2354 }
2335 2355 }
2336 2356
@@ -2348,10 +2368,9 @@
2348 2368 if ( ! current_user_can( 'administrator' ) || current_user_can( 'frm_view_forms' ) ) {
2349 2369 return;
2350 2370 }
2351 2371
2352 - $user_id = get_current_user_id();
2353 - $user = new WP_User( $user_id );
2372 + $user = new WP_User( get_current_user_id() );
2354 2373 $frm_roles = self::frm_capabilities();
2355 2374
2356 2375 foreach ( $frm_roles as $frm_role => $frm_role_description ) {
2357 2376 $user->add_cap( $frm_role );
@@ -2368,15 +2387,17 @@
2368 2387 *
2369 2388 * @return void
2370 2389 */
2371 2390 public static function force_capability( $cap = 'frm_change_settings' ) {
2372 - if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
2373 - $role = get_role( 'administrator' );
2374 - $frm_roles = self::frm_capabilities();
2391 + if ( ! current_user_can( 'administrator' ) || current_user_can( $cap ) ) {
2392 + return;
2393 + }
2375 2394
2376 - foreach ( $frm_roles as $frm_role => $frm_role_description ) {
2377 - $role->add_cap( $frm_role );
2378 - }
2395 + $role = get_role( 'administrator' );
2396 + $frm_roles = self::frm_capabilities();
2397 +
2398 + foreach ( $frm_roles as $frm_role => $frm_role_description ) {
2399 + $role->add_cap( $frm_role );
2379 2400 }
2380 2401 }
2381 2402
2382 2403 /**
@@ -2390,14 +2411,17 @@
2390 2411 */
2391 2412 public static function permission_check( $permission, $show_message = 'show' ) {
2392 2413 $permission_error = self::permission_nonce_error( $permission );
2393 2414
2394 - if ( $permission_error !== false ) {
2395 - if ( 'hide' == $show_message ) {
2396 - $permission_error = '';
2397 - }
2398 - wp_die( esc_html( $permission_error ) );
2415 + if ( $permission_error === false ) {
2416 + return;
2399 2417 }
2418 +
2419 + if ( 'hide' === $show_message ) {
2420 + $permission_error = '';
2421 + }
2422 +
2423 + wp_die( esc_html( $permission_error ) );
2400 2424 }
2401 2425
2402 2426 /**
2403 2427 * Check user permission and nonce
@@ -2410,17 +2434,16 @@
2410 2434 *
2411 2435 * @return false|string The permission message or false if allowed
2412 2436 */
2413 2437 public static function permission_nonce_error( $permission, $nonce_name = '', $nonce = '' ) {
2414 - if ( ! empty( $permission ) && ! current_user_can( $permission ) && ! current_user_can( 'administrator' ) ) {
2438 + if ( $permission && ! current_user_can( $permission ) && ! current_user_can( 'administrator' ) ) {
2415 2439 $frm_settings = self::get_settings();
2416 -
2417 2440 return $frm_settings->admin_permission;
2418 2441 }
2419 2442
2420 2443 $error = false;
2421 2444
2422 - if ( empty( $nonce_name ) ) {
2445 + if ( ! $nonce_name ) {
2423 2446 return $error;
2424 2447 }
2425 2448
2426 2449 $nonce_value = $_REQUEST && isset( $_REQUEST[ $nonce_name ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $nonce_name ] ) ) : '';
@@ -2446,19 +2469,19 @@
2446 2469 }
2447 2470
2448 2471 /**
2449 2472 * @param array|string $values
2450 - * @param string $current
2473 + * @param string|null $current
2451 2474 *
2452 2475 * @return bool
2453 2476 */
2454 2477 public static function check_selected( $values, $current ) {
2455 - $values = self::recursive_function_map( $values, 'trim' );
2456 - $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
2457 -
2478 + $values = self::recursive_function_map( $values, 'trim' );
2479 + $values = self::recursive_function_map( $values, 'htmlspecialchars_decode' );
2458 2480 $current = is_null( $current ) ? '' : htmlspecialchars_decode( trim( $current ) );
2459 2481
2460 - return ( is_array( $values ) && in_array( $current, $values ) ) || ( ! is_array( $values ) && $values == $current );
2482 + // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict, Universal.Operators.StrictComparisons
2483 + return is_array( $values ) ? in_array( $current, $values ) : $values == $current;
2461 2484 }
2462 2485
2463 2486 /**
2464 2487 * @param array|string $value
@@ -2468,23 +2491,18 @@
2468 2491 */
2469 2492 public static function recursive_function_map( $value, $function ) {
2470 2493 if ( is_array( $value ) ) {
2471 2494 $original_function = $function;
2495 + $function = count( $value ) ? explode( ', ', FrmDb::prepare_array_values( $value, $function ) ) : array( $function );
2472 2496
2473 - if ( count( $value ) ) {
2474 - $function = explode( ', ', FrmDb::prepare_array_values( $value, $function ) );
2475 - } else {
2476 - $function = array( $function );
2477 - }
2478 -
2479 - if ( ! self::is_assoc( $value ) ) {
2480 - $value = array_map( array( 'FrmAppHelper', 'recursive_function_map' ), $value, $function );
2481 - } else {
2497 + if ( self::is_assoc( $value ) ) {
2482 2498 foreach ( $value as $k => $v ) {
2483 2499 if ( ! is_array( $v ) ) {
2484 2500 $value[ $k ] = call_user_func( $original_function, $v );
2485 2501 }
2486 2502 }
2503 + } else {
2504 + $value = array_map( array( 'FrmAppHelper', 'recursive_function_map' ), $value, $function );
2487 2505 }
2488 2506 } else {
2489 2507 $value = self::maybe_update_value_if_null( $value, $function );
2490 2508 $value = call_user_func( $function, $value );
@@ -2504,9 +2522,9 @@
2504 2522 * @return mixed
2505 2523 */
2506 2524 private static function maybe_update_value_if_null( $value, $function ) {
2507 2525 if ( null === $value && in_array( $function, array( 'trim', 'strlen' ), true ) ) {
2508 - $value = '';
2526 + return '';
2509 2527 }
2510 2528
2511 2529 return $value;
2512 2530 }
@@ -2534,9 +2552,9 @@
2534 2552 foreach ( $array as $key => $value ) {
2535 2553 if ( is_array( $value ) ) {
2536 2554 $return = array_merge( $return, self::array_flatten( $value, $keys ) );
2537 2555 } elseif ( $keys === 'keep' ) {
2538 - $return[ $key ] = $value;
2556 + $return[ $key ] = $value;
2539 2557 } else {
2540 2558 $return[] = $value;
2541 2559 }
2542 2560 }
@@ -2591,9 +2609,9 @@
2591 2609 * @return mixed
2592 2610 */
2593 2611 public static function use_wpautop( $content ) {
2594 2612 if ( apply_filters( 'frm_use_wpautop', true ) && is_string( $content ) ) {
2595 - $content = wpautop( str_replace( '<br>', '<br />', $content ) );
2613 + return wpautop( str_replace( '<br>', '<br />', $content ) );
2596 2614 }
2597 2615
2598 2616 return $content;
2599 2617 }
@@ -2609,11 +2627,9 @@
2609 2627 // Replace double quotes.
2610 2628 $val = str_replace( array( '&#8220;', '&#8221;', '&#8243;' ), '"', $val );
2611 2629
2612 2630 // Replace single quotes.
2613 - $val = str_replace( array( '&#8216;', '&#8217;', '&#8242;', '&prime;', '&rsquo;', '&lsquo;' ), "'", $val );
2614 -
2615 - return $val;
2631 + return str_replace( array( '&#8216;', '&#8217;', '&#8242;', '&prime;', '&rsquo;', '&lsquo;' ), "'", $val );
2616 2632 }
2617 2633
2618 2634 /**
2619 2635 * @param string $handle
@@ -2636,9 +2652,9 @@
2636 2652
2637 2653 $query = $wp_scripts->registered[ $handle ];
2638 2654
2639 2655 if ( is_object( $query ) && ! empty( $query->ver ) ) {
2640 - $ver = $query->ver;
2656 + return $query->ver;
2641 2657 }
2642 2658
2643 2659 return $ver;
2644 2660 }
@@ -2672,13 +2688,9 @@
2672 2688
2673 2689 if ( $user_id === 'current' ) {
2674 2690 $user_id = get_current_user_id();
2675 2691 } else {
2676 - if ( is_email( $user_id ) ) {
2677 - $user = get_user_by( 'email', $user_id );
2678 - } else {
2679 - $user = get_user_by( 'login', $user_id );
2680 - }
2692 + $user = is_email( $user_id ) ? get_user_by( 'email', $user_id ) : get_user_by( 'login', $user_id );
2681 2693
2682 2694 if ( $user ) {
2683 2695 $user_id = $user->ID;
2684 2696 }
@@ -2701,12 +2713,9 @@
2701 2713
2702 2714 extract( $atts ); // phpcs:ignore WordPress.PHP.DontExtract
2703 2715 ob_start();
2704 2716 include $filename;
2705 - $contents = ob_get_contents();
2706 - ob_end_clean();
2707 -
2708 - return $contents;
2717 + return ob_get_clean();
2709 2718 }
2710 2719
2711 2720 /**
2712 2721 * @param string $name
@@ -2738,31 +2747,31 @@
2738 2747 $column
2739 2748 );
2740 2749
2741 2750 // Create a unique field id if it has already been used.
2742 - if ( in_array( $key, $similar_keys, true ) ) {
2743 - $key = self::maybe_truncate_key_before_appending( $column, $key );
2751 + if ( ! in_array( $key, $similar_keys, true ) ) {
2752 + return $key;
2753 + }
2744 2754
2745 - /**
2746 - * Allow for a custom separator between the attempted key and the generated suffix.
2747 - *
2748 - * @since 5.2.03
2749 - *
2750 - * @param string $separator. Default empty.
2751 - * @param string $key the key without the added suffix.
2752 - */
2753 - $separator = apply_filters( 'frm_unique_' . $column . '_separator', '', $key );
2755 + $key = self::maybe_truncate_key_before_appending( $column, $key );
2754 2756
2755 - $suffix = 2;
2756 - do {
2757 - $key_check = $key . $separator . $suffix;
2758 - ++$suffix;
2759 - } while ( in_array( $key_check, $similar_keys, true ) );
2757 + /**
2758 + * Allow for a custom separator between the attempted key and the generated suffix.
2759 + *
2760 + * @since 5.2.03
2761 + *
2762 + * @param string $separator. Default empty.
2763 + * @param string $key the key without the added suffix.
2764 + */
2765 + $separator = apply_filters( 'frm_unique_' . $column . '_separator', '', $key );
2760 2766
2761 - $key = $key_check;
2762 - }//end if
2767 + $suffix = 2;
2768 + do {
2769 + $key_check = $key . $separator . $suffix;
2770 + ++$suffix;
2771 + } while ( in_array( $key_check, $similar_keys, true ) );
2763 2772
2764 - return $key;
2773 + return $key_check;
2765 2774 }
2766 2775
2767 2776 /**
2768 2777 * Avoid trying to append to a really long key,
@@ -2773,19 +2782,22 @@
2773 2782 *
2774 2783 * @return string
2775 2784 */
2776 2785 private static function maybe_truncate_key_before_appending( $column, $key ) {
2777 - if ( in_array( $column, array( 'form_key', 'field_key' ), true ) ) {
2778 - $max_key_length_before_truncating = 60;
2786 + if ( ! in_array( $column, array( 'form_key', 'field_key' ), true ) ) {
2787 + return $key;
2788 + }
2779 2789
2780 - if ( strlen( $key ) > $max_key_length_before_truncating ) {
2781 - $key = substr( $key, 0, $max_key_length_before_truncating );
2790 + $max_key_length_before_truncating = 60;
2782 2791
2783 - if ( is_numeric( $key ) ) {
2784 - $key .= 'a';
2785 - }
2792 + if ( strlen( $key ) > $max_key_length_before_truncating ) {
2793 + $key = substr( $key, 0, $max_key_length_before_truncating );
2794 +
2795 + if ( is_numeric( $key ) ) {
2796 + $key .= 'a';
2786 2797 }
2787 2798 }
2799 +
2788 2800 return $key;
2789 2801 }
2790 2802
2791 2803 /**
@@ -2797,9 +2809,9 @@
2797 2809 * @return string either the original key value, or an empty string if the key was too long.
2798 2810 */
2799 2811 private static function maybe_clear_long_key( $key, $column ) {
2800 2812 if ( 'field_key' === $column && strlen( $key ) >= 70 ) {
2801 - $key = '';
2813 + return '';
2802 2814 }
2803 2815 return $key;
2804 2816 }
2805 2817
@@ -2840,8 +2852,9 @@
2840 2852 if ( in_array( $key, $not_allowed, true ) ) {
2841 2853 $key .= 'a';
2842 2854 }
2843 2855 }
2856 +
2844 2857 return $key;
2845 2858 }
2846 2859
2847 2860 /**
@@ -2860,9 +2873,9 @@
2860 2873 if ( ! $record ) {
2861 2874 return false;
2862 2875 }
2863 2876
2864 - if ( empty( $post_values ) ) {
2877 + if ( ! $post_values ) {
2865 2878 $post_values = wp_unslash( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
2866 2879 }
2867 2880
2868 2881 $values = array(
@@ -2899,17 +2912,20 @@
2899 2912 *
2900 2913 * @return void
2901 2914 */
2902 2915 private static function prepare_field_arrays( $fields, $record, array &$values, $args ) {
2903 - if ( ! empty( $fields ) ) {
2904 - foreach ( (array) $fields as $field ) {
2905 - if ( ! self::is_admin_page() ) {
2906 - // Don't prep default values on the form settings page.
2907 - $field->default_value = apply_filters( 'frm_get_default_value', $field->default_value, $field, true );
2908 - }
2909 - $args['parent_form_id'] = $args['parent_form_id'] ?? $field->form_id;
2910 - self::fill_field_defaults( $field, $record, $values, $args );
2916 + if ( ! $fields ) {
2917 + return;
2918 + }
2919 +
2920 + foreach ( (array) $fields as $field ) {
2921 + if ( ! self::is_admin_page() ) {
2922 + // Don't prep default values on the form settings page.
2923 + $field->default_value = apply_filters( 'frm_get_default_value', $field->default_value, $field, true );
2911 2924 }
2925 +
2926 + $args['parent_form_id'] = $args['parent_form_id'] ?? $field->form_id;
2927 + self::fill_field_defaults( $field, $record, $values, $args );
2912 2928 }
2913 2929 }
2914 2930
2915 2931 /**
@@ -2924,24 +2940,24 @@
2924 2940 $post_values = $args['post_values'];
2925 2941
2926 2942 if ( $args['default'] ) {
2927 2943 $meta_value = $field->default_value;
2928 - } elseif ( $record->post_id && self::pro_is_installed() && isset( $field->field_options['post_field'] ) && $field->field_options['post_field'] ) {
2944 + } elseif ( $record->post_id && self::pro_is_installed() && ! empty( $field->field_options['post_field'] ) ) {
2929 2945 if ( ! isset( $field->field_options['custom_field'] ) ) {
2930 2946 $field->field_options['custom_field'] = '';
2931 2947 }
2932 2948
2933 - $meta_value = FrmProEntryMetaHelper::get_post_value(
2934 - $record->post_id,
2935 - $field->field_options['post_field'],
2936 - $field->field_options['custom_field'],
2937 - array(
2938 - 'truncate' => false,
2939 - 'type' => $field->type,
2940 - 'form_id' => $field->form_id,
2941 - 'field' => $field,
2942 - )
2943 - );
2949 + $meta_value = FrmProEntryMetaHelper::get_post_value(
2950 + $record->post_id,
2951 + $field->field_options['post_field'],
2952 + $field->field_options['custom_field'],
2953 + array(
2954 + 'truncate' => false,
2955 + 'type' => $field->type,
2956 + 'form_id' => $field->form_id,
2957 + 'field' => $field,
2958 + )
2959 + );
2944 2960 } else {
2945 2961 $meta_value = FrmEntryMeta::get_meta_value( $record, $field->id );
2946 2962 }//end if
2947 2963
@@ -2962,9 +2978,9 @@
2962 2978 $args['field_type'] = $field_type;
2963 2979
2964 2980 FrmFieldsHelper::prepare_edit_front_field( $field_array, $field, $values['id'], $args );
2965 2981
2966 - if ( ! isset( $field_array['unique'] ) || ! $field_array['unique'] ) {
2982 + if ( empty( $field_array['unique'] ) ) {
2967 2983 $field_array['unique_msg'] = '';
2968 2984 }
2969 2985
2970 2986 $field_array = array_merge( (array) $field->field_options, $field_array );
@@ -3041,10 +3057,11 @@
3041 3057 private static function fill_form_defaults( $post_values, array &$values ) {
3042 3058 $form_defaults = FrmFormsHelper::get_default_opts();
3043 3059
3044 3060 foreach ( $form_defaults as $opt => $default ) {
3061 + // phpcs:ignore Universal.Operators.StrictComparisons
3045 3062 if ( ! isset( $values[ $opt ] ) || $values[ $opt ] == '' ) {
3046 - $values[ $opt ] = $post_values && isset( $post_values['options'][ $opt ] ) ? $post_values['options'][ $opt ] : $default;
3063 + $values[ $opt ] = $post_values['options'][ $opt ] ?? $default;
3047 3064 }
3048 3065
3049 3066 unset( $opt, $default );
3050 3067 }
@@ -3054,9 +3071,9 @@
3054 3071 }
3055 3072
3056 3073 foreach ( array( 'before', 'after', 'submit' ) as $h ) {
3057 3074 if ( ! isset( $values[ $h . '_html' ] ) ) {
3058 - $values[ $h . '_html' ] = ( $post_values['options'][ $h . '_html' ] ?? FrmFormsHelper::get_default_html( $h ) );
3075 + $values[ $h . '_html' ] = $post_values['options'][ $h . '_html' ] ?? FrmFormsHelper::get_default_html( $h );
3059 3076 }
3060 3077 unset( $h );
3061 3078 }
3062 3079 }
@@ -3068,47 +3085,57 @@
3068 3085 *
3069 3086 * @return bool|int
3070 3087 */
3071 3088 public static function custom_style_value( $post_values ) {
3072 - if ( ! empty( $post_values ) && isset( $post_values['options']['custom_style'] ) ) {
3073 - $custom_style = absint( $post_values['options']['custom_style'] );
3074 - } else {
3075 - $frm_settings = self::get_settings();
3076 - $custom_style = ( $frm_settings->load_style !== 'none' );
3089 + if ( $post_values && isset( $post_values['options']['custom_style'] ) ) {
3090 + return absint( $post_values['options']['custom_style'] );
3077 3091 }
3078 3092
3079 - return $custom_style;
3093 + $frm_settings = self::get_settings();
3094 + return $frm_settings->load_style !== 'none';
3080 3095 }
3081 3096
3082 3097 /**
3098 + * Truncate a string.
3099 + *
3100 + * Note: By default, this function will allow for a few additional characters more than $length.
3101 + * If a string has no spaces, it allows up to 50 additional characters. To force a true length limit,
3102 + * use $force_length_limit = true.
3103 + *
3083 3104 * @param mixed $original_string
3084 3105 * @param int|string $length
3085 3106 * @param int $minword
3086 3107 * @param string $continue
3108 + * @param bool $force_length_limit Force the final string to never exceed the length limit.
3087 3109 *
3088 3110 * @return string
3089 3111 */
3090 - public static function truncate( $original_string, $length, $minword = 3, $continue = '...' ) {
3112 + public static function truncate( $original_string, $length, $minword = 3, $continue = '...', $force_length_limit = false ) {
3091 3113 if ( ! is_string( $original_string ) && ! is_int( $original_string ) ) {
3092 3114 return '';
3093 3115 }
3094 3116
3095 - $length = (int) $length;
3096 - $str = wp_strip_all_tags( (string) $original_string );
3097 - $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
3117 + $length = (int) $length;
3098 3118
3099 - if ( $length == 0 ) {
3119 + if ( $length === 0 ) {
3100 3120 return '';
3101 3121 }
3102 3122
3123 + $str = wp_strip_all_tags( (string) $original_string );
3124 + $original_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $str ) );
3125 +
3103 3126 if ( $length <= 10 ) {
3104 3127 $sub = self::mb_function( array( 'mb_substr', 'substr' ), array( $str, 0, $length ) );
3128 +
3129 + if ( $force_length_limit ) {
3130 + return $sub;
3131 + }
3132 +
3105 3133 return $sub . ( $length < $original_len ? $continue : '' );
3106 3134 }
3107 3135
3108 - $sub = '';
3109 - $len = 0;
3110 -
3136 + $sub = '';
3137 + $len = 0;
3111 3138 $words = self::mb_function( array( 'mb_split', 'explode' ), array( ' ', $str ) );
3112 3139
3113 3140 if ( ! is_array( $words ) ) {
3114 3141 return $original_string;
@@ -3131,10 +3158,21 @@
3131 3158
3132 3159 unset( $total_len, $word );
3133 3160 }
3134 3161
3135 - $sub = self::maybe_force_truncate_on_string_with_no_spaces( $sub, $length );
3162 + $sub = self::maybe_force_truncate_on_string_with_no_spaces( $sub, $length, $force_length_limit );
3136 3163
3164 + if ( $force_length_limit ) {
3165 + // Ensure the final string doesn't exceed the length limit.
3166 + $final_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub ) );
3167 +
3168 + if ( $final_len > $length ) {
3169 + return self::mb_function( array( 'mb_substr', 'substr' ), array( $sub, 0, $length ) );
3170 + }
3171 +
3172 + return $sub;
3173 + }
3174 +
3137 3175 return $sub . ( $len < $original_len ? $continue : '' );
3138 3176 }
3139 3177
3140 3178 /**
@@ -3141,27 +3179,39 @@
3141 3179 * If the string is still too long because there may not have been any spaces, force truncate.
3142 3180 *
3143 3181 * @since 6.5.4
3144 3182 *
3145 - * @param string $sub Current substring.
3146 - * @param int $length The length limit.
3183 + * @param string $sub Current substring.
3184 + * @param int $length The length limit.
3185 + * @param bool $force_length_limit Force the string to not exceed the length limit.
3147 3186 *
3148 3187 * @return string
3149 3188 */
3150 - private static function maybe_force_truncate_on_string_with_no_spaces( $sub, $length ) {
3151 - if ( strlen( $sub ) < $length + 50 ) {
3152 - // If the string isn't way over the limit, leave it.
3153 - return $sub;
3189 + private static function maybe_force_truncate_on_string_with_no_spaces( $sub, $length, $force_length_limit = false ) {
3190 + if ( ! $force_length_limit ) {
3191 + if ( strlen( $sub ) < $length + 50 ) {
3192 + // If the string isn't way over the limit, leave it.
3193 + return $sub;
3194 + }
3195 +
3196 + $first_space = strpos( $sub, ' ', $length );
3197 +
3198 + if ( false !== $first_space ) {
3199 + // Ignore anything with spaces.
3200 + return $sub;
3201 + }
3202 +
3203 + return substr( $sub, 0, $length + 10 );
3154 3204 }
3155 3205
3156 - $first_space = strpos( $sub, ' ', $length );
3206 + // When force_length_limit is true, ensure the string doesn't exceed the length.
3207 + $final_len = self::mb_function( array( 'mb_strlen', 'strlen' ), array( $sub ) );
3157 3208
3158 - if ( false !== $first_space ) {
3159 - // Ignore anything with spaces.
3160 - return $sub;
3209 + if ( $final_len > $length ) {
3210 + return self::mb_function( array( 'mb_substr', 'substr' ), array( $sub, 0, $length ) );
3161 3211 }
3162 3212
3163 - return substr( $sub, 0, $length + 10 );
3213 + return $sub;
3164 3214 }
3165 3215
3166 3216 /**
3167 3217 * @param array $function_names
@@ -3187,13 +3237,13 @@
3187 3237 *
3188 3238 * @return string
3189 3239 */
3190 3240 public static function get_formatted_time( $date, $date_format = '', $time_format = '' ) {
3191 - if ( empty( $date ) ) {
3241 + if ( ! $date ) {
3192 3242 return $date;
3193 3243 }
3194 3244
3195 - if ( empty( $date_format ) ) {
3245 + if ( ! $date_format ) {
3196 3246 $date_format = get_option( 'date_format' );
3197 3247 }
3198 3248
3199 3249 if ( preg_match( '/^\d{1-2}\/\d{1-2}\/\d{4}$/', $date ) && self::pro_is_installed() ) {
@@ -3201,11 +3251,10 @@
3201 3251 $date = FrmProAppHelper::convert_date( $date, $frmpro_settings->date_format, 'Y-m-d' );
3202 3252 }
3203 3253
3204 3254 $formatted = self::get_localized_date( $date_format, $date );
3255 + $do_time = gmdate( 'H:i:s', strtotime( $date ) ) !== '00:00:00';
3205 3256
3206 - $do_time = ( gmdate( 'H:i:s', strtotime( $date ) ) !== '00:00:00' );
3207 -
3208 3257 if ( $do_time ) {
3209 3258 $formatted .= self::add_time_to_date( $time_format, $date );
3210 3259 }
3211 3260
@@ -3218,20 +3267,19 @@
3218 3267 *
3219 3268 * @return string
3220 3269 */
3221 3270 private static function add_time_to_date( $time_format, $date ) {
3222 - if ( empty( $time_format ) ) {
3271 + if ( ! $time_format ) {
3223 3272 $time_format = get_option( 'time_format' );
3224 3273 }
3225 3274
3226 3275 $trimmed_format = trim( $time_format );
3227 - $time = '';
3228 3276
3229 - if ( $time_format && ! empty( $trimmed_format ) ) {
3230 - $time = ' ' . __( 'at', 'formidable' ) . ' ' . self::get_localized_date( $time_format, $date );
3277 + if ( $time_format && $trimmed_format ) {
3278 + return ' ' . __( 'at', 'formidable' ) . ' ' . self::get_localized_date( $time_format, $date );
3231 3279 }
3232 3280
3233 - return $time;
3281 + return '';
3234 3282 }
3235 3283
3236 3284 /**
3237 3285 * @since 2.0.8
@@ -3242,9 +3290,8 @@
3242 3290 * @return string
3243 3291 */
3244 3292 public static function get_localized_date( $date_format, $date ) {
3245 3293 $date = get_date_from_gmt( $date );
3246 -
3247 3294 return date_i18n( $date_format, strtotime( $date ) );
3248 3295 }
3249 3296
3250 3297 /**
@@ -3253,17 +3300,12 @@
3253 3300 * @param int $from In seconds.
3254 3301 * @param int|string $to In seconds.
3255 3302 * @param int|string $levels Number of time units to include or a specific unit.
3256 3303 *
3257 - * @return string $time_ago
3304 + * @return string Time ago.
3258 3305 */
3259 3306 public static function human_time_diff( $from, $to = '', $levels = 1 ) {
3260 - if ( empty( $to ) && 0 !== $to ) {
3261 - $now = new DateTime();
3262 - } else {
3263 - $now = new DateTime( '@' . $to );
3264 - }
3265 -
3307 + $now = ! $to && 0 !== $to ? new DateTime() : new DateTime( '@' . $to );
3266 3308 $ago = new DateTime( '@' . $from );
3267 3309
3268 3310 // Get the time difference
3269 3311 $diff_object = $now->diff( $ago );
@@ -3291,9 +3333,9 @@
3291 3333 $levels = 1;
3292 3334 }
3293 3335
3294 3336 foreach ( $time_strings as $k => $v ) {
3295 - if ( isset( $diff[ $k ] ) && $diff[ $k ] ) {
3337 + if ( ! empty( $diff[ $k ] ) ) {
3296 3338 $time_strings[ $k ] = $diff[ $k ] . ' ' . ( $diff[ $k ] > 1 ? $v[1] : $v[0] );
3297 3339 } elseif ( isset( $diff[ $k ] ) && count( $time_strings ) === 1 ) {
3298 3340 // Account for 0.
3299 3341 $time_strings[ $k ] = $diff[ $k ] . ' ' . $v[1];
@@ -3301,13 +3343,12 @@
3301 3343 unset( $time_strings[ $k ] );
3302 3344 }
3303 3345 }
3304 3346
3305 - $levels_deep = apply_filters( 'frm_time_ago_levels', $levels, compact( 'time_strings', 'from', 'to' ) );
3306 - $time_strings = array_slice( $time_strings, 0, absint( $levels_deep ) );
3307 - $time_ago_string = implode( ' ', $time_strings );
3347 + $levels_deep = apply_filters( 'frm_time_ago_levels', $levels, compact( 'time_strings', 'from', 'to' ) );
3348 + $time_strings = array_slice( $time_strings, 0, absint( $levels_deep ) );
3308 3349
3309 - return $time_ago_string;
3350 + return implode( ' ', $time_strings );
3310 3351 }
3311 3352
3312 3353 /**
3313 3354 * @since 4.05.01
@@ -3327,9 +3368,8 @@
3327 3368 return $diff[ $return[ $unit ] ];
3328 3369 }
3329 3370
3330 3371 $total = $diff['days'] * self::convert_time( 'd', $unit );
3331 -
3332 3372 $times = array( 'h', 'i', 's' );
3333 3373
3334 3374 foreach ( $times as $time ) {
3335 3375 if ( ! isset( $diff[ $time ] ) ) {
@@ -3378,12 +3418,13 @@
3378 3418 return $unit;
3379 3419 }
3380 3420
3381 3421 foreach ( $units as $u => $strings ) {
3382 - if ( in_array( $unit, $strings ) ) {
3422 + if ( in_array( $unit, $strings, true ) ) {
3383 3423 return $u;
3384 3424 }
3385 3425 }
3426 +
3386 3427 return 1;
3387 3428 }
3388 3429
3389 3430 /**
@@ -3443,9 +3484,9 @@
3443 3484 *
3444 3485 * @return int
3445 3486 */
3446 3487 public static function get_last_record_num( $r_count, $current_p, $p_size ) {
3447 - return ( $r_count < $current_p * $p_size ? $r_count : $current_p * $p_size );
3488 + return $r_count < $current_p * $p_size ? $r_count : $current_p * $p_size;
3448 3489 }
3449 3490
3450 3491 /**
3451 3492 * @param int $r_count
@@ -3454,8 +3495,9 @@
3454 3495 *
3455 3496 * @return int
3456 3497 */
3457 3498 public static function get_first_record_num( $r_count, $current_p, $p_size ) {
3499 + // phpcs:ignore Universal.Operators.StrictComparisons
3458 3500 if ( $current_p == 1 ) {
3459 3501 return 1;
3460 3502 }
3461 3503 return self::get_last_record_num( $r_count, $current_p - 1, $p_size ) + 1;
@@ -3487,9 +3529,9 @@
3487 3529 if ( ! isset( $l3 ) ) {
3488 3530 $l3 = $name;
3489 3531 }
3490 3532
3491 - $this_val = $p == $last ? $jv['value'] : array();
3533 + $this_val = $p === $last ? $jv['value'] : array();
3492 3534
3493 3535 switch ( $p ) {
3494 3536 case 0:
3495 3537 $l1 = $name;
@@ -3528,8 +3570,9 @@
3528 3570 *
3529 3571 * @return void
3530 3572 */
3531 3573 public static function add_value_to_array( $name, $l1, $val, &$vars ) {
3574 + // phpcs:ignore Universal.Operators.StrictComparisons
3532 3575 if ( $name == '' ) {
3533 3576 $vars[] = $val;
3534 3577 } elseif ( ! isset( $vars[ $l1 ] ) ) {
3535 3578 $vars[ $l1 ] = $val;
@@ -3545,16 +3588,16 @@
3545 3588 */
3546 3589 public static function maybe_add_tooltip( $name, $class = 'closed', $form_name = '' ) {
3547 3590 $tooltips = array(
3548 3591 'action_title' => __( 'Give this action a label for easy reference.', 'formidable' ),
3549 - 'email_to' => __( 'Add one or more recipient addresses separated by a ",". FORMAT: Name <[email protected]> or [email protected]. [default-email] is the address set in the global "Default Email Address" settings.', 'formidable' ),
3592 + 'email_to' => __( 'Add one or more recipient addresses separated by a ",". FORMAT: Name <[email protected]> or [email protected]. [default-email] is the address set in the global "Default Email Address" settings.', 'formidable' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3550 3593 'cc' => __( 'Add CC addresses separated by a ",". FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
3551 3594 'bcc' => __( 'Add BCC addresses separated by a ",". FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
3552 - 'reply_to' => __( 'If you would like a different reply to address than the "from" address, add a single address here. FORMAT: Name <[email protected]> or [email protected].', 'formidable' ),
3595 + 'reply_to' => __( 'If you would like a different reply to address than the "from" address, add a single address here. FORMAT: Name <[email protected]> or [email protected].', 'formidable' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3553 3596 'from' => __( 'Enter the name and/or email address of the sender. FORMAT: John Bates <[email protected]> or [email protected].', 'formidable' ),
3554 3597 /* translators: %1$s: Form name, %2$s: Date */
3555 - 'email_subject' => esc_attr( sprintf( __( 'If you leave the subject blank, the default will be used: %1$s Form submitted on %2$s', 'formidable' ), $form_name, self::site_name() ) ),
3556 - 'new_tab' => __( 'This option will open the link in a new browser tab. Please note that some popup blockers may prevent this from happening, in which case the link will be displayed.', 'formidable' ),
3598 + 'email_subject' => esc_attr( sprintf( __( 'If you leave the subject blank, the default will be used: %1$s Form submitted on %2$s', 'formidable' ), $form_name, self::site_name() ) ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3599 + 'new_tab' => __( 'This option will open the link in a new browser tab. Please note that some popup blockers may prevent this from happening, in which case the link will be displayed.', 'formidable' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3557 3600 );
3558 3601
3559 3602 if ( ! isset( $tooltips[ $name ] ) ) {
3560 3603 return;
@@ -3559,9 +3602,9 @@
3559 3602 if ( ! isset( $tooltips[ $name ] ) ) {
3560 3603 return;
3561 3604 }
3562 3605
3563 - if ( 'open' == $class ) {
3606 + if ( 'open' === $class ) {
3564 3607 echo ' frm_help"';
3565 3608 } else {
3566 3609 echo ' class="frm_help"';
3567 3610 }
@@ -3567,9 +3610,9 @@
3567 3610 }
3568 3611
3569 3612 echo ' title="' . esc_attr( $tooltips[ $name ] );
3570 3613
3571 - if ( 'open' != $class ) {
3614 + if ( 'open' !== $class ) {
3572 3615 echo '"';
3573 3616 }
3574 3617 }
3575 3618
@@ -3582,8 +3625,9 @@
3582 3625 *
3583 3626 * @return void
3584 3627 */
3585 3628 public static function select_current_page( $page, $current_page, $action = array() ) {
3629 + // phpcs:ignore Universal.Operators.StrictComparisons
3586 3630 if ( $current_page != $page ) {
3587 3631 return;
3588 3632 }
3589 3633
@@ -3592,9 +3636,9 @@
3592 3636 if ( 'lite-reports' === $frm_action ) {
3593 3637 $frm_action = 'reports';
3594 3638 }
3595 3639
3596 - if ( empty( $action ) || ( ! empty( $frm_action ) && in_array( $frm_action, $action ) ) ) {
3640 + if ( ! $action || ( $frm_action && in_array( $frm_action, $action, true ) ) ) {
3597 3641 echo ' class="current_page"';
3598 3642 }
3599 3643 }
3600 3644
@@ -3624,12 +3668,10 @@
3624 3668
3625 3669 // Add extra slashes for \r\n since WP strips them.
3626 3670 $post_content = str_replace( array( '\\r', '\\n', '\\u', '\\t' ), array( '\\\\r', '\\\\n', '\\\\u', '\\\\t' ), $post_content );
3627 3671
3628 - // allow for &quot
3629 - $post_content = str_replace( '&quot;', '\\"', $post_content );
3630 -
3631 - return $post_content;
3672 + // Allow for &quot
3673 + return str_replace( '&quot;', '\\"', $post_content );
3632 3674 }
3633 3675
3634 3676 /**
3635 3677 * @param array|string $val
@@ -3647,15 +3689,17 @@
3647 3689 foreach ( $val as $k1 => $v1 ) {
3648 3690 self::prepare_action_slashes( $v1, $k1, $post_content[ $key ] );
3649 3691 unset( $k1, $v1 );
3650 3692 }
3651 - } else {
3652 - // Strip all slashes so everything is the same, no matter where the value is coming from
3653 - $val = stripslashes( $val );
3654 3693
3655 - // Add backslashes before double quotes and forward slashes only
3656 - $post_content[ $key ] = addcslashes( $val, '"\\/' );
3694 + return;
3657 3695 }
3696 +
3697 + // Strip all slashes so everything is the same, no matter where the value is coming from
3698 + $val = stripslashes( $val );
3699 +
3700 + // Add backslashes before double quotes and forward slashes only
3701 + $post_content[ $key ] = addcslashes( $val, '"\\/' );
3658 3702 }
3659 3703
3660 3704 /**
3661 3705 * Check for either json or serialized data. This is temporary while transitioning
@@ -3671,13 +3715,9 @@
3671 3715 if ( is_array( $value ) ) {
3672 3716 return;
3673 3717 }
3674 3718
3675 - if ( is_serialized( $value ) ) {
3676 - $value = self::maybe_unserialize_array( $value );
3677 - } else {
3678 - $value = self::maybe_json_decode( $value, false );
3679 - }
3719 + $value = is_serialized( $value ) ? self::maybe_unserialize_array( $value ) : self::maybe_json_decode( $value, false );
3680 3720 }
3681 3721
3682 3722 /**
3683 3723 * Safely unserialize an array if necessary.
@@ -3694,19 +3734,15 @@
3694 3734 return $value;
3695 3735 }
3696 3736
3697 3737 // Since we only expect an array, skip anything that doesn't start with a:.
3698 - if ( ! is_serialized( $value ) || 'a:' !== substr( $value, 0, 2 ) ) {
3738 + if ( ! is_serialized( $value ) || ! str_starts_with( $value, 'a:' ) ) {
3699 3739 return $value;
3700 3740 }
3701 3741
3702 3742 $parsed = FrmSerializedStringParserHelper::get()->parse( $value );
3703 3743
3704 - if ( is_array( $parsed ) ) {
3705 - $value = $parsed;
3706 - }
3707 -
3708 - return $value;
3744 + return is_array( $parsed ) ? $parsed : $value;
3709 3745 }
3710 3746
3711 3747 /**
3712 3748 * Decode a JSON string.
@@ -3711,12 +3747,12 @@
3711 3747 /**
3712 3748 * Decode a JSON string.
3713 3749 * Do not switch shortcodes like [24] to array unless intentional ie XML values.
3714 3750 *
3715 - * @param mixed $string
3716 - * @param bool $single_to_array
3751 + * @param array|string|null $string
3752 + * @param bool $single_to_array
3717 3753 *
3718 - * @return mixed
3754 + * @return array|string|null
3719 3755 */
3720 3756 public static function maybe_json_decode( $string, $single_to_array = true ) {
3721 3757 if ( is_array( $string ) || is_null( $string ) ) {
3722 3758 return $string;
@@ -3721,21 +3757,17 @@
3721 3757 if ( is_array( $string ) || is_null( $string ) ) {
3722 3758 return $string;
3723 3759 }
3724 3760
3725 - $new_string = json_decode( $string, true );
3761 + $new_string = json_decode( $string, true );
3762 + $single_value = false;
3726 3763
3727 - if ( function_exists( 'json_last_error' ) ) {
3728 - // php 5.3+
3729 - $single_value = false;
3764 + if ( ! $single_to_array ) {
3765 + $single_value = is_array( $new_string ) && count( $new_string ) === 1 && isset( $new_string[0] );
3766 + }
3730 3767
3731 - if ( ! $single_to_array ) {
3732 - $single_value = is_array( $new_string ) && count( $new_string ) === 1 && isset( $new_string[0] );
3733 - }
3734 -
3735 - if ( json_last_error() == JSON_ERROR_NONE && is_array( $new_string ) && ! $single_value ) {
3736 - $string = $new_string;
3737 - }
3768 + if ( json_last_error() === JSON_ERROR_NONE && is_array( $new_string ) && ! $single_value ) {
3769 + return $new_string;
3738 3770 }
3739 3771
3740 3772 return $string;
3741 3773 }
@@ -3754,8 +3786,9 @@
3754 3786 if ( function_exists( 'mb_check_encoding' ) && function_exists( 'mb_convert_encoding' ) ) {
3755 3787 if ( mb_check_encoding( $value, $from_format ) ) {
3756 3788 return mb_convert_encoding( $value, $to_format, $from_format );
3757 3789 }
3790 +
3758 3791 return $value;
3759 3792 }
3760 3793
3761 3794 if ( function_exists( 'iconv' ) ) {
@@ -3774,9 +3807,9 @@
3774 3807 * Reformat the json serialized array in name => value array.
3775 3808 *
3776 3809 * @since 4.02.03
3777 3810 *
3778 - * @param array $form
3811 + * @param array $form
3779 3812 *
3780 3813 * @return void
3781 3814 */
3782 3815 public static function format_form_data( &$form ) {
@@ -3788,16 +3821,17 @@
3788 3821 }
3789 3822
3790 3823 $key = $input['name'];
3791 3824
3792 - if ( isset( $formatted[ $key ] ) ) {
3793 - if ( is_array( $formatted[ $key ] ) ) {
3794 - $formatted[ $key ][] = $input['value'];
3795 - } else {
3796 - $formatted[ $key ] = array( $formatted[ $key ], $input['value'] );
3797 - }
3825 + if ( ! isset( $formatted[ $key ] ) ) {
3826 + $formatted[ $key ] = $input['value'];
3827 + continue;
3828 + }
3829 +
3830 + if ( is_array( $formatted[ $key ] ) ) {
3831 + $formatted[ $key ][] = $input['value'];
3798 3832 } else {
3799 - $formatted[ $key ] = $input['value'];
3833 + $formatted[ $key ] = array( $formatted[ $key ], $input['value'] );
3800 3834 }
3801 3835 }
3802 3836
3803 3837 parse_str( http_build_query( $formatted ), $form );
@@ -3810,12 +3844,9 @@
3810 3844 *
3811 3845 * @return string
3812 3846 */
3813 3847 public static function maybe_json_encode( $value ) {
3814 - if ( is_array( $value ) ) {
3815 - $value = wp_json_encode( $value );
3816 - }
3817 - return $value;
3848 + return is_array( $value ) ? wp_json_encode( $value ) : $value;
3818 3849 }
3819 3850
3820 3851 /**
3821 3852 * Echo The javascript to open and highlight the Formidable menu
@@ -3828,13 +3859,13 @@
3828 3859 */
3829 3860 public static function maybe_highlight_menu( $post_type ) {
3830 3861 global $post;
3831 3862
3832 - if ( isset( $_REQUEST['post_type'] ) && $_REQUEST['post_type'] != $post_type ) {
3863 + if ( isset( $_REQUEST['post_type'] ) && $_REQUEST['post_type'] !== $post_type ) {
3833 3864 return;
3834 3865 }
3835 3866
3836 - if ( is_object( $post ) && $post->post_type != $post_type ) {
3867 + if ( is_object( $post ) && $post->post_type !== $post_type ) {
3837 3868 return;
3838 3869 }
3839 3870
3840 3871 self::load_admin_wide_js();
@@ -3850,10 +3881,9 @@
3850 3881 *
3851 3882 * @return void
3852 3883 */
3853 3884 public static function load_admin_wide_js( $load = true ) {
3854 - $version = self::plugin_version();
3855 - wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), $version );
3885 + wp_register_script( 'formidable_admin_global', self::plugin_url() . '/js/formidable_admin_global.js', array( 'jquery' ), self::plugin_version() );
3856 3886
3857 3887 $global_strings = array(
3858 3888 'updating_msg' => __( 'Please wait while your site updates.', 'formidable' ),
3859 3889 'deauthorize' => __( 'Are you sure you want to deauthorize Formidable Forms on this site?', 'formidable' ),
@@ -3859,9 +3889,9 @@
3859 3889 'deauthorize' => __( 'Are you sure you want to deauthorize Formidable Forms on this site?', 'formidable' ),
3860 3890 'url' => self::plugin_url(),
3861 3891 'app_url' => 'https://formidableforms.com/',
3862 3892 'applicationsUrl' => admin_url( 'admin.php?page=formidable-applications' ),
3863 - 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ),
3893 + 'canAccessApplicationDashboard' => current_user_can( is_callable( 'FrmProApplicationsHelper::get_required_templates_capability' ) ? FrmProApplicationsHelper::get_required_templates_capability() : 'frm_edit_forms' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3864 3894 'loading' => __( 'Loading&hellip;', 'formidable' ),
3865 3895 'nonce' => wp_create_nonce( 'frm_ajax' ),
3866 3896 'proIncludesSliderJs' => is_callable( 'FrmProFormsHelper::prepare_custom_currency' ),
3867 3897 'inboxSlideIn' => FrmInbox::get_inbox_slide_in_value_for_js(),
@@ -3927,9 +3957,9 @@
3927 3957 'valid_default' => __( 'Default value will pass form validation', 'formidable' ),
3928 3958 'no_valid_default' => __( 'Default value will NOT pass form validation', 'formidable' ),
3929 3959 'confirm' => __( 'Are you sure?', 'formidable' ),
3930 3960 'conf_delete' => __( 'Are you sure you want to delete this field and all data associated with it?', 'formidable' ),
3931 - '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' ),
3961 + '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' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3932 3962 'conf_no_repeat' => __( 'Warning: If you have entries with multiple rows, all but the first row will be lost.', 'formidable' ),
3933 3963 'default_unique' => FrmFieldsHelper::default_unique_msg(),
3934 3964 'default_conf' => __( 'The entered values do not match', 'formidable' ),
3935 3965 'enter_email' => __( 'Enter Email', 'formidable' ),
@@ -3935,9 +3965,9 @@
3935 3965 'enter_email' => __( 'Enter Email', 'formidable' ),
3936 3966 'confirm_email' => __( 'Confirm Email', 'formidable' ),
3937 3967 'conditional_text' => __( 'Conditional content here', 'formidable' ),
3938 3968 'new_option' => __( 'New Option', 'formidable' ),
3939 - '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' ),
3969 + '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' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3940 3970 'enter_password' => __( 'Enter Password', 'formidable' ),
3941 3971 'confirm_password' => __( 'Confirm Password', 'formidable' ),
3942 3972 'import_complete' => __( 'Import Complete', 'formidable' ),
3943 3973 'updating' => __( 'Please wait while your site updates.', 'formidable' ),
@@ -3951,13 +3981,15 @@
3951 3981 'text_shortcodes' => __( 'This calculation may have shortcodes that work in text calculations but not numeric calculations.', 'formidable' ),
3952 3982 /* translators: %d is the number of allowed actions per form */
3953 3983 'only_one_action' => sprintf( __( 'This form action is limited to %d per form.', 'formidable' ), 1 ),
3954 3984 'edit_action_text' => __( 'Please edit the existing form action.', 'formidable' ),
3985 + 'only_one_payment_action' => __( 'This form already has a payment action, and is currently limited to a single payment action.', 'formidable' ),
3986 + 'only_one_stripe_action' => __( 'This form already has a payment action. Multiple Stripe actions are available when using the Stripe add-on, available for Formidable Business licenses and higher.', 'formidable' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3955 3987 'unsafe_params' => FrmFormsHelper::reserved_words(),
3956 3988 /* Translators: %s is the name of a Detail Page Slug that is a reserved word.*/
3957 - 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ),
3989 + 'slug_is_reserved' => sprintf( __( 'The Detail Page Slug "%s" is reserved by WordPress. This may cause problems. Is this intentional?', 'formidable' ), '****' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3958 3990 /* 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. */
3959 - 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ),
3991 + 'param_is_reserved' => sprintf( __( 'The parameter "%s" is reserved by WordPress. This may cause problems when included in the URL. Is this intentional? ', 'formidable' ), '****' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
3960 3992 'reserved_words' => __( 'See the list of reserved words in WordPress.', 'formidable' ),
3961 3993 'repeat_limit_min' => __( 'Please enter a Repeat Limit that is greater than 1.', 'formidable' ),
3962 3994 'checkbox_limit' => __( 'Please select a limit between 0 and 200.', 'formidable' ),
3963 3995 'install' => __( 'Install', 'formidable' ),
@@ -3978,11 +4010,14 @@
3978 4010 'holdShiftMsg' => esc_html__( 'You can hold %1$sShift%2$s on your keyboard to select multiple fields', 'formidable' ),
3979 4011 'noTitleText' => FrmFormsHelper::get_no_title_text(),
3980 4012
3981 4013 // In older versions this event listener causes the section to immediately close again
3982 - // when the h3 element is clicked. It's only required in WP 6.7+.
4014 + // When the h3 element is clicked. It's only required in WP 6.7+.
3983 4015 'requireAccordionTitleClickListener' => version_compare( $wp_version, '6.7', '>=' ),
3984 4016 );
4017 +
4018 + self::add_form_builder_modal_data( $admin_script_strings );
4019 +
3985 4020 /**
3986 4021 * @param array $admin_script_strings
3987 4022 */
3988 4023 $admin_script_strings = apply_filters( 'frm_admin_script_strings', $admin_script_strings );
@@ -3995,8 +4030,80 @@
3995 4030 }//end if
3996 4031 }
3997 4032
3998 4033 /**
4034 + * @param array $admin_script_strings
4035 + *
4036 + * @return void
4037 + */
4038 + private static function add_form_builder_modal_data( &$admin_script_strings ) {
4039 + if ( ! self::is_form_builder_page() || self::pro_is_installed() ) {
4040 + return;
4041 + }
4042 +
4043 + $stripe_connected = FrmStrpLiteConnectHelper::at_least_one_mode_is_setup();
4044 + $square_connected = FrmSquareLiteConnectHelper::at_least_one_mode_is_setup();
4045 + $paypal_connected = FrmPayPalLiteConnectHelper::at_least_one_mode_is_setup();
4046 + $gateway_connected = $stripe_connected || $square_connected || $paypal_connected;
4047 + $payments_settings_url = FrmStrpLiteAppController::get_payments_settings_url();
4048 +
4049 + if ( ! $gateway_connected ) {
4050 + // This modal shows when user clicks on one of the pricing fields and no payment gateways configured.
4051 + $admin_script_strings['paymentsSettingsModal'] = array(
4052 + 'title' => __( 'Setup a Payment Gateway first', 'formidable' ),
4053 + 'msg' => __( 'To use the payment fields, please install and configure a payment gateway in your account settings.', 'formidable' ),
4054 + 'closeText' => __( 'Close', 'formidable' ),
4055 + 'actionUrl' => $payments_settings_url,
4056 + 'actionText' => __( 'Go to Payment Settings', 'formidable' ),
4057 + 'noCenter' => true,
4058 + );
4059 + }
4060 +
4061 + // This modal shows on load once after upgrading the plugin.
4062 + $show_pricing_fields_modal = get_option( 'frm_show_pricing_fields_modal' );
4063 +
4064 + if ( ! $show_pricing_fields_modal ) {
4065 + return;
4066 + }
4067 +
4068 + $admin_script_strings['pricingFieldsModal'] = array(
4069 + 'title' => esc_html__( 'Start Accepting Payments Today!', 'formidable' ),
4070 + 'img' => esc_url( self::plugin_url() . '/images/upsell/pricing-fields.png' ),
4071 + 'noCenter' => true,
4072 + );
4073 +
4074 + if ( $gateway_connected ) {
4075 + $gateway_texts = array();
4076 +
4077 + if ( $stripe_connected ) {
4078 + $gateway_texts['stripe'] = esc_html__( 'Stripe', 'formidable' );
4079 + }
4080 +
4081 + if ( $square_connected ) {
4082 + $gateway_texts['square'] = esc_html__( 'Square', 'formidable' );
4083 + }
4084 +
4085 + if ( $paypal_connected ) {
4086 + $gateway_texts['paypal'] = esc_html__( 'PayPal', 'formidable' );
4087 + }
4088 +
4089 + $admin_script_strings['pricingFieldsModal']['msg'] = sprintf(
4090 + // translators: %s: Stripe, Square, or PayPal.
4091 + esc_html__( 'You already have %s connected, so these have already been unlocked.', 'formidable' ),
4092 + esc_html( implode( ' ' . esc_html__( 'and', 'formidable' ) . ' ', $gateway_texts ) )
4093 + );
4094 + } else {
4095 + $admin_script_strings['pricingFieldsModal']['closeText'] = __( 'I\'ll do it later!', 'formidable' );
4096 + $admin_script_strings['pricingFieldsModal']['actionText'] = __( 'Setup Payments Now', 'formidable' );
4097 + $admin_script_strings['pricingFieldsModal']['actionUrl'] = $payments_settings_url;
4098 + // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
4099 + $admin_script_strings['pricingFieldsModal']['msg'] = __( 'We\'ve unlocked Product, Quantity, and Total fields for Lite users! You can now transform your forms into checkout pages. To start collecting revenue, simply connect your preferred payment gateway (Stripe, Square, or PayPal) in your settings.', 'formidable' );
4100 + }//end if
4101 +
4102 + delete_option( 'frm_show_pricing_fields_modal' );
4103 + }
4104 +
4105 + /**
3999 4106 * Get the no label text.
4000 4107 *
4001 4108 * @since 6.25.1
4002 4109 *
@@ -4061,11 +4168,11 @@
4061 4168 return;
4062 4169 }
4063 4170
4064 4171 $wp_list_table = _get_list_table( 'WP_Plugins_List_Table' );
4065 - echo '<tr class="plugin-update-tr active"><th colspan="' . absint( $wp_list_table->get_column_count() ) . '" class="check-column plugin-update colspanchange"><div class="update-message">' .
4066 - esc_html__( 'You are running an outdated version of Formidable. This plugin may not work correctly if you do not update Formidable.', 'formidable' ) .
4067 - '</div></td></tr>';
4172 + echo '<tr class="plugin-update-tr active"><th colspan="' . absint( $wp_list_table->get_column_count() ) . '" class="check-column plugin-update colspanchange"><div class="update-message">' . // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
4173 + esc_html__( 'You are running an outdated version of Formidable. This plugin may not work correctly if you do not update Formidable.', 'formidable' ) .
4174 + '</div></td></tr>';
4068 4175 }
4069 4176
4070 4177 /**
4071 4178 * If Pro is far outdated, show a message.
@@ -4116,11 +4223,12 @@
4116 4223 private static function php_version_notice() {
4117 4224 $message = array();
4118 4225
4119 4226 if ( version_compare( phpversion(), '7.0', '<' ) ) {
4120 - $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' );
4227 + $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' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
4121 4228 }
4122 4229
4230 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
4123 4231 foreach ( $message as $m ) {
4124 4232 ?>
4125 4233 <div class="frm-banner-alert frm_error_style frm_previous_install">
4126 4234 <?php echo esc_html( $m ); ?>
@@ -4126,8 +4234,9 @@
4126 4234 <?php echo esc_html( $m ); ?>
4127 4235 </div>
4128 4236 <?php
4129 4237 }
4238 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
4130 4239 }
4131 4240
4132 4241 /**
4133 4242 * @param string $type
@@ -4226,12 +4335,12 @@
4226 4335 'zu' => __( 'Zulu', 'formidable' ),
4227 4336 );
4228 4337
4229 4338 if ( $type === 'captcha' ) {
4230 - // remove the languages unavailable for the captcha
4339 + // Remove the languages unavailable for the captcha
4231 4340 $unset = array( 'sq', 'bs', 'eo', 'fo', 'fr-CH', 'sr-SR', 'ar-DZ', 'be', 'cy-GB', 'kk', 'km', 'ky', 'lb', 'mk', 'nb', 'nn', 'rm', 'tj' );
4232 4341 } else {
4233 - // remove the languages unavailable for the datepicker
4342 + // Remove the languages unavailable for the datepicker
4234 4343 $unset = array( 'fil', 'fr-CA', 'de-AT', 'de-CH', 'iw', 'hi', 'pt', 'pt-PT', 'es-419', 'mr', 'lo', 'kn', 'si', 'gu', 'bn', 'zu', 'ur', 'te', 'sw', 'am' );
4235 4344 }
4236 4345
4237 4346 $locales = array_diff_key( $locales, array_flip( $unset ) );
@@ -4246,11 +4355,9 @@
4246 4355 *
4247 4356 * @type string $type
4248 4357 * }
4249 4358 */
4250 - $locales = apply_filters( 'frm_locales', $locales, compact( 'type' ) );
4251 -
4252 - return $locales;
4359 + return apply_filters( 'frm_locales', $locales, compact( 'type' ) );
4253 4360 }
4254 4361
4255 4362 /**
4256 4363 * @return string
@@ -4262,8 +4369,9 @@
4262 4369 if ( is_object( $settings ) && ! empty( $settings->menu_icon ) ) {
4263 4370 return $settings->menu_icon;
4264 4371 }
4265 4372 }
4373 +
4266 4374 return 'frmfont frm_logo_icon';
4267 4375 }
4268 4376
4269 4377 /**
@@ -4281,10 +4389,9 @@
4281 4389 * @type array $input_attrs Attributes of value input.
4282 4390 * }
4283 4391 */
4284 4392 public static function images_dropdown( $args ) {
4285 - $args = self::fill_default_images_dropdown_args( $args );
4286 -
4393 + $args = self::fill_default_images_dropdown_args( $args );
4287 4394 $input_attrs_str = self::get_images_dropdown_input_attrs( $args );
4288 4395 ob_start();
4289 4396 include self::plugin_path() . '/classes/views/shared/images-dropdown.php';
4290 4397 $output = ob_get_clean();
@@ -4455,9 +4562,9 @@
4455 4562 if ( ! empty( $option['custom_attrs'] ) && is_array( $option['custom_attrs'] ) ) {
4456 4563 $html_attrs_arr = array();
4457 4564
4458 4565 foreach ( $option['custom_attrs'] as $key => $value ) {
4459 - if ( in_array( $key, array( 'type', 'class', 'data-value' ) ) ) {
4566 + if ( in_array( $key, array( 'type', 'class', 'data-value' ), true ) ) {
4460 4567 continue;
4461 4568 }
4462 4569
4463 4570 $html_attrs_arr[] = sprintf( '%s="%s"', esc_attr( $key ), esc_attr( $value ) );
@@ -4519,11 +4626,9 @@
4519 4626 *
4520 4627 * @return array
4521 4628 */
4522 4629 public static function maybe_filter_array( $values, $keys ) {
4523 - $allow_unfiltered_html = self::allow_unfiltered_html();
4524 -
4525 - if ( $allow_unfiltered_html ) {
4630 + if ( self::allow_unfiltered_html() ) {
4526 4631 return $values;
4527 4632 }
4528 4633
4529 4634 foreach ( $keys as $key ) {
@@ -4547,9 +4652,9 @@
4547 4652 * @return string
4548 4653 */
4549 4654 public static function maybe_kses( $value, $allowed = 'all' ) {
4550 4655 if ( self::should_never_allow_unfiltered_html() ) {
4551 - $value = self::kses( $value, $allowed );
4656 + return self::kses( $value, $allowed );
4552 4657 }
4553 4658 return $value;
4554 4659 }
4555 4660
@@ -4565,12 +4670,12 @@
4565 4670 */
4566 4671 public static function input_key_is_safe( $key, $context = 'display' ) {
4567 4672 if ( 'update' === $context && in_array( $key, array( 'opt', 'label' ), true ) ) {
4568 4673 $safe = true;
4569 - } elseif ( 0 === strpos( $key, 'data-' ) ) {
4674 + } elseif ( str_starts_with( $key, 'data-' ) ) {
4570 4675 // Allow all data attributes.
4571 4676 $safe = true;
4572 - } elseif ( 0 === strpos( $key, 'aria-' ) ) {
4677 + } elseif ( str_starts_with( $key, 'aria-' ) ) {
4573 4678 // Allow all aria attributes.
4574 4679 $safe = true;
4575 4680 } else {
4576 4681 $safe_keys = array(
@@ -4704,8 +4809,9 @@
4704 4809 if ( is_null( $hook_suffix ) ) {
4705 4810 // $hook_suffix gets used in substr so make sure it's not null. PHP 8.1 deprecates null in substr.
4706 4811 $hook_suffix = ''; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
4707 4812 }
4813 +
4708 4814 set_current_screen();
4709 4815 }
4710 4816
4711 4817 /**
@@ -4712,9 +4818,9 @@
4712 4818 * Shows pill text.
4713 4819 *
4714 4820 * @since 5.2.02
4715 4821 *
4716 - * @param string $text Text in the pill. Default is NEW.
4822 + * @param string|null $text Text in the pill. Default is NEW.
4717 4823 */
4718 4824 public static function show_pill_text( $text = null ) {
4719 4825 if ( null === $text ) {
4720 4826 $text = __( 'NEW', 'formidable' );
@@ -4825,9 +4931,9 @@
4825 4931 *
4826 4932 * @return bool
4827 4933 */
4828 4934 public static function validate_url_is_in_s3_bucket( $url, $expected_extension ) {
4829 - $file_is_in_expected_s3_bucket = 0 === strpos( $url, 'https://s3.amazonaws.com/fp.strategy11.com' );
4935 + $file_is_in_expected_s3_bucket = str_starts_with( $url, 'https://s3.amazonaws.com/fp.strategy11.com' );
4830 4936
4831 4937 if ( ! $file_is_in_expected_s3_bucket ) {
4832 4938 return false;
4833 4939 }
@@ -4840,15 +4946,10 @@
4840 4946 }
4841 4947
4842 4948 $path = $parsed['path'];
4843 4949 $ext = pathinfo( $path, PATHINFO_EXTENSION );
4844 -
4845 - if ( $expected_extension !== $ext ) {
4846 - // The URL isn't to an XML file.
4847 - return false;
4848 - }
4849 -
4850 - return true;
4950 + // The URL isn't to an XML file.
4951 + return $expected_extension === $ext;
4851 4952 }
4852 4953
4853 4954 /**
4854 4955 * Display a dismissable warning message and save its dismissal state.
@@ -4909,9 +5010,9 @@
4909 5010 self::permission_check( 'frm_change_settings' );
4910 5011 check_ajax_referer( 'frm_ajax', 'nonce' );
4911 5012
4912 5013 if ( $option ) {
4913 - update_option( $option, true, 'no' );
5014 + update_option( $option, true, false );
4914 5015 }
4915 5016
4916 5017 wp_send_json_success();
4917 5018 }
@@ -4925,9 +5026,8 @@
4925 5026 * @return string
4926 5027 */
4927 5028 public static function copy_for_lite_license() {
4928 5029 $message = __( 'You\'re using Formidable Forms Lite - no license needed. Enjoy!', 'formidable' ) . ' 🙂';
4929 -
4930 5030 return apply_filters( 'frm_license_type_text', $message );
4931 5031 }
4932 5032
4933 5033 /**
@@ -4959,13 +5059,15 @@
4959 5059 $atts['class'] .= ' frm_help';
4960 5060 } else {
4961 5061 $atts['class'] = 'frm_help';
4962 5062 }
5063 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
4963 5064 ?>
4964 5065 <span <?php self::array_to_html_params( $atts, true ); ?>>
4965 5066 <?php self::icon_by_class( 'frmfont frm_tooltip_icon' ); ?>
4966 5067 </span>
4967 5068 <?php
5069 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
4968 5070 }
4969 5071
4970 5072 /**
4971 5073 * Prints errors for settings in onboarding wizard or template settings.
@@ -4986,8 +5088,10 @@
4986 5088 )
4987 5089 );
4988 5090
4989 5091 $args['class'] .= ' frm-validation-error frm-mt-xs frm_hidden';
5092 +
5093 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
4990 5094 ?>
4991 5095 <span id="<?php echo esc_attr( $args['id'] ); ?>" class="<?php echo esc_attr( $args['class'] ); ?>">
4992 5096 <?php
4993 5097 if ( is_array( $args['errors'] ) ) {
@@ -5001,8 +5105,9 @@
5001 5105 }
5002 5106 ?>
5003 5107 </span>
5004 5108 <?php
5109 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
5005 5110 }
5006 5111
5007 5112 /**
5008 5113 * Check if GDPR is enabled.
@@ -5032,13 +5137,18 @@
5032 5137 * Check if a string is valid UTF-8.
5033 5138 *
5034 5139 * @since 6.24
5035 5140 *
5036 - * @param string $string The string to check.
5141 + * @param string|null $string The string to check.
5037 5142 *
5038 5143 * @return bool
5039 5144 */
5040 5145 public static function is_valid_utf8( $string ) {
5146 + if ( is_null( $string ) ) {
5147 + // Return true so we do not attempt to change encoding on a null value.
5148 + return true;
5149 + }
5150 +
5041 5151 // wp_is_valid_utf8 is added in WP 6.9.
5042 5152 if ( function_exists( 'wp_is_valid_utf8' ) ) {
5043 5153 return wp_is_valid_utf8( $string );
5044 5154 }
@@ -5043,12 +5153,9 @@
5043 5153 return wp_is_valid_utf8( $string );
5044 5154 }
5045 5155
5046 5156 // As of WP 6.9, seems_utf8 is deprecated.
5047 - if ( function_exists( 'seems_utf8' ) ) {
5048 - return seems_utf8( $string );
5049 - }
5050 - return false;
5157 + return function_exists( 'seems_utf8' ) ? seems_utf8( $string ) : false;
5051 5158 }
5052 5159
5053 5160 /**
5054 5161 * Get a documentation URL with UTM parameters and affiliate tracking.