| @@ -683,16 +683,16 @@ | ||
| 683 | 683 | // Sanitizing is done later. |
| 684 | 684 | //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing |
| 685 | 685 | $posted = wp_unslash( $_POST['frm_style_setting'] ); |
| 686 | 686 | |
| 687 | - if ( ! is_array( $posted ) ) { | |
| 687 | + if ( is_array( $posted ) ) { | |
| 688 | + $settings = $frm_style->sanitize_post_content( $posted['post_content'] ); | |
| 689 | + $style_name = FrmAppHelper::get_post_param( 'style_name', '', 'sanitize_title' ); | |
| 690 | + } else { | |
| 688 | 691 | $posted = json_decode( $posted, true ); |
| 689 | 692 | FrmAppHelper::format_form_data( $posted ); |
| 690 | 693 | $settings = $frm_style->sanitize_post_content( $posted['frm_style_setting']['post_content'] ); |
| 691 | 694 | $style_name = sanitize_title( $posted['style_name'] ); |
| 692 | - } else { | |
| 693 | - $settings = $frm_style->sanitize_post_content( $posted['post_content'] ); | |
| 694 | - $style_name = FrmAppHelper::get_post_param( 'style_name', '', 'sanitize_title' ); | |
| 695 | 695 | } |
| 696 | 696 | } else { |
| 697 | 697 | $settings = $frm_style->sanitize_post_content( wp_unslash( $_GET ) ); |
| 698 | 698 | $style_name = FrmAppHelper::get_param( 'style_name', '', 'get', 'sanitize_title' ); |
| @@ -867,11 +867,8 @@ | ||
| 867 | 867 | $color = trim( $color ); |
| 868 | 868 | |
| 869 | 869 | if ( ! $color ) { |
| 870 | 870 | $color = $default; |
| 871 | - } elseif ( str_contains( $color, 'rgb(' ) ) { | |
| 872 | - $color = str_replace( 'rgb(', 'rgba(', $color ); | |
| 873 | - $color = str_replace( ')', ',1)', $color ); | |
| 874 | 871 | } elseif ( ! str_contains( $color, '#' ) && self::is_hex( $color ) ) { |
| 875 | 872 | $color = '#' . $color; |
| 876 | 873 | } |
| 877 | 874 | } |
| @@ -887,8 +884,9 @@ | ||
| 887 | 884 | * @return bool |
| 888 | 885 | */ |
| 889 | 886 | private static function is_hex( $color ) { |
| 890 | 887 | $non_hex_substrings = array( |
| 888 | + 'rgb(', | |
| 891 | 889 | 'rgba(', |
| 892 | 890 | 'hsl(', |
| 893 | 891 | 'hsla(', |
| 894 | 892 | 'hwb(', |
| @@ -928,8 +926,24 @@ | ||
| 928 | 926 | return $change_margin; |
| 929 | 927 | } |
| 930 | 928 | |
| 931 | 929 | /** |
| 930 | + * Get the raw alignment value stored in the active style for a radio or checkbox field. | |
| 931 | + * | |
| 932 | + * @since 6.32 | |
| 933 | + * | |
| 934 | + * @param array|int $field The 'field' array. | |
| 935 | + * | |
| 936 | + * @return string | |
| 937 | + */ | |
| 938 | + public static function get_align_from_active_style( $field ) { | |
| 939 | + $field_type = FrmField::is_checkbox( $field ) ? 'checkbox' : 'radio'; | |
| 940 | + $key = FrmStylesController::get_align_key_for_style_settings( $field_type ); | |
| 941 | + | |
| 942 | + return FrmStylesController::get_active_style( $field )->post_content[ $key ] ?? ''; | |
| 943 | + } | |
| 944 | + | |
| 945 | + /** | |
| 932 | 946 | * @since 2.3 |
| 933 | 947 | * |
| 934 | 948 | * @return bool |
| 935 | 949 | */ |
| @@ -1160,6 +1174,92 @@ | ||
| 1160 | 1174 | |
| 1161 | 1175 | $parts = explode( ' ', $value ); |
| 1162 | 1176 | |
| 1163 | 1177 | return count( $parts ) < 3 ? $parts[0] : $parts[2]; |
| 1178 | + } | |
| 1179 | + | |
| 1180 | + /** | |
| 1181 | + * Scope CSS to .frm_forms on admin pages to prevent style conflicts. | |
| 1182 | + * On front-end pages, the CSS is returned unchanged. | |
| 1183 | + * | |
| 1184 | + * @since 6.30 | |
| 1185 | + * | |
| 1186 | + * @param string $css The CSS to scope. | |
| 1187 | + * | |
| 1188 | + * @return string | |
| 1189 | + */ | |
| 1190 | + public static function maybe_scope_css_for_admin( $css ) { | |
| 1191 | + if ( ! self::should_scope_custom_css() ) { | |
| 1192 | + return $css; | |
| 1193 | + } | |
| 1194 | + | |
| 1195 | + /** | |
| 1196 | + * Filter the CSS selector used for @scope when scoping custom CSS on admin pages. | |
| 1197 | + * | |
| 1198 | + * @since 6.30 | |
| 1199 | + * | |
| 1200 | + * @param string $selector The CSS selector to scope to. Default '.frm_forms'. | |
| 1201 | + */ | |
| 1202 | + $selector = apply_filters( 'frm_scope_custom_css_selector', '.frm_forms' ); | |
| 1203 | + | |
| 1204 | + return '@scope (' . $selector . ') {' . $css . '}'; | |
| 1205 | + } | |
| 1206 | + | |
| 1207 | + /** | |
| 1208 | + * Scope only the custom CSS portion of the full cached stylesheet for admin pages. | |
| 1209 | + * Extracts the global custom CSS from the cached CSS, outputs the theme CSS unchanged, | |
| 1210 | + * and returns only the custom CSS portion scoped. | |
| 1211 | + * | |
| 1212 | + * @since 6.30 | |
| 1213 | + * | |
| 1214 | + * @param string $css The full cached CSS containing both theme and custom CSS. | |
| 1215 | + * | |
| 1216 | + * @return string The theme CSS with only the custom CSS portion scoped. | |
| 1217 | + */ | |
| 1218 | + public static function maybe_scope_custom_css_in_cached_output( $css ) { | |
| 1219 | + if ( ! self::should_scope_custom_css() ) { | |
| 1220 | + return $css; | |
| 1221 | + } | |
| 1222 | + | |
| 1223 | + $custom_css = strip_tags( FrmStylesController::get_custom_css() ); | |
| 1224 | + | |
| 1225 | + if ( ! $custom_css ) { | |
| 1226 | + return $css; | |
| 1227 | + } | |
| 1228 | + | |
| 1229 | + // The cached CSS is minified. Minify the custom CSS the same way to find it. | |
| 1230 | + $minified_custom_css = self::minify_css( $custom_css ); | |
| 1231 | + $custom_css_pos = strrpos( $css, $minified_custom_css ); | |
| 1232 | + | |
| 1233 | + if ( false !== $custom_css_pos ) { | |
| 1234 | + $css = substr( $css, 0, $custom_css_pos ); | |
| 1235 | + } | |
| 1236 | + | |
| 1237 | + return $css . self::maybe_scope_css_for_admin( $custom_css ); | |
| 1238 | + } | |
| 1239 | + | |
| 1240 | + /** | |
| 1241 | + * Minify CSS by stripping comments and whitespace. | |
| 1242 | + * Matches the minification used when saving the cached CSS file. | |
| 1243 | + * | |
| 1244 | + * @since 6.30 | |
| 1245 | + * | |
| 1246 | + * @param string $css The CSS to minify. | |
| 1247 | + * | |
| 1248 | + * @return string | |
| 1249 | + */ | |
| 1250 | + private static function minify_css( $css ) { | |
| 1251 | + return preg_replace( '/\/\*(.|\s)*?\*\//', '', str_replace( array( "\r\n", "\r", "\n", "\t", ' ' ), '', $css ) ); | |
| 1252 | + } | |
| 1253 | + | |
| 1254 | + /** | |
| 1255 | + * Check if custom CSS should be scoped for admin context. | |
| 1256 | + * | |
| 1257 | + * @since 6.30 | |
| 1258 | + * | |
| 1259 | + * @return bool | |
| 1260 | + */ | |
| 1261 | + private static function should_scope_custom_css() { | |
| 1262 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only, used to scope CSS output for admin context. | |
| 1263 | + return isset( $_GET['frm_scope_custom_css'] ); | |
| 1164 | 1264 | } |
| 1165 | 1265 | } |