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/FrmStylesHelper.php +274 -54 6.25.1 → trunk View file →
@@ -4,10 +4,14 @@
4 4 }
5 5
6 6 class FrmStylesHelper {
7 7
8 + /**
9 + * @return array
10 + */
8 11 public static function get_upload_base() {
9 12 $uploads = wp_upload_dir();
13 +
10 14 if ( is_ssl() && ! preg_match( '/^https:\/\/.*\..*$/', $uploads['baseurl'] ) ) {
11 15 $uploads['baseurl'] = str_replace( 'http://', 'https://', $uploads['baseurl'] );
12 16 }
13 17
@@ -17,17 +21,23 @@
17 21 /**
18 22 * Called from the admin header.
19 23 *
20 24 * @since 4.0
25 + *
26 + * @return void
21 27 */
22 28 public static function save_button() {
29 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
23 30 ?>
24 31 <input type="submit" name="submit" class="button button-primary frm-button-primary" value="<?php esc_attr_e( 'Update', 'formidable' ); ?>" />
25 32 <?php
33 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
26 34 }
27 35
28 36 /**
29 37 * @since 2.05
38 + *
39 + * @return array
30 40 */
31 41 public static function get_css_label_positions() {
32 42 return array(
33 43 'none' => __( 'top', 'formidable' ),
@@ -66,8 +76,11 @@
66 76 */
67 77 return apply_filters( 'frm_single_label_positions', $label_positions, $field );
68 78 }
69 79
80 + /**
81 + * @return array
82 + */
70 83 public static function minus_icons() {
71 84 return array(
72 85 0 => array(
73 86 '-' => '62e',
@@ -91,8 +104,11 @@
91 104 ),
92 105 );
93 106 }
94 107
108 + /**
109 + * @return array
110 + */
95 111 public static function arrow_icons() {
96 112 $minus_icons = self::minus_icons();
97 113
98 114 return array(
@@ -133,8 +149,13 @@
133 149 }
134 150
135 151 /**
136 152 * @since 2.0
153 + *
154 + * @param int|string $key Icon key.
155 + * @param string $icon Icon state, `+` or `-`.
156 + * @param string $type Icon type, such as `arrow`.
157 + *
137 158 * @return string The class for this icon.
138 159 */
139 160 public static function icon_key_to_class( $key, $icon = '+', $type = 'arrow' ) {
140 161 if ( 'arrow' === $type && is_numeric( $key ) ) {
@@ -156,11 +177,10 @@
156 177
157 178 if ( $key ) {
158 179 $class .= $key;
159 180 }
160 - $class .= '_icon';
161 181
162 - return $class;
182 + return $class . '_icon';
163 183 }
164 184
165 185 /**
166 186 * @param WP_Post $style
@@ -165,8 +185,9 @@
165 185 /**
166 186 * @param WP_Post $style
167 187 * @param FrmStyle $frm_style
168 188 * @param string $type
189 + *
169 190 * @return void
170 191 */
171 192 public static function bs_icon_select( $style, $frm_style, $type = 'arrow' ) {
172 193 $function_name = $type . '_icons';
@@ -173,8 +194,9 @@
173 194 $icons = self::$function_name();
174 195 unset( $function_name );
175 196
176 197 $name = 'arrow' === $type ? 'collapse_icon' : 'repeat_icon';
198 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
177 199 ?>
178 200 <div class="btn-group" id="frm_<?php echo esc_attr( $name ); ?>_select">
179 201 <button class="multiselect dropdown-toggle btn btn-default" data-toggle="dropdown" type="button">
180 202 <?php FrmAppHelper::icon_by_class( 'frmfont ' . self::icon_key_to_class( $style->post_content[ $name ], '+', $type ) ); ?>
@@ -182,12 +204,12 @@
182 204 <b class="caret"></b>
183 205 </button>
184 206 <ul class="multiselect-container frm-dropdown-menu">
185 207 <?php foreach ( $icons as $key => $icon ) { ?>
186 - <li <?php echo $style->post_content['collapse_icon'] == $key ? 'class="active"' : ''; ?>>
208 + <li <?php echo $style->post_content['collapse_icon'] == $key ? 'class="active"' : ''; // phpcs:ignore Universal.Operators.StrictComparisons ?>>
187 209 <a href="javascript:void(0);">
188 210 <label>
189 - <input type="radio" value="<?php echo esc_attr( $key ); ?>" name="<?php echo esc_attr( $frm_style->get_field_name( $name ) ); ?>" <?php checked( $style->post_content[ $name ], $key ); ?> />
211 + <input type="radio" value="<?php echo esc_attr( $key ); ?>" name="<?php echo esc_attr( $frm_style->get_field_name( $name ) ); ?>" <?php checked( $style->post_content[ $name ], $key ); ?> /><?php // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
190 212 <span>
191 213 <?php
192 214 FrmAppHelper::icon_by_class( 'frmfont ' . self::icon_key_to_class( $key, '+', $type ) );
193 215 FrmAppHelper::icon_by_class( 'frmfont ' . self::icon_key_to_class( $key, '-', $type ) );
@@ -199,8 +221,9 @@
199 221 <?php } ?>
200 222 </ul>
201 223 </div>
202 224 <?php
225 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
203 226 }
204 227
205 228 /**
206 229 * Convert a color setting to a RGB CSV (without the rgb()/rgba() wrapper).
@@ -207,16 +230,13 @@
207 230 *
208 231 * @since 2.0
209 232 *
210 233 * @param string $color Color setting value. This could be hex or rgb.
234 + *
211 235 * @return string RGB value without the rgb() wrapper.
212 236 */
213 237 public static function hex2rgb( $color ) {
214 - if ( 0 === strpos( $color, 'rgb' ) ) {
215 - $rgb = self::get_rgb_array_from_rgb( $color );
216 - } else {
217 - $rgb = self::get_rgb_array_from_hex( $color );
218 - }
238 + $rgb = str_starts_with( $color, 'rgb' ) ? self::get_rgb_array_from_rgb( $color ) : self::get_rgb_array_from_hex( $color );
219 239 return implode( ',', $rgb );
220 240 }
221 241
222 242 /**
@@ -224,17 +244,20 @@
224 244 *
225 245 * @since 6.8.3
226 246 *
227 247 * @param string $rgb RGB value including the rgb() or rgba() wrapper.
248 + *
228 249 * @return array<string> including three numeric values for R, G, and B.
229 250 */
230 251 private static function get_rgb_array_from_rgb( $rgb ) {
231 252 $rgb = str_replace( array( 'rgb(', 'rgba(', ')' ), '', $rgb );
232 253 $rgb = explode( ',', $rgb );
254 +
233 255 if ( 4 === count( $rgb ) ) {
234 256 // Drop the alpha. The function is expected to only return r,g,b with no alpha.
235 257 array_pop( $rgb );
236 258 }
259 +
237 260 return $rgb;
238 261 }
239 262
240 263 /**
@@ -242,8 +265,9 @@
242 265 *
243 266 * @since 6.8.3
244 267 *
245 268 * @param string $hex A hex color string.
269 + *
246 270 * @return array<string> Including three numeric values for R, G, and B.
247 271 */
248 272 private static function get_rgb_array_from_hex( $hex ) {
249 273 $hex = str_replace( '#', '', $hex );
@@ -252,12 +276,16 @@
252 276 }
253 277
254 278 /**
255 279 * @since 4.0
280 + *
281 + * @param string $hex Hex color string.
282 + * @param float|int|string $a Alpha channel value.
283 + *
284 + * @return string
256 285 */
257 286 public static function hex2rgba( $hex, $a ) {
258 287 $rgb = self::hex2rgb( $hex );
259 -
260 288 return 'rgba(' . $rgb . ',' . $a . ')';
261 289 }
262 290
263 291 /**
@@ -263,12 +291,13 @@
263 291 /**
264 292 * @since 6.0
265 293 *
266 294 * @param string $rgba Color setting value. This could be hex or rgb.
295 + *
267 296 * @return string Hex color value.
268 297 */
269 298 private static function rgb_to_hex( $rgba ) {
270 - if ( strpos( $rgba, '#' ) === 0 ) {
299 + if ( str_starts_with( $rgba, '#' ) ) {
271 300 // Color is already hex.
272 301 return $rgba;
273 302 }
274 303 preg_match( '/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i', $rgba, $by_color );
@@ -278,8 +307,9 @@
278 307 /**
279 308 * @since 6.8
280 309 *
281 310 * @param string $hsl
311 + *
282 312 * @return string|null Null if it fails to parse the HSL string.
283 313 */
284 314 private static function hsl_to_hex( $hsl ) {
285 315 // Convert hsla to hsl.
@@ -331,22 +361,23 @@
331 361 $g = round( ( $g + $m ) * 255 );
332 362 $b = round( ( $b + $m ) * 255 );
333 363
334 364 // Convert RGB to hex
335 - $hex = sprintf( '%02x%02x%02x', $r, $g, $b );
336 -
337 - return $hex;
365 + return sprintf( '%02x%02x%02x', $r, $g, $b );
338 366 }
339 367
340 368 /**
341 369 * @since 2.3
370 + *
342 371 * @param string $hex string The original color in hex format #ffffff.
343 372 * @param int $steps integer Should be between -255 and 255. Negative = darker, positive = lighter.
373 + *
374 + * @return string
344 375 */
345 376 public static function adjust_brightness( $hex, $steps ) {
346 377 $steps = max( - 255, min( 255, $steps ) );
347 378
348 - if ( 0 === strpos( $hex, 'rgba(' ) ) {
379 + if ( str_starts_with( $hex, 'rgba(' ) ) {
349 380 $rgba = str_replace( ')', '', str_replace( 'rgba(', '', $hex ) );
350 381 list ( $r, $g, $b, $a ) = array_map( 'trim', explode( ',', $rgba ) );
351 382 $r = max( 0, min( 255, $r + $steps ) );
352 383 $g = max( 0, min( 255, $g + $steps ) );
@@ -378,32 +409,34 @@
378 409 /**
379 410 * @since 6.0
380 411 *
381 412 * @param string $color
413 + *
382 414 * @return int
383 415 */
384 416 public static function get_color_brightness( $color ) {
385 - if ( 0 === strpos( $color, 'rgb' ) ) {
417 + if ( str_starts_with( $color, 'rgb' ) ) {
386 418 $color = self::rgb_to_hex( $color );
387 419 }
388 420
389 - if ( 0 === strpos( $color, 'hsl' ) ) {
421 + if ( str_starts_with( $color, 'hsl' ) ) {
390 422 $hsl_to_hex = self::hsl_to_hex( $color );
423 +
391 424 if ( is_null( $hsl_to_hex ) ) {
392 425 // Fallback if we cannot convert the HSL value.
393 426 return 0;
394 427 }
428 +
395 429 $color = $hsl_to_hex;
396 430 }
397 431
398 432 self::fill_hex( $color );
399 433
400 - $c_r = hexdec( substr( $color, 0, 2 ) );
401 - $c_g = hexdec( substr( $color, 2, 2 ) );
402 - $c_b = hexdec( substr( $color, 4, 2 ) );
403 - $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;
434 + $c_r = hexdec( substr( $color, 0, 2 ) );
435 + $c_g = hexdec( substr( $color, 2, 2 ) );
436 + $c_b = hexdec( substr( $color, 4, 2 ) );
404 437
405 - return $brightness;
438 + return ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;
406 439 }
407 440
408 441 /**
409 442 * Change a 3 character hex color to a 6 character one.
@@ -409,8 +442,10 @@
409 442 * Change a 3 character hex color to a 6 character one.
410 443 *
411 444 * @since 6.0
412 445 *
446 + * @param string $color Color value, passed by reference.
447 + *
413 448 * @return void
414 449 */
415 450 private static function fill_hex( &$color ) {
416 451 if ( 3 === strlen( $color ) ) {
@@ -419,8 +454,12 @@
419 454 }
420 455
421 456 /**
422 457 * @since 4.05.02
458 + *
459 + * @param array $vars CSS variable keys.
460 + *
461 + * @return array
423 462 */
424 463 public static function get_css_vars( $vars = array() ) {
425 464 $vars = apply_filters( 'frm_css_vars', $vars );
426 465 return array_unique( $vars );
@@ -427,32 +466,72 @@
427 466 }
428 467
429 468 /**
430 469 * @since 4.05.02
470 + *
471 + * @param array $settings Style settings.
472 + * @param array $defaults Default style settings.
473 + * @param array $vars CSS variable keys to output.
474 + *
475 + * @return void
431 476 */
432 477 public static function output_vars( $settings, $defaults = array(), $vars = array() ) {
433 - if ( empty( $vars ) ) {
478 + if ( ! $vars ) {
434 479 $vars = self::get_css_vars( array_keys( $settings ) );
435 480 }
436 - $remove = array( 'remove_box_shadow', 'remove_box_shadow_active', 'theme_css', 'theme_name', 'theme_selector', 'important_style', 'submit_style', 'collapse_icon', 'center_form', 'custom_css', 'style_class', 'submit_bg_img', 'change_margin', 'repeat_icon', 'use_base_font_size', 'field_shape_type' );
437 - $vars = array_diff( $vars, $remove );
438 481
482 + $vars = array_diff( $vars, self::get_style_keys_to_remove_from_output_vars() );
483 +
439 484 foreach ( $vars as $var ) {
440 485 if ( ! isset( $settings[ $var ] ) || ! self::css_key_is_valid( $var ) ) {
441 486 continue;
442 487 }
488 +
443 489 if ( ! isset( $defaults[ $var ] ) ) {
444 490 $defaults[ $var ] = '';
445 491 }
446 492
447 493 $prepared_value = '';
494 +
448 495 if ( self::should_add_css_var( $settings, $defaults, $var, $prepared_value ) ) {
449 - echo '--' . esc_html( self::clean_var_name( str_replace( '_', '-', $var ) ) ) . ':' . $prepared_value . ';'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
496 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
497 + echo '--' . esc_html( self::clean_var_name( str_replace( '_', '-', $var ) ) ) . ':' . $prepared_value . ';';
450 498 }
451 499 }
452 500 }
453 501
454 502 /**
503 + * None of these style settings are used as CSS variables, so we want to exclude them to keep the CSS output clean.
504 + *
505 + * @since 6.26.1
506 + *
507 + * @return array<string>
508 + */
509 + private static function get_style_keys_to_remove_from_output_vars() {
510 + return array(
511 + 'remove_box_shadow',
512 + 'remove_box_shadow_active',
513 + 'theme_css',
514 + 'theme_name',
515 + 'theme_selector',
516 + 'important_style',
517 + 'submit_style',
518 + 'collapse_icon',
519 + 'center_form',
520 + 'custom_css',
521 + 'style_class',
522 + 'submit_bg_img',
523 + 'change_margin',
524 + 'repeat_icon',
525 + 'use_base_font_size',
526 + 'field_shape_type',
527 + 'bg_image_id',
528 + 'single_style_custom_css',
529 + 'enable_style_custom_css',
530 + );
531 + }
532 +
533 + /**
455 534 * Check if a CSS variable setting is not blank, doesn't match the default, and doesn't include invalid substrings.
456 535 *
457 536 * @since 6.24
458 537 *
@@ -459,12 +538,14 @@
459 538 * @param array $settings Array of setting values.
460 539 * @param array $defaults Array of default values.
461 540 * @param string $var The setting key name.
462 541 * @param string $prepared_value The value from calling css_var_prepare_value. This is set by reference so it can be used after this function is called.
542 + *
463 543 * @return bool True if the CSS value should be printed.
464 544 */
465 545 private static function should_add_css_var( $settings, $defaults, $var, &$prepared_value ) {
466 546 $prepared_value = self::css_var_prepare_value( $settings, $var );
547 +
467 548 if ( $prepared_value === '' ) {
468 549 return false;
469 550 }
470 551
@@ -480,14 +561,15 @@
480 561 *
481 562 * @since 6.20
482 563 *
483 564 * @param string $key
565 + *
484 566 * @return bool
485 567 */
486 568 private static function css_key_is_valid( $key ) {
487 569 // Any key that is abnormally large is not valid.
488 570 // Any key that contains a '{' is not valid.
489 - return strlen( $key ) < 100 && false === strpos( $key, '{' );
571 + return strlen( $key ) < 100 && ! str_contains( $key, '{' );
490 572 }
491 573
492 574 /**
493 575 * Confirm a CSS value is valid.
@@ -495,8 +577,9 @@
495 577 *
496 578 * @since 6.20
497 579 *
498 580 * @param string $var
581 + *
499 582 * @return bool
500 583 */
501 584 private static function css_value_is_valid( $var ) {
502 585 if ( is_numeric( $var ) ) {
@@ -514,9 +597,9 @@
514 597 'Array;',
515 598 );
516 599
517 600 foreach ( $invalid_substrings as $substring ) {
518 - if ( strpos( $var, $substring ) !== false ) {
601 + if ( str_contains( $var, $substring ) ) {
519 602 return false;
520 603 }
521 604 }
522 605
@@ -522,13 +605,13 @@
522 605
523 606 return true;
524 607 }
525 608
526 -
527 609 /**
528 610 * Remove anything that isn't used as a CSS variable name.
529 611 *
530 612 * @param string $var_name
613 + *
531 614 * @return string
532 615 */
533 616 private static function clean_var_name( $var_name ) {
534 617 return preg_replace( '/[^a-zA-Z0-9_-]/', '', $var_name );
@@ -587,25 +670,29 @@
587 670 /**
588 671 * @since 2.3
589 672 *
590 673 * @param WP_Post $style
674 + *
591 675 * @return array
592 676 */
593 677 public static function get_settings_for_output( $style ) {
594 678 if ( self::previewing_style() ) {
595 679 $frm_style = new FrmStyle();
680 +
596 681 if ( isset( $_POST['frm_style_setting'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
597 682
598 683 // Sanitizing is done later.
599 - $posted = wp_unslash( $_POST['frm_style_setting'] ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
600 - if ( ! is_array( $posted ) ) {
684 + //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
685 + $posted = wp_unslash( $_POST['frm_style_setting'] );
686 +
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 {
601 691 $posted = json_decode( $posted, true );
602 692 FrmAppHelper::format_form_data( $posted );
603 693 $settings = $frm_style->sanitize_post_content( $posted['frm_style_setting']['post_content'] );
604 694 $style_name = sanitize_title( $posted['style_name'] );
605 - } else {
606 - $settings = $frm_style->sanitize_post_content( $posted['post_content'] );
607 - $style_name = FrmAppHelper::get_post_param( 'style_name', '', 'sanitize_title' );
608 695 }
609 696 } else {
610 697 $settings = $frm_style->sanitize_post_content( wp_unslash( $_GET ) );
611 698 $style_name = FrmAppHelper::get_param( 'style_name', '', 'get', 'sanitize_title' );
@@ -615,8 +702,9 @@
615 702
616 703 FrmAppHelper::sanitize_value( 'sanitize_text_field', $settings );
617 704
618 705 $settings['style_class'] = '';
706 +
619 707 if ( ! empty( $style_name ) ) {
620 708 $settings['style_class'] = $style_name . '.';
621 709 }
622 710 } else {
@@ -628,8 +716,9 @@
628 716 $settings['font'] = stripslashes( $settings['font'] );
629 717 $settings['change_margin'] = self::description_margin_for_screensize( $settings['width'] );
630 718
631 719 $checkbox_opts = array( 'important_style', 'auto_width', 'submit_style', 'collapse_icon', 'center_form' );
720 +
632 721 foreach ( $checkbox_opts as $opt ) {
633 722 if ( ! isset( $settings[ $opt ] ) ) {
634 723 $settings[ $opt ] = 0;
635 724 }
@@ -654,8 +743,9 @@
654 743 *
655 744 * @since 6.14
656 745 *
657 746 * @param array $settings An array of css style.
747 + * @param array $defaults Default style settings.
658 748 *
659 749 * @return array
660 750 */
661 751 public static function update_base_font_size( $settings, $defaults ) {
@@ -661,8 +751,9 @@
661 751 public static function update_base_font_size( $settings, $defaults ) {
662 752 if ( empty( $settings['base_font_size'] ) || empty( $settings['use_base_font_size'] ) || 'false' === $settings['use_base_font_size'] ) {
663 753 return $settings;
664 754 }
755 +
665 756 $base_font_size = (int) $settings['base_font_size'];
666 757 $font_size = $defaults['font_size'];
667 758 $font_sizes_to_update = array(
668 759 'font_size',
@@ -694,8 +785,12 @@
694 785 * Get style font size scale value.
695 786 *
696 787 * @since 6.14
697 788 *
789 + * @param string $key Setting key.
790 + * @param int|string $value Base font size value.
791 + * @param array $defaults Default style settings.
792 + *
698 793 * @return float
699 794 */
700 795 private static function get_base_font_size_scale( $key, $value, $defaults ) {
701 796 if ( empty( $defaults[ $key ] ) || ! is_numeric( (int) $defaults[ $key ] ) || ! is_numeric( (int) $value ) || 0 === (int) $value ) {
@@ -706,15 +801,22 @@
706 801 }
707 802
708 803 /**
709 804 * @since 2.3
805 + *
806 + * @param array $settings Style settings, passed by reference.
807 + * @param bool $allow_transparent Whether transparent colors are allowed.
808 + *
809 + * @return void
710 810 */
711 811 public static function prepare_color_output( &$settings, $allow_transparent = true ) {
712 812 $colors = self::allow_color_override();
813 +
713 814 foreach ( $colors as $css => $opts ) {
714 815 if ( $css === 'transparent' && ! $allow_transparent ) {
715 816 $css = '';
716 817 }
818 +
717 819 foreach ( $opts as $opt ) {
718 820 self::get_color_output( $css, $settings[ $opt ] );
719 821 }
720 822 }
@@ -754,17 +856,20 @@
754 856 }
755 857
756 858 /**
757 859 * @since 2.3
860 + *
861 + * @param string $default Default color value.
862 + * @param string $color Color value, passed by reference.
863 + *
864 + * @return void
758 865 */
759 866 private static function get_color_output( $default, &$color ) {
760 867 $color = trim( $color );
761 - if ( empty( $color ) ) {
868 +
869 + if ( ! $color ) {
762 870 $color = $default;
763 - } elseif ( false !== strpos( $color, 'rgb(' ) ) {
764 - $color = str_replace( 'rgb(', 'rgba(', $color );
765 - $color = str_replace( ')', ',1)', $color );
766 - } elseif ( strpos( $color, '#' ) === false && self::is_hex( $color ) ) {
871 + } elseif ( ! str_contains( $color, '#' ) && self::is_hex( $color ) ) {
767 872 $color = '#' . $color;
768 873 }
769 874 }
770 875
@@ -774,12 +879,14 @@
774 879 *
775 880 * @since 6.8
776 881 *
777 882 * @param string $color
883 + *
778 884 * @return bool
779 885 */
780 886 private static function is_hex( $color ) {
781 887 $non_hex_substrings = array(
888 + 'rgb(',
782 889 'rgba(',
783 890 'hsl(',
784 891 'hsla(',
785 892 'hwb(',
@@ -785,9 +892,9 @@
785 892 'hwb(',
786 893 );
787 894
788 895 foreach ( $non_hex_substrings as $substring ) {
789 - if ( false !== strpos( $color, $substring ) ) {
896 + if ( str_contains( $color, $substring ) ) {
790 897 return false;
791 898 }
792 899 }
793 900
@@ -798,12 +905,17 @@
798 905 * If left/right label is over a certain size,
799 906 * adjust the field description margin at a different screen size
800 907 *
801 908 * @since 2.3
909 + *
910 + * @param string $width Label width value.
911 + *
912 + * @return false|string
802 913 */
803 914 private static function description_margin_for_screensize( $width ) {
804 915 $temp_label_width = str_replace( 'px', '', $width );
805 916 $change_margin = false;
917 +
806 918 if ( $temp_label_width >= 230 ) {
807 919 $change_margin = '800px';
808 920 } elseif ( $width >= 215 ) {
809 921 $change_margin = '700px';
@@ -814,14 +926,31 @@
814 926 return $change_margin;
815 927 }
816 928
817 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 + /**
818 946 * @since 2.3
819 947 *
820 948 * @return bool
821 949 */
822 950 public static function previewing_style() {
823 - $ajax_change = isset( $_POST['action'] ) && $_POST['action'] === 'frm_change_styling' && isset( $_POST['frm_style_setting'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
951 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
952 + $ajax_change = isset( $_POST['action'] ) && $_POST['action'] === 'frm_change_styling' && isset( $_POST['frm_style_setting'] );
824 953
825 954 return $ajax_change || isset( $_GET['flat'] );
826 955 }
827 956
@@ -830,8 +959,9 @@
830 959 *
831 960 * @since 6.0
832 961 *
833 962 * @param int|string $form_id
963 + *
834 964 * @return string
835 965 */
836 966 public static function get_list_url( $form_id ) {
837 967 return admin_url( 'admin.php?page=formidable-styles&form=' . absint( $form_id ) );
@@ -843,8 +973,9 @@
843 973 * @since 6.14
844 974 *
845 975 * @param stdClass|WP_Post $style
846 976 * @param int $form_id
977 + *
847 978 * @return array
848 979 */
849 980 public static function get_style_options_back_button_args( $style, $form_id ) {
850 981 if ( self::is_advanced_settings() ) {
@@ -891,8 +1022,9 @@
891 1022 * @since 6.0
892 1023 *
893 1024 * @param int|string $style_id
894 1025 * @param bool $is_default
1026 + *
895 1027 * @return int
896 1028 */
897 1029 public static function get_form_count_for_style( $style_id, $is_default ) {
898 1030 $serialized = serialize( array( 'custom_style' => (string) $style_id ) );
@@ -911,11 +1043,10 @@
911 1043 return $number_of_forms;
912 1044 }
913 1045
914 1046 $conversational_style_id = FrmDb::get_var( 'posts', array( 'post_name' => 'lines-no-boxes' ), 'ID' );
915 - $number_of_forms += self::get_default_style_count( $style_id, $conversational_style_id );
916 1047
917 - return $number_of_forms;
1048 + return $number_of_forms + self::get_default_style_count( $style_id, $conversational_style_id );
918 1049 }
919 1050
920 1051 /**
921 1052 * Get the number of forms that use the default style.
@@ -923,8 +1054,9 @@
923 1054 * @since 6.0
924 1055 *
925 1056 * @param int|string $style_id
926 1057 * @param mixed $conversational_style_id
1058 + *
927 1059 * @return int
928 1060 */
929 1061 private static function get_default_style_count( $style_id, $conversational_style_id ) {
930 1062 $substrings = array_map(
@@ -976,14 +1108,13 @@
976 1108 *
977 1109 * @return string The style editor wrapper classname.
978 1110 */
979 1111 public static function style_editor_get_wrapper_classname( $section_type ) {
980 - $is_quick_settings = ( 'quick-settings' === $section_type );
1112 + $is_quick_settings = 'quick-settings' === $section_type;
981 1113 $classname = 'frm-style-editor-form';
982 1114 $classname .= ( ! self::is_advanced_settings() xor $is_quick_settings ) ? ' frm_hidden' : '';
983 - $classname .= FrmAppHelper::pro_is_installed() ? ' frm-pro' : '';
984 1115
985 - return $classname;
1116 + return $classname . ( FrmAppHelper::pro_is_installed() ? ' frm-pro' : '' );
986 1117 }
987 1118
988 1119 /**
989 1120 * Retrieve the background image URL of the submit button.
@@ -991,16 +1122,21 @@
991 1122 *
992 1123 * @since 6.14
993 1124 *
994 1125 * @param array $settings
1126 + *
995 1127 * @return false|string Return image url or false.
996 1128 */
997 1129 public static function get_submit_image_bg_url( $settings ) {
998 1130 $background_image = $settings['submit_bg_img'];
999 - if ( empty( $background_image ) ) {
1131 +
1132 + if ( ! $background_image ) {
1000 1133 return false;
1001 1134 }
1002 - // Handle the case where the submit_bg_img is a full URL string. If the settings were saved with the older styler version prior to 6.14, the submit_bg_img will be a full URL string.
1135 +
1136 + // Handle the case where the submit_bg_img is a full URL string. If the
1137 + // Settings were saved with the older styler version prior to 6.14, the
1138 + // submit_bg_img will be a full URL string.
1003 1139 if ( ! is_numeric( $background_image ) ) {
1004 1140 return $background_image;
1005 1141 }
1006 1142
@@ -1018,11 +1154,9 @@
1018 1154 if ( ! FrmAppHelper::pro_is_installed() ) {
1019 1155 return false;
1020 1156 }
1021 1157
1022 - return is_callable( 'FrmProAppHelper::use_chosen_js' )
1023 - ? FrmProAppHelper::use_chosen_js()
1024 - : true;
1158 + return is_callable( 'FrmProAppHelper::use_chosen_js' ) ? FrmProAppHelper::use_chosen_js() : true;
1025 1159 }
1026 1160
1027 1161 /**
1028 1162 * Returns the bottom part from a margin/padding value.
@@ -1029,8 +1163,9 @@
1029 1163 *
1030 1164 * @since 6.17
1031 1165 *
1032 1166 * @param string $value The margin/padding value.
1167 + *
1033 1168 * @return string
1034 1169 */
1035 1170 public static function get_bottom_value( $value ) {
1036 1171 if ( ! $value ) {
@@ -1035,11 +1170,96 @@
1035 1170 public static function get_bottom_value( $value ) {
1036 1171 if ( ! $value ) {
1037 1172 return $value;
1038 1173 }
1174 +
1039 1175 $parts = explode( ' ', $value );
1040 - if ( count( $parts ) < 3 ) {
1041 - return $parts[0];
1176 +
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;
1042 1193 }
1043 - return $parts[2];
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'] );
1044 1264 }
1045 1265 }