Diff: STRATO-apps/wordpress_03/app/wp-content/themes/blocksy/inc/classes/class-ct-css-injector.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 + /**
3 + * CSS Injector
4 + * Helper object for including dynamic styles into head of the document,
5 + * with possibilities of extending it.
6 + *
7 + * @copyright 2019-present Creative Themes
8 + * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
9 + * @package Blocksy
10 + */
11 +
12 + class Blocksy_Css_Injector {
13 + /**
14 + * Temporary CSS attributes.
15 + *
16 + * @var array $attr Attributes.
17 + */
18 + private $attr = [];
19 + private $additional_symbols = [];
20 + private $selector_prefix = null;
21 + private $fonts_manager = null;
22 +
23 + /**
24 + * Keyword that allows skiping a certain CSS rule from getting in the output.
25 + */
26 + public static function get_skip_rule_keyword($suffix = '') {
27 + return 'CT_CSS_SKIP_RULE' . $suffix;
28 + }
29 +
30 + public static function get_inline_keyword($suffix = '') {
31 + return 'CT_CSS_INLINE_CSS' . $suffix;
32 + }
33 +
34 + /**
35 + * Injector constructor.
36 + */
37 + public function __construct($args = []) {
38 + $args = wp_parse_args(
39 + $args,
40 + [
41 + 'selector_prefix' => '',
42 + 'fonts_manager' => null
43 + ]
44 + );
45 +
46 + if (! empty($args['selector_prefix'])) {
47 + $this->selector_prefix = $args['selector_prefix'];
48 + }
49 +
50 + $this->additional_symbols = ['-', '%', 'px', 's'];
51 +
52 + if ($args['fonts_manager']) {
53 + $this->fonts_manager = $args['fonts_manager'];
54 + }
55 + }
56 +
57 + public function process_matching_typography($value) {
58 + if (! $this->fonts_manager) {
59 + return;
60 + }
61 +
62 + $this->fonts_manager->process_matching_typography($value);
63 + }
64 +
65 + /**
66 + * Parse each temporary structure and transform it into actual CSS.
67 + */
68 + public function build_css_structure() {
69 + $content = '';
70 +
71 + if (isset($this->attr[Blocksy_Css_Injector::get_inline_keyword()])) {
72 + $content .= implode('', $this->attr[Blocksy_Css_Injector::get_inline_keyword()]);
73 + unset($this->attr[Blocksy_Css_Injector::get_inline_keyword()]);
74 + }
75 +
76 + if (count($this->attr)) {
77 + $content .= "\n" . $this->convert_to_css();
78 + }
79 +
80 + $content = $this->css_minify($content);
81 +
82 + return $content;
83 + }
84 +
85 + public function get_wp_style_engine_rules($args = []) {
86 + $args = wp_parse_args(
87 + $args,
88 + [
89 + 'device' => 'desktop'
90 + ]
91 + );
92 +
93 + $media_queries = [
94 + 'tablet' => '@media (max-width: 999.98px)',
95 + 'mobile' => '@media (max-width: 689.98px)'
96 + ];
97 +
98 + $rules = [];
99 +
100 + foreach ($this->attr as $selector => $lines) {
101 + $declarations = [];
102 +
103 + foreach ($lines as $line) {
104 + $line = trim($line);
105 +
106 + if (! $line) {
107 + continue;
108 + }
109 +
110 + $parts = explode(':', $line);
111 +
112 + if (count($parts) <= 1) {
113 + continue;
114 + }
115 +
116 + $declarations[trim($parts[0])] = trim($parts[1]);
117 + }
118 +
119 + $rule = [
120 + 'selector' => $selector,
121 + 'declarations' => $declarations
122 + ];
123 +
124 + if (isset($media_queries[$args['device']])) {
125 + $rule['rules_group'] = $media_queries[$args['device']];
126 + }
127 +
128 + $rules[] = $rule;
129 + }
130 +
131 + return $rules;
132 + }
133 +
134 + /**
135 + * Add new line in CSS structure.
136 + *
137 + * @param string|array $selector CSS class, id, tag.
138 + * @param string|array $rules CSS syntax.
139 + */
140 + public function put($selector, $rules) {
141 + $normalized = $this->normalize_inputs($selector, $rules);
142 +
143 + if (! $normalized) {
144 + return;
145 + }
146 +
147 + $selector = $normalized['selector'];
148 + $rules = $normalized['rules'];
149 +
150 + if (! isset($this->attr[$selector])) {
151 + $this->attr[$selector] = [];
152 + }
153 +
154 + foreach ($rules as $line) {
155 + $line = trim($line);
156 +
157 + if (
158 + ! $line
159 + ||
160 + in_array($line, $this->attr[$selector], true)
161 + ) {
162 + continue;
163 + }
164 +
165 + if (strpos($line, self::get_skip_rule_keyword()) !== false) {
166 + continue;
167 + }
168 +
169 + $this->attr[$selector][] = $line;
170 + }
171 + }
172 +
173 + private function normalize_inputs($selector, $preliminary_rules) {
174 + if (is_string($preliminary_rules) && trim($preliminary_rules) === '') {
175 + return false;
176 + }
177 +
178 + if (is_array($selector)) {
179 + $selector = implode(",\n", $selector);
180 + }
181 +
182 + $rules = [];
183 +
184 + if ($selector === Blocksy_Css_Injector::get_inline_keyword()) {
185 + $rules = is_array($preliminary_rules) ? $preliminary_rules : [
186 + $preliminary_rules
187 + ];
188 + } else {
189 + // Convert string to array.
190 + if (! is_array($preliminary_rules)) {
191 + $rules = explode(';', $preliminary_rules);
192 + } else {
193 + // Support nested rules.
194 + foreach ($preliminary_rules as $maybe_rule) {
195 + $current_rules = explode(';', $maybe_rule);
196 +
197 + foreach ($current_rules as $current_rule) {
198 + $rules[] = $current_rule;
199 + }
200 + }
201 + }
202 + }
203 +
204 + $prefix = '';
205 +
206 + if (! empty($this->selector_prefix)) {
207 + $prefix = $this->selector_prefix . ' ';
208 + }
209 +
210 + return [
211 + 'selector' => $prefix . $selector,
212 + 'rules' => $rules
213 + ];
214 + }
215 +
216 + /**
217 + * Merge selectors that have the same CSS. This has the effect of increasing
218 + * the weight of the selectors.
219 + */
220 + private function merge_class_with_the_same_css() {
221 + return;
222 +
223 + $new_names = [];
224 + $used = [];
225 +
226 + foreach ($this->attr as $key => $values) {
227 + if (isset($used[$key])) {
228 + continue;
229 + }
230 +
231 + foreach ($this->attr as $sub_key => $sub_values) {
232 + if ($sub_key !== $key && $values === $sub_values) {
233 + $used[$sub_key] = 1;
234 + $new_names[$key][] = $sub_key;
235 + $used[$key] = 1;
236 + }
237 + }
238 + }
239 +
240 + // Merge classes.
241 + foreach ($new_names as $parent => $childs) {
242 + $class_name = $parent . ",\n" . join(",\n", $childs);
243 + $this->attr[$class_name] = $this->attr[$parent];
244 +
245 + // Remove CSS from main structure.
246 + if (isset($this->attr[$parent])) {
247 + unset($this->attr[$parent]);
248 + }
249 +
250 + // Remove all childs css.
251 + foreach ($childs as $child_class) {
252 + if (isset($this->attr[$child_class])) {
253 + unset($this->attr[$child_class]);
254 + }
255 + }
256 + }
257 + }
258 +
259 + /**
260 + * Convert this->attr to a CSS string.
261 + */
262 + private function convert_to_css() {
263 + $css = '';
264 +
265 + $this->merge_class_with_the_same_css();
266 +
267 + foreach ($this->attr as $key => $values) {
268 + $section = '';
269 +
270 + $section .= $key . " {\n";
271 +
272 + $content = '';
273 +
274 + foreach ($values as $line) {
275 + $line = trim($line);
276 +
277 + if (! $this->is_empty_style($line)) {
278 + if (strpos($key, '@media') === false) {
279 + $line = str_replace(';', '', $line);
280 + }
281 +
282 + $content .= " {$line}";
283 +
284 + if (strpos($key, '@media') === false) {
285 + $content .= ";\n";
286 + }
287 + }
288 + }
289 +
290 + // CSS is not empty.
291 + if ($content) {
292 + $section .= $content;
293 + } else {
294 + continue;
295 + }
296 +
297 + $section .= "}\n\n";
298 + $css .= $section;
299 + }
300 +
301 + // Erase structure.
302 + $this->attr = [];
303 +
304 + return $css;
305 + }
306 +
307 + /**
308 + * Check if a CSS rule is empty.
309 + *
310 + * @param string $line Single rule.
311 + */
312 + private function is_empty_style($line) {
313 + $parts = explode(':', $line);
314 +
315 + if (count($parts) <= 1) {
316 + return false;
317 + }
318 +
319 + if (! isset($parts[1])) {
320 + return true;
321 + }
322 +
323 + $parts[1] = str_replace($this->additional_symbols, '', $parts[1]);
324 +
325 + return strlen(trim($parts[1])) === 0;
326 + }
327 +
328 + /**
329 + * Very rudimentary CSS minifier.
330 + *
331 + * @param string $minify CSS to be minified.
332 + */
333 + private function css_minify($minify) {
334 + if (defined('WP_DEBUG') && WP_DEBUG) {
335 + // return $minify;
336 + }
337 +
338 + // return $minify;
339 +
340 + /* remove comments */
341 + $minify = preg_replace( '!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $minify );
342 +
343 + /* remove tabs, spaces, newlines, etc. */
344 + $minify = str_replace( array( "\r\n", "\r", "\n", "\t", ' ', ' ', ' ' ), '', $minify );
345 + /* remove space after colons */
346 + $minify = str_replace( ': ', ':', $minify );
347 + $minify = str_replace( '}[', '} [', $minify );
348 +
349 + return $minify;
350 + }
351 + }
352 +
353 +