PluginProbe ʕ •ᴥ•ʔ
WPForms – Easy Form Builder for WordPress – Contact Forms, Payment Forms, Surveys, & More / 1.9.9.4
WPForms – Easy Form Builder for WordPress – Contact Forms, Payment Forms, Surveys, & More v1.9.9.4
1.10.1.1 1.10.1 1.10.0.5 trunk 1.1.4 1.1.4.2 1.1.5 1.1.5.1 1.1.6 1.1.6.1 1.1.7 1.1.7.1 1.1.7.2 1.1.8 1.1.8.1 1.1.8.2 1.1.8.3 1.1.8.4 1.10.0.1 1.10.0.2 1.10.0.3 1.10.0.4 1.2.0 1.2.0.1 1.2.1 1.2.2 1.2.2.1 1.2.2.2 1.2.3 1.2.3.1 1.2.3.2 1.2.4 1.2.4.1 1.2.5 1.2.5.1 1.2.6 1.2.7 1.2.8 1.2.8.1 1.2.9 1.3.0 1.3.1 1.3.1.1 1.3.1.2 1.3.2 1.3.3 1.3.5 1.3.6 1.3.6.1 1.3.6.2 1.3.7.2 1.3.7.3 1.3.7.4 1.3.8 1.3.9.1 1.4.0.1 1.4.1.1 1.4.2 1.4.2.1 1.4.2.2 1.4.3 1.4.4 1.4.4.1 1.4.5 1.4.5.1 1.4.5.2 1.4.5.3 1.4.6 1.4.7.1 1.4.7.2 1.4.8.1 1.4.9 1.5.0.1 1.5.0.3 1.5.0.4 1.5.1 1.5.1.1 1.5.1.3 1.5.2.1 1.5.2.2 1.5.2.3 1.5.3 1.5.3.1 1.5.4.1 1.5.4.2 1.5.5 1.5.5.1 1.5.6 1.5.6.2 1.5.7 1.5.8.2 1.5.9.1 1.5.9.4 1.5.9.5 1.6.0.1 1.6.0.2 1.6.1 1.6.2.2 1.6.2.3 1.6.3.1 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.7 1.6.7.1 1.6.7.2 1.6.7.3 1.6.8 1.6.8.1 1.6.9 1.7.0 1.7.1.1 1.7.1.2 1.7.2 1.7.2.1 1.7.3 1.7.4 1.7.4.1 1.7.4.2 1.7.5.1 1.7.5.2 1.7.5.3 1.7.5.5 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.7.9.1 1.8.0.1 1.8.0.2 1.8.1.1 1.8.1.2 1.8.1.3 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.3.1 1.8.4 1.8.4.1 1.8.5.2 1.8.5.3 1.8.5.4 1.8.6.2 1.8.6.3 1.8.6.4 1.8.7.2 1.8.8.2 1.8.8.3 1.8.9.1 1.8.9.2 1.8.9.4 1.8.9.5 1.8.9.6 1.9.0.1 1.9.0.2 1.9.0.3 1.9.0.4 1.9.1.1 1.9.1.2 1.9.1.3 1.9.1.4 1.9.1.5 1.9.1.6 1.9.2.1 1.9.2.2 1.9.2.3 1.9.3.1 1.9.3.2 1.9.4.1 1.9.4.2 1.9.5 1.9.5.1 1.9.5.2 1.9.6 1.9.6.1 1.9.6.2 1.9.7.1 1.9.7.2 1.9.7.3 1.9.8.1 1.9.8.2 1.9.8.4 1.9.8.7 1.9.9.2 1.9.9.3 1.9.9.4
wpforms-lite / src / Frontend / CSSVars.php
wpforms-lite / src / Frontend Last commit date
Amp.php 1 year ago CSSVars.php 8 months ago Captcha.php 3 months ago Classic.php 1 year ago Frontend.php 8 months ago Modern.php 10 months ago
CSSVars.php
826 lines
1 <?php
2
3 namespace WPForms\Frontend;
4
5 use WPForms\Integrations\Gutenberg\ThemesData;
6 use WPForms\Lite\Integrations\Gutenberg\ThemesData as LiteThemesData;
7 use WPForms\Pro\Integrations\Gutenberg\ThemesData as ProThemesData;
8 use WPForms\Pro\Integrations\Gutenberg\StockPhotos;
9
10 /**
11 * CSS variables class.
12 *
13 * @since 1.8.1
14 */
15 class CSSVars {
16
17 /**
18 * Root vars and values.
19 *
20 * @since 1.8.1
21 *
22 * @var array
23 */
24 public const ROOT_VARS = [
25 'field-border-radius' => '3px',
26 'field-border-style' => 'solid',
27 'field-border-size' => '1px',
28 'field-background-color' => self::WHITE,
29 'field-border-color' => 'rgba( 0, 0, 0, 0.25 )',
30 'field-text-color' => 'rgba( 0, 0, 0, 0.7 )',
31 'field-menu-color' => self::WHITE,
32
33 'label-color' => 'rgba( 0, 0, 0, 0.85 )',
34 'label-sublabel-color' => 'rgba( 0, 0, 0, 0.55 )',
35 'label-error-color' => '#d63637',
36
37 'button-border-radius' => '3px',
38 'button-border-style' => 'none',
39 'button-border-size' => '1px',
40 'button-background-color' => '#066aab',
41 'button-border-color' => '#066aab',
42 'button-text-color' => self::WHITE,
43
44 'page-break-color' => '#066aab',
45
46 'background-image' => 'none',
47 'background-position' => 'center center',
48 'background-repeat' => 'no-repeat',
49 'background-size' => 'cover',
50 'background-width' => '100px',
51 'background-height' => '100px',
52 'background-color' => 'rgba( 0, 0, 0, 0 )',
53 'background-url' => 'url()',
54
55 'container-padding' => '0px',
56 'container-border-style' => 'none',
57 'container-border-width' => '1px',
58 'container-border-color' => '#000000',
59 'container-border-radius' => '3px',
60 ];
61
62 /**
63 * Container shadow vars and values.
64 *
65 * @since 1.8.8
66 *
67 * @var array
68 */
69 public const CONTAINER_SHADOW_SIZE = [
70 'none' => [
71 'box-shadow' => 'none',
72 ],
73 'small' => [
74 'box-shadow' => '0px 3px 5px 0px rgba(0, 0, 0, 0.1)',
75 ],
76 'medium' => [
77 'box-shadow' => '0px 10px 20px 0px rgba(0, 0, 0, 0.1)',
78 ],
79 'large' => [
80 'box-shadow' => '0px 30px 50px -10px rgba(0, 0, 0, 0.15)',
81 ],
82 ];
83
84 /**
85 * Field Size vars and values.
86 *
87 * @since 1.8.1
88 *
89 * @var array
90 */
91 public const FIELD_SIZE = [
92 'small' => [
93 'input-height' => '31px',
94 'input-spacing' => '10px',
95 'font-size' => '14px',
96 'line-height' => '17px',
97 'padding-h' => '9px',
98 'checkbox-size' => '14px',
99 'sublabel-spacing' => '5px',
100 'icon-size' => '0.75',
101 ],
102 'medium' => [
103 'input-height' => '43px',
104 'input-spacing' => '15px',
105 'font-size' => '16px',
106 'line-height' => '19px',
107 'padding-h' => '14px',
108 'checkbox-size' => '16px',
109 'sublabel-spacing' => '5px',
110 'icon-size' => '1',
111 ],
112 'large' => [
113 'input-height' => '50px',
114 'input-spacing' => '20px',
115 'font-size' => '18px',
116 'line-height' => '21px',
117 'padding-h' => '14px',
118 'checkbox-size' => '18px',
119 'sublabel-spacing' => '10px',
120 'icon-size' => '1.25',
121 ],
122 ];
123
124 /**
125 * Label Size vars and values.
126 *
127 * @since 1.8.1
128 *
129 * @var array
130 */
131 public const LABEL_SIZE = [
132 'small' => [
133 'font-size' => '14px',
134 'line-height' => '17px',
135 'sublabel-font-size' => '13px',
136 'sublabel-line-height' => '16px',
137 ],
138 'medium' => [
139 'font-size' => '16px',
140 'line-height' => '19px',
141 'sublabel-font-size' => '14px',
142 'sublabel-line-height' => '17px',
143 ],
144 'large' => [
145 'font-size' => '18px',
146 'line-height' => '21px',
147 'sublabel-font-size' => '16px',
148 'sublabel-line-height' => '19px',
149 ],
150 ];
151
152 /**
153 * Button Size vars and values.
154 *
155 * @since 1.8.1
156 *
157 * @var array
158 */
159 public const BUTTON_SIZE = [
160 'small' => [
161 'font-size' => '14px',
162 'height' => '37px',
163 'padding-h' => '15px',
164 'margin-top' => '5px',
165 ],
166 'medium' => [
167 'font-size' => '17px',
168 'height' => '41px',
169 'padding-h' => '15px',
170 'margin-top' => '10px',
171 ],
172 'large' => [
173 'font-size' => '20px',
174 'height' => '48px',
175 'padding-h' => '20px',
176 'margin-top' => '15px',
177 ],
178 ];
179
180 /**
181 * Spare variables.
182 *
183 * @since 1.8.8
184 *
185 * @var array
186 */
187 private const SPARE_VARS = [ 'field-border-color' ];
188
189 /**
190 * White color.
191 *
192 * @since 1.8.8
193 *
194 * @var string
195 */
196 private const WHITE = '#ffffff';
197
198 /**
199 * Render engine.
200 *
201 * @since 1.8.1
202 *
203 * @var string
204 */
205 private $render_engine;
206
207 /**
208 * CSS variables.
209 *
210 * @since 1.8.1
211 *
212 * @var array
213 */
214 private $css_vars;
215
216 /**
217 * Flag to check if root CSS vars were output.
218 *
219 * @since 1.8.1
220 *
221 * @var bool
222 */
223 private $is_root_vars_displayed;
224
225 /**
226 * Initialize class.
227 *
228 * @since 1.8.1
229 */
230 public function init(): void {
231
232 $this->init_vars();
233 }
234
235 /**
236 * CSS variables data.
237 *
238 * @since 1.8.1
239 */
240 private function init_vars(): void {
241
242 $vars = [];
243
244 $vars[':root'] = array_merge(
245 self::ROOT_VARS,
246 $this->get_complex_vars( 'field-size', self::FIELD_SIZE['medium'] ),
247 $this->get_complex_vars( 'label-size', self::LABEL_SIZE['medium'] ),
248 $this->get_complex_vars( 'button-size', self::BUTTON_SIZE['medium'] ),
249 $this->get_complex_vars( 'container-shadow-size', self::CONTAINER_SHADOW_SIZE['none'] )
250 );
251
252 /**
253 * Allows developers to modify default CSS variables which output on the frontend.
254 *
255 * @since 1.8.1
256 *
257 * @param array $vars CSS variables two-dimensional array.
258 * The first level keys is the CSS selector.
259 * Second level keys is the variable name without the `--wpforms-` prefix.
260 */
261 $this->css_vars = apply_filters( 'wpforms_frontend_css_vars_init_vars', $vars );
262 }
263
264 /**
265 * Get complex CSS variables data.
266 *
267 * @since 1.8.1
268 *
269 * @param string $prefix CSS variable prefix.
270 * @param array $values Values.
271 */
272 public function get_complex_vars( string $prefix, array $values ): array {
273
274 $vars = [];
275
276 foreach ( $values as $key => $value ) {
277 $vars[ "{$prefix}-{$key}" ] = $value;
278 }
279
280 return $vars;
281 }
282
283 /**
284 * Get CSS variables data by selector.
285 *
286 * @since 1.8.1
287 *
288 * @param string $selector Selector.
289 *
290 * @return array
291 */
292 public function get_vars( string $selector = ':root' ): array {
293
294 if ( empty( $this->css_vars[ $selector ] ) ) {
295 return [];
296 }
297
298 return $this->css_vars[ $selector ];
299 }
300
301 /**
302 * Output root CSS variables.
303 *
304 * @since 1.8.1
305 * @since 1.8.1.2 Added $force argument.
306 * @deprecated 1.9.3
307 *
308 * @param bool $force Force output root variables.
309 *
310 * @noinspection PhpMissingParamTypeInspection
311 */
312 public function output_root( $force = false ): void {
313
314 _deprecated_function( __METHOD__, '1.9.3 of the WPForms plugin' );
315
316 if ( ! empty( $this->is_root_vars_displayed ) && empty( $force ) ) {
317 return;
318 }
319
320 $this->output_selector_vars( ':root', $this->css_vars[':root'] );
321
322 $this->is_root_vars_displayed = true;
323 }
324
325 /**
326 * Get root variables CSS.
327 *
328 * @since 1.9.3
329 *
330 * @return string
331 */
332 public function get_root_vars_css(): string {
333
334 return $this->get_selector_vars_css( ':root', $this->css_vars[':root'] );
335 }
336
337 /**
338 * Output selector's CSS variables.
339 *
340 * @since 1.8.1
341 *
342 * @param string $selector Selector.
343 * @param array $vars Variables data.
344 * @param string $style_id Style tag ID attribute. Optional. Default is an empty string.
345 * @param string|int $form_id Form ID. Optional. Default is an empty string.
346 */
347 public function output_selector_vars( string $selector, array $vars, string $style_id = '', $form_id = '' ): void {
348
349 if ( empty( $this->render_engine ) ) {
350 $this->render_engine = wpforms_get_render_engine();
351 }
352
353 if ( $this->render_engine === 'classic' ) {
354 return;
355 }
356
357 // If this is not full "Base and Form Theme Styling", skip.
358 if ( (int) wpforms_setting( 'disable-css', '1' ) !== 1 ) {
359 return;
360 }
361
362 $style_id = empty( $style_id ) ? 'wpforms-css-vars-' . $selector : $style_id;
363
364 printf(
365 '<style id="%1$s">
366 %2$s
367 </style>',
368 sanitize_key( $style_id ),
369 $this->get_selector_vars_css( $selector, $vars, $form_id ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
370 );
371 }
372
373 /**
374 * Output CSS vars for the form added as a shortcode.
375 *
376 * @since 1.9.7
377 *
378 * @param array $atts Shortcode attributes.
379 */
380 public function output_css_vars_for_shortcode( array $atts ): void {
381
382 if ( empty( $atts['id'] ) ) {
383 return;
384 }
385
386 $form_handler = wpforms()->obj( 'form' );
387
388 if ( ! $form_handler ) {
389 return;
390 }
391
392 $form_id = (int) $atts['id'];
393 $form_data = $form_handler->get( $form_id, [ 'content_only' => true ] );
394
395 if ( empty( $form_data ) ) {
396 return;
397 }
398
399 $attr = isset( $form_data['settings']['themes'] ) ? (array) $form_data['settings']['themes'] : [];
400 $attr = $this->maybe_override_attributes( $attr );
401
402 $css_vars = $this->get_customized_css_vars( $attr );
403 $css_vars = $this->add_css_vars_units( $css_vars );
404
405 $selector = "#wpforms-{$form_id}";
406 $style_id = "wpforms-css-vars-{$form_id}";
407
408 $this->output_selector_vars( $selector, $css_vars, $style_id, $form_id );
409 $this->output_custom_css( $attr, $selector, $style_id );
410 }
411
412 /**
413 * Output custom CSS.
414 *
415 * @since 1.9.7
416 *
417 * @param array $attr Attributes.
418 * @param string $selector Selector.
419 * @param string $style_id Style ID.
420 *
421 * @noinspection PhpMissingParamTypeInspection
422 */
423 private function output_custom_css( array $attr, string $selector, string $style_id ): void {
424
425 if ( wpforms_get_render_engine() === 'classic' ) {
426 return;
427 }
428
429 $custom_css = trim( $attr['customCss'] ?? '' );
430
431 if ( empty( $custom_css ) ) {
432 return;
433 }
434
435 printf(
436 '<style id="%1$s-custom-css">
437 %2$s {
438 %3$s
439 }
440 </style>',
441 sanitize_key( $style_id ),
442 $selector, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
443 wp_strip_all_tags( $custom_css ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
444 );
445 }
446
447 /**
448 * Maybe override attributes with themes.json settings.
449 *
450 * @since 1.9.7
451 *
452 * @param array $attr Attributes.
453 *
454 * @return array
455 */
456 private function maybe_override_attributes( array $attr ): array {
457
458 $theme_slug = (string) ( $attr['wpformsTheme'] ?? '' );
459
460 if ( empty( $theme_slug ) ) {
461 return $attr;
462 }
463
464 $attr = $this->normalize_background_url( $attr );
465
466 $theme_data = $this->get_themes_data_object()->get_theme( $theme_slug );
467 $settings = $theme_data['settings'] ?? [];
468
469 return array_merge( $attr, $settings );
470 }
471
472 /**
473 * Normalize background URL.
474 *
475 * Check if the background URL is not wrapped in url() and add it if needed.
476 *
477 * @since 1.9.7
478 *
479 * @param array $attr Attributes.
480 */
481 private function normalize_background_url( array $attr ): array {
482
483 if ( ! isset( $attr['backgroundUrl'] ) ) {
484 return $attr;
485 }
486
487 if ( strpos( $attr['backgroundUrl'], 'url(' ) === 0 ) {
488 return $attr;
489 }
490
491 $attr['backgroundUrl'] = 'url(' . $attr['backgroundUrl'] . ')';
492
493 return $attr;
494 }
495
496 /**
497 * Get themes data object.
498 *
499 * @since 1.9.7
500 *
501 * @return ThemesData
502 */
503 private function get_themes_data_object(): ThemesData {
504
505 if ( wpforms()->is_pro() ) {
506 return new ProThemesData( new StockPhotos() );
507 }
508
509 return new LiteThemesData();
510 }
511
512 /**
513 * Add CSS vars units.
514 *
515 * Form builder saves values without pixels, we need to add them before outputting as CSS vars.
516 *
517 * @since 1.9.7
518 *
519 * @param array $css_vars CSS vars.
520 *
521 * @return array
522 */
523 private function add_css_vars_units( array $css_vars ): array {
524
525 $has_pixels = [
526 'field-border-size',
527 'field-border-radius',
528 'button-border-size',
529 'button-border-radius',
530 'container-padding',
531 'container-border-width',
532 'container-border-radius',
533 ];
534
535 foreach ( $has_pixels as $key ) {
536 if ( isset( $css_vars[ $key ] ) && is_numeric( $css_vars[ $key ] ) && $css_vars[ $key ] > 0 ) {
537 $css_vars[ $key ] .= 'px';
538 }
539 }
540
541 return $css_vars;
542 }
543
544 /**
545 * Get selector variables CSS.
546 *
547 * @since 1.9.3
548 *
549 * @param string $selector Selector.
550 * @param array $vars Variables data.
551 * @param string|int $form_id Form ID. Optional. Default is an empty string.
552 *
553 * @return string
554 */
555 private function get_selector_vars_css( string $selector, array $vars, $form_id = '' ): string {
556
557 return sprintf(
558 '%1$s {
559 %2$s
560 }',
561 $selector, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
562 wp_strip_all_tags( $this->get_vars_css( $vars, $form_id ) )
563 );
564 }
565
566 /**
567 * Pre print vars filter.
568 *
569 * @since 1.8.8
570 *
571 * @param array $vars Variables data.
572 * @param string|int $form_id Form ID. Optional. Default is an empty string.
573 *
574 * @return array
575 */
576 private function get_pre_print_vars( array $vars, $form_id = '' ): array {
577
578 // Normalize the `background-url` variable.
579 if ( isset( $vars['background-url'] ) ) {
580 $vars['background-url'] = $vars['background-url'] === 'url()' ? 'none' : $vars['background-url'];
581 }
582
583 /**
584 * Filter CSS variables right before printing the CSS.
585 *
586 * @since 1.8.8
587 *
588 * @param array $vars CSS variables.
589 * @param int $form_id Form ID. Optional. Default is an empty string.
590 */
591 return (array) apply_filters( 'wpforms_frontend_css_vars_pre_print_filter', $vars, $form_id );
592 }
593
594 /**
595 * Generate CSS code from given vars data.
596 *
597 * @since 1.8.1
598 *
599 * @param array $vars Variables data.
600 * @param string|int $form_id Form ID. Optional. Default is an empty string.
601 */
602 private function get_vars_css( array $vars, $form_id = '' ): string {
603
604 $vars = $this->get_pre_print_vars( $vars, $form_id );
605 $result = '';
606
607 foreach ( $vars as $name => $value ) {
608 if ( ! is_string( $value ) ) {
609 continue;
610 }
611
612 if ( $value === '0' ) {
613 $value = '0px';
614 }
615
616 $result .= "--wpforms-{$name}: {$value};\n";
617
618 if ( in_array( $name, self::SPARE_VARS, true ) ) {
619 $result .= "--wpforms-{$name}-spare: {$value};\n";
620 }
621 }
622
623 return $result;
624 }
625
626 /**
627 * Get customized CSS vars.
628 *
629 * @since 1.8.3
630 *
631 * @param array $attr Attributes passed by integration.
632 *
633 * @return array
634 */
635 public function get_customized_css_vars( array $attr ): array { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
636
637 $root_css_vars = $this->get_vars();
638 $css_vars = [];
639
640 foreach ( $attr as $key => $value ) {
641
642 $var_name = strtolower( preg_replace( '/[A-Z]/', '-$0', $key ) );
643
644 // Skip an attribute that is not the CSS var or has the default value.
645 if ( empty( $root_css_vars[ $var_name ] ) || $root_css_vars[ $var_name ] === $value ) {
646 continue;
647 }
648
649 $css_vars[ $var_name ] = $value;
650 }
651
652 // Reset border size in case of border style is `none`.
653 $css_vars = $this->maybe_reset_border( $css_vars, 'field-border' );
654 $css_vars = $this->maybe_reset_border( $css_vars, 'button-border' );
655
656 // Set the button alternative background color and use border color for accent in case of transparent color.
657 $button_bg_color = $css_vars['button-background-color'] ?? $root_css_vars['button-background-color'];
658
659 if ( $this->is_transparent_color( $button_bg_color ) ) {
660 $css_vars['button-background-color-alt'] = $button_bg_color;
661
662 $border_color = $css_vars['button-border-color'] ?? $root_css_vars['button-border-color'];
663
664 $css_vars['button-background-color'] = $this->is_transparent_color( $border_color ) ? $root_css_vars['button-background-color'] : $border_color;
665 $button_bg_color = $css_vars['button-background-color'];
666 }
667
668 $button_bg_color = strtolower( $button_bg_color );
669
670 // Set the button alternative text color in case if the background and text color are identical.
671 $button_text_color = strtolower( $css_vars['button-text-color'] ?? $root_css_vars['button-text-color'] );
672
673 if ( $button_bg_color === $button_text_color || $this->is_transparent_color( $button_text_color ) ) {
674 $css_vars['button-text-color-alt'] = $this->get_contrast_color( $button_bg_color );
675 }
676
677 $size_css_vars = $this->get_size_css_vars( $attr );
678
679 return array_merge( $css_vars, $size_css_vars );
680 }
681
682 /**
683 * Reset border size in case of border style is `none`.
684 *
685 * @since 1.9.7
686 *
687 * @param array $css_vars CSS vars.
688 * @param string $key Key.
689 *
690 * @return array
691 */
692 private function maybe_reset_border( array $css_vars, string $key ): array {
693
694 $style_key = $key . '-style';
695 $size_key = $key . '-size';
696
697 if ( isset( $css_vars[ $style_key ] ) && $css_vars[ $style_key ] === 'none' ) {
698 $css_vars[ $size_key ] = '0px';
699 }
700
701 return $css_vars;
702 }
703
704 /**
705 * Checks if the provided color has transparency.
706 *
707 * @since 1.8.8
708 *
709 * @param string $color The color to check.
710 *
711 * @return bool
712 */
713 private function is_transparent_color( string $color ): bool {
714
715 $rgba = $this->get_color_as_rgb_array( $color );
716
717 $opacity_threshold = 0.33;
718 $opacity = $rgba[3] ?? 1;
719
720 return $opacity < $opacity_threshold;
721 }
722
723 /**
724 * Get contrast color relative to a given color.
725 *
726 * @since 1.8.8
727 *
728 * @param string|array $color The color.
729 *
730 * @return string
731 */
732 private function get_contrast_color( $color ): string {
733
734 $rgba = is_array( $color ) ? $color : $this->get_color_as_rgb_array( $color );
735 $avg = (int) ( ( ( array_sum( $rgba ) ) / 3 ) * ( $rgba[3] ?? 1 ) );
736
737 return $avg < 128 ? '#ffffff' : '#000000';
738 }
739
740 /**
741 * Get size CSS vars.
742 *
743 * @since 1.8.3
744 * @since 1.8.8 Removed $css_vars argument.
745 *
746 * @param array $attr Attributes passed by integration.
747 *
748 * @return array
749 */
750 private function get_size_css_vars( array $attr ): array {
751
752 $size_items = [ 'field', 'label', 'button', 'container-shadow' ];
753 $size_css_vars = [];
754
755 foreach ( $size_items as $item ) {
756
757 $item_attr = preg_replace_callback(
758 '/-(\w)/',
759 static function ( $matches ) {
760
761 return strtoupper( $matches[1] );
762 },
763 $item
764 );
765
766 $item_attr .= 'Size';
767
768 $item_key = $item . '-size';
769 $item_constant = 'self::' . str_replace( '-', '_', strtoupper( $item ) ) . '_SIZE';
770
771 if ( empty( $attr[ $item_attr ] ) ) {
772 continue;
773 }
774
775 $size_css_vars[] = $this->get_complex_vars( $item_key, constant( $item_constant )[ $attr[ $item_attr ] ] );
776 }
777
778 return empty( $size_css_vars ) ? [] : array_merge( ...$size_css_vars );
779 }
780
781 /**
782 * Get color as an array of RGB(A) values.
783 *
784 * @since 1.8.8
785 *
786 * @param string $color Color.
787 *
788 * @return array|bool Color as an array of RGBA values. False on error.
789 */
790 private function get_color_as_rgb_array( string $color ) {
791
792 // Remove # from the beginning of the string and remove whitespaces.
793 $color = preg_replace( '/^#/', '', strtolower( trim( $color ) ) );
794 $color = str_replace( ' ', '', (string) $color );
795
796 if ( $color === 'transparent' ) {
797 $color = 'rgba(0,0,0,0)';
798 }
799
800 $rgba = $color;
801 $rgb_array = [];
802
803 // Check if color is in HEX(A) format.
804 $is_hex = preg_match( '/[0-9a-f]{6,8}$/', $rgba );
805
806 if ( $is_hex ) {
807 // Search and split HEX(A) color into an array of char couples.
808 preg_match_all( '/\w\w/', $rgba, $rgb_array );
809
810 $rgb_array = array_map(
811 static function ( $value ) {
812
813 return hexdec( '0x' . $value );
814 },
815 $rgb_array[0] ?? []
816 );
817 $rgb_array[3] = ( $rgb_array[3] ?? 255 ) / 255;
818 } else {
819 $rgba = preg_replace( '/[^\d,.]/', '', $rgba );
820 $rgb_array = explode( ',', $rgba );
821 }
822
823 return $rgb_array;
824 }
825 }
826