summaryrefslogtreecommitdiffstats
path: root/wp-includes/style-engine/class-wp-style-engine-css-rule.php
blob: 291652a615016ff49b9883206645fa086df60d13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<?php
/**
 * Style Engine: WP_Style_Engine_CSS_Rule class
 *
 * @package WordPress
 * @subpackage StyleEngine
 * @since 6.1.0
 */

/**
 * Core class used for style engine CSS rules.
 *
 * Holds, sanitizes, processes, and prints CSS declarations for the style engine.
 *
 * @since 6.1.0
 */
#[AllowDynamicProperties]
class WP_Style_Engine_CSS_Rule {

	/**
	 * The selector.
	 *
	 * @since 6.1.0
	 * @var string
	 */
	protected $selector;

	/**
	 * The selector declarations.
	 *
	 * Contains a WP_Style_Engine_CSS_Declarations object.
	 *
	 * @since 6.1.0
	 * @var WP_Style_Engine_CSS_Declarations
	 */
	protected $declarations;

	/**
	 * A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
	 * such as `@media (min-width: 80rem)` or `@layer module`.
	 *
	 * @since 6.6.0
	 * @var string
	 */
	protected $rules_group;

	/**
	 * Constructor.
	 *
	 * @since 6.1.0
	 * @since 6.6.0 Added the `$rules_group` parameter.
	 *
	 * @param string                                    $selector     Optional. The CSS selector. Default empty string.
	 * @param string[]|WP_Style_Engine_CSS_Declarations $declarations Optional. An associative array of CSS definitions,
	 *                                                                e.g. `array( "$property" => "$value", "$property" => "$value" )`,
	 *                                                                or a WP_Style_Engine_CSS_Declarations object.
	 *                                                                Default empty array.
	 * @param string                                    $rules_group  A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
	 *                                                                such as `@media (min-width: 80rem)` or `@layer module`.
	 */
	public function __construct( $selector = '', $declarations = array(), $rules_group = '' ) {
		$this->set_selector( $selector );
		$this->add_declarations( $declarations );
		$this->set_rules_group( $rules_group );
	}

	/**
	 * Sets the selector.
	 *
	 * @since 6.1.0
	 *
	 * @param string $selector The CSS selector.
	 * @return WP_Style_Engine_CSS_Rule Returns the object to allow chaining of methods.
	 */
	public function set_selector( $selector ) {
		$this->selector = $selector;
		return $this;
	}

	/**
	 * Sets the declarations.
	 *
	 * @since 6.1.0
	 *
	 * @param string[]|WP_Style_Engine_CSS_Declarations $declarations An array of declarations (property => value pairs),
	 *                                                                or a WP_Style_Engine_CSS_Declarations object.
	 * @return WP_Style_Engine_CSS_Rule Returns the object to allow chaining of methods.
	 */
	public function add_declarations( $declarations ) {
		$is_declarations_object = ! is_array( $declarations );
		$declarations_array     = $is_declarations_object ? $declarations->get_declarations() : $declarations;

		if ( null === $this->declarations ) {
			if ( $is_declarations_object ) {
				$this->declarations = $declarations;
				return $this;
			}
			$this->declarations = new WP_Style_Engine_CSS_Declarations( $declarations_array );
		}
		$this->declarations->add_declarations( $declarations_array );

		return $this;
	}

	/**
	 * Sets the rules group.
	 *
	 * @since 6.6.0
	 *
	 * @param string $rules_group A parent CSS selector in the case of nested CSS, or a CSS nested @rule,
	 *                            such as `@media (min-width: 80rem)` or `@layer module`.
	 * @return WP_Style_Engine_CSS_Rule Returns the object to allow chaining of methods.
	 */
	public function set_rules_group( $rules_group ) {
		$this->rules_group = $rules_group;
		return $this;
	}

	/**
	 * Gets the rules group.
	 *
	 * @since 6.6.0
	 *
	 * @return string
	 */
	public function get_rules_group() {
		return $this->rules_group;
	}

	/**
	 * Gets the declarations object.
	 *
	 * @since 6.1.0
	 *
	 * @return WP_Style_Engine_CSS_Declarations The declarations object.
	 */
	public function get_declarations() {
		return $this->declarations;
	}

	/**
	 * Gets the full selector.
	 *
	 * @since 6.1.0
	 *
	 * @return string
	 */
	public function get_selector() {
		return $this->selector;
	}

	/**
	 * Gets the CSS.
	 *
	 * @since 6.1.0
	 * @since 6.6.0 Added support for nested CSS with rules groups.
	 *
	 * @param bool $should_prettify Optional. Whether to add spacing, new lines and indents.
	 *                              Default false.
	 * @param int  $indent_count    Optional. The number of tab indents to apply to the rule.
	 *                              Applies if `prettify` is `true`. Default 0.
	 * @return string
	 */
	public function get_css( $should_prettify = false, $indent_count = 0 ) {
		$rule_indent                = $should_prettify ? str_repeat( "\t", $indent_count ) : '';
		$nested_rule_indent         = $should_prettify ? str_repeat( "\t", $indent_count + 1 ) : '';
		$declarations_indent        = $should_prettify ? $indent_count + 1 : 0;
		$nested_declarations_indent = $should_prettify ? $indent_count + 2 : 0;
		$suffix                     = $should_prettify ? "\n" : '';
		$spacer                     = $should_prettify ? ' ' : '';
		// Trims any multiple selectors strings.
		$selector         = $should_prettify ? implode( ',', array_map( 'trim', explode( ',', $this->get_selector() ) ) ) : $this->get_selector();
		$selector         = $should_prettify ? str_replace( array( ',' ), ",\n", $selector ) : $selector;
		$rules_group      = $this->get_rules_group();
		$has_rules_group  = ! empty( $rules_group );
		$css_declarations = $this->declarations->get_declarations_string( $should_prettify, $has_rules_group ? $nested_declarations_indent : $declarations_indent );

		if ( empty( $css_declarations ) ) {
			return '';
		}

		if ( $has_rules_group ) {
			$selector = "{$rule_indent}{$rules_group}{$spacer}{{$suffix}{$nested_rule_indent}{$selector}{$spacer}{{$suffix}{$css_declarations}{$suffix}{$nested_rule_indent}}{$suffix}{$rule_indent}}";
			return $selector;
		}

		return "{$rule_indent}{$selector}{$spacer}{{$suffix}{$css_declarations}{$suffix}{$rule_indent}}";
	}
}