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 +59 -17 6.30 → 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 = 105;
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.30';
32 + public static $plug_version = '6.35';
33 33
34 34 /**
35 35 * @var bool
36 36 */
@@ -937,8 +937,9 @@
937 937 } else {
938 938 self::sanitize_value( self::class . '::strip_most_html', $value );
939 939 }
940 940 self::decode_specialchars( $value );
941 + self::sanitize_value( 'FrmHtmlSanitizer::sanitize_url_attributes', $value );
941 942 }
942 943
943 944 /**
944 945 * Allow only a small set of very basic HTML for unprivileged users.
@@ -1368,10 +1369,9 @@
1368 1369 if ( isset( $atts['echo'] ) ) {
1369 1370 unset( $atts['echo'] );
1370 1371 }
1371 1372
1372 - $html_atts = self::array_to_html_params( $atts );
1373 - $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
1373 + $icon = trim( str_replace( array( 'frm_icon_font', 'frmfont ' ), '', $class ) );
1374 1374
1375 1375 // Replace icons that have been removed or renamed.
1376 1376 $deprecated = array(
1377 1377 'frm_clone_solid_icon' => 'frm_clone_icon',
@@ -1383,11 +1383,11 @@
1383 1383 $icon = $deprecated[ $icon ];
1384 1384 $class = str_replace( $icon, $deprecated[ $icon ], $class );
1385 1385 }
1386 1386
1387 - if ( $icon === $class ) {
1388 - $icon = '<i class="' . esc_attr( $class ) . '"' . $html_atts . '></i>';
1389 - } else {
1387 + $is_font_icon = $icon === $class;
1388 +
1389 + if ( ! $is_font_icon ) {
1390 1390 $class = str_contains( $icon, ' ' ) ? ' ' . $icon : '';
1391 1391
1392 1392 if ( str_contains( $icon, ' ' ) ) {
1393 1393 $icon = explode( ' ', $icon );
@@ -1392,18 +1392,46 @@
1392 1392 if ( str_contains( $icon, ' ' ) ) {
1393 1393 $icon = explode( ' ', $icon );
1394 1394 $icon = reset( $icon );
1395 1395 }
1396 + }
1396 1397
1397 - $icon = '<svg class="frmsvg' . esc_attr( $class ) . '"' . $html_atts . '><use href="#' . esc_attr( $icon ) . '" /></svg>';
1398 - }
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>';
1399 1406
1400 - if ( $echo ) {
1401 - echo self::kses_icon( $icon ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1407 + if ( ! $echo ) {
1408 + return $markup;
1409 + }
1410 +
1411 + echo self::kses_icon( $markup ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1402 1412 return null;
1403 1413 }
1404 1414
1405 - return $icon;
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 );
1406 1434 }
1407 1435
1408 1436 /**
1409 1437 * Run kses for icons. It needs to add a few filters first in order to preserve some custom style values.
@@ -1535,8 +1563,10 @@
1535 1563 * @param Closure $echo_function
1536 1564 * @param bool $echo
1537 1565 *
1538 1566 * @return string|null
1567 + *
1568 + * @psalm-return ($echo is true ? null : string)
1539 1569 */
1540 1570 public static function clip( $echo_function, $echo = false ) {
1541 1571 if ( ! $echo ) {
1542 1572 ob_start();
@@ -1628,9 +1658,9 @@
1628 1658
1629 1659 printf(
1630 1660 /* translators: %1$s: Start link HTML, %2$s: CTA text ("upgrading to PRO" by default), %3$s: End link HTML */
1631 1661 esc_html__( 'You\'re using Formidable Forms Lite. To unlock more features consider %1$s%2$s%3$s.', 'formidable' ),
1632 - '<a href="' . esc_url( $upgrade_link ) . '">',
1662 + '<a href="' . esc_url( $upgrade_link ) . '" target="_blank" rel="noopener">',
1633 1663 esc_html( $cta_text ),
1634 1664 '</a>'
1635 1665 );
1636 1666 ?>
@@ -3951,8 +3981,10 @@
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 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. */
@@ -4009,9 +4041,10 @@
4009 4041 }
4010 4042
4011 4043 $stripe_connected = FrmStrpLiteConnectHelper::at_least_one_mode_is_setup();
4012 4044 $square_connected = FrmSquareLiteConnectHelper::at_least_one_mode_is_setup();
4013 - $gateway_connected = $stripe_connected || $square_connected;
4045 + $paypal_connected = FrmPayPalLiteConnectHelper::at_least_one_mode_is_setup();
4046 + $gateway_connected = $stripe_connected || $square_connected || $paypal_connected;
4014 4047 $payments_settings_url = FrmStrpLiteAppController::get_payments_settings_url();
4015 4048
4016 4049 if ( ! $gateway_connected ) {
4017 4050 // This modal shows when user clicks on one of the pricing fields and no payment gateways configured.
@@ -4048,10 +4081,14 @@
4048 4081 if ( $square_connected ) {
4049 4082 $gateway_texts['square'] = esc_html__( 'Square', 'formidable' );
4050 4083 }
4051 4084
4085 + if ( $paypal_connected ) {
4086 + $gateway_texts['paypal'] = esc_html__( 'PayPal', 'formidable' );
4087 + }
4088 +
4052 4089 $admin_script_strings['pricingFieldsModal']['msg'] = sprintf(
4053 - // translators: %s: Stripe or Square.
4090 + // translators: %s: Stripe, Square, or PayPal.
4054 4091 esc_html__( 'You already have %s connected, so these have already been unlocked.', 'formidable' ),
4055 4092 esc_html( implode( ' ' . esc_html__( 'and', 'formidable' ) . ' ', $gateway_texts ) )
4056 4093 );
4057 4094 } else {
@@ -4058,9 +4095,9 @@
4058 4095 $admin_script_strings['pricingFieldsModal']['closeText'] = __( 'I\'ll do it later!', 'formidable' );
4059 4096 $admin_script_strings['pricingFieldsModal']['actionText'] = __( 'Setup Payments Now', 'formidable' );
4060 4097 $admin_script_strings['pricingFieldsModal']['actionUrl'] = $payments_settings_url;
4061 4098 // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
4062 - $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, or Square) in your settings.', 'formidable' );
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' );
4063 4100 }//end if
4064 4101
4065 4102 delete_option( 'frm_show_pricing_fields_modal' );
4066 4103 }
@@ -5100,13 +5137,18 @@
5100 5137 * Check if a string is valid UTF-8.
5101 5138 *
5102 5139 * @since 6.24
5103 5140 *
5104 - * @param string $string The string to check.
5141 + * @param string|null $string The string to check.
5105 5142 *
5106 5143 * @return bool
5107 5144 */
5108 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 +
5109 5151 // wp_is_valid_utf8 is added in WP 6.9.
5110 5152 if ( function_exists( 'wp_is_valid_utf8' ) ) {
5111 5153 return wp_is_valid_utf8( $string );
5112 5154 }