PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
← All changes | lib/ext/compressor.php +264 -0 22.5.222.7.0 View file →
@@ -1,0 +1,264 @@
1 +<?php
2 +
3 +if ( ! defined( 'ABSPATH' ) ) {
4 +
5 + die( 'These aren\'t the droids you\'re looking for.' );
6 +}
7 +
8 +if ( ! class_exists( 'SuextMinifyCssCompressor' ) ) {
9 +
10 + /**
11 + * Compress CSS
12 + *
13 + * This is a heavy regex-based removal of whitespace, unnecessary
14 + * comments and tokens, and some CSS value minimization, where practical.
15 + * Many steps have been taken to avoid breaking comment-based hacks,
16 + * including the ie5/mac filter (and its inversion), but expect tricky
17 + * hacks involving comment tokens in 'content' value strings to break
18 + * minimization badly. A test suite is available.
19 + *
20 + * @package Minify
21 + * @author Stephen Clay <steve@mrclay.org>
22 + * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
23 + */
24 + class SuextMinifyCssCompressor {
25 +
26 + /**
27 + * Minify a CSS string
28 + *
29 + * @param string $css
30 + *
31 + * @param array $options (currently ignored)
32 + *
33 + * @return string
34 + */
35 + public static function process( $css, $options = array() ) {
36 +
37 + $instance = new SuextMinifyCssCompressor( $options );
38 +
39 + return $instance->_process( $css );
40 + }
41 +
42 + /**
43 + * @var array
44 + */
45 + protected $_options = null;
46 +
47 + /**
48 + * Are we "in" a hack? I.e. are some browsers targetted until the next comment?
49 + *
50 + * @var bool
51 + */
52 + protected $_inHack = false;
53 +
54 +
55 + /**
56 + * Constructor
57 + *
58 + * @param array $options (currently ignored)
59 + */
60 + private function __construct($options)
61 + {
62 + $this->_options = $options;
63 + }
64 +
65 + /**
66 + * Minify a CSS string
67 + *
68 + * @param string $css
69 + *
70 + * @return string
71 + */
72 + protected function _process($css)
73 + {
74 + $css = str_replace("\r\n", "\n", $css);
75 +
76 + // preserve empty comment after '>'
77 + // http://www.webdevout.net/css-hacks#in_css-selectors
78 + $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
79 +
80 + // preserve empty comment between property and value
81 + // http://css-discuss.incutio.com/?page=BoxModelHack
82 + $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
83 + $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
84 +
85 + // apply callback to all valid comments (and strip out surrounding ws
86 + $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
87 + ,array($this, '_commentCB'), $css);
88 +
89 + // remove ws around { } and last semicolon in declaration block
90 + $css = preg_replace('/\\s*{\\s*/', '{', $css);
91 + $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
92 +
93 + // remove ws surrounding semicolons
94 + $css = preg_replace('/\\s*;\\s*/', ';', $css);
95 +
96 + // remove ws around urls
97 + $css = preg_replace('/
98 + url\\( # url(
99 + \\s*
100 + ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
101 + \\s*
102 + \\) # )
103 + /x', 'url($1)', $css);
104 +
105 + // remove ws between rules and colons
106 + $css = preg_replace('/
107 + \\s*
108 + ([{;]) # 1 = beginning of block or rule separator
109 + \\s*
110 + ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
111 + \\s*
112 + :
113 + \\s*
114 + (\\b|[#\'"-]) # 3 = first character of a value
115 + /x', '$1$2:$3', $css);
116 +
117 + // remove ws in selectors
118 + $css = preg_replace_callback('/
119 + (?: # non-capture
120 + \\s*
121 + [^~>+,\\s]+ # selector part
122 + \\s*
123 + [,>+~] # combinators
124 + )+
125 + \\s*
126 + [^~>+,\\s]+ # selector part
127 + { # open declaration block
128 + /x'
129 + ,array($this, '_selectorsCB'), $css);
130 +
131 + // minimize hex colors
132 + $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
133 + , '$1#$2$3$4$5', $css);
134 +
135 + // remove spaces between font families
136 + $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
137 + ,array($this, '_fontFamilyCB'), $css);
138 +
139 + $css = preg_replace('/@import\\s+url/', '@import url', $css);
140 +
141 + // replace any ws involving newlines with a single newline
142 + $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
143 +
144 + // separate common descendent selectors w/ newlines (to limit line lengths)
145 + $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
146 +
147 + // Use newline after 1st numeric value (to limit line lengths).
148 + $css = preg_replace('/
149 + ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
150 + \\s+
151 + /x'
152 + ,"$1\n", $css);
153 +
154 + // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
155 + $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
156 +
157 + return trim($css);
158 + }
159 +
160 + /**
161 + * Replace what looks like a set of selectors
162 + *
163 + * @param array $m regex matches
164 + *
165 + * @return string
166 + */
167 + protected function _selectorsCB($m)
168 + {
169 + // remove ws around the combinators
170 + return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
171 + }
172 +
173 + /**
174 + * Process a comment and return a replacement
175 + *
176 + * @param array $m regex matches
177 + *
178 + * @return string
179 + */
180 + protected function _commentCB($m)
181 + {
182 + $hasSurroundingWs = (trim($m[0]) !== $m[1]);
183 + $m = $m[1];
184 + // $m is the comment content w/o the surrounding tokens,
185 + // but the return value will replace the entire comment.
186 + if ($m === 'keep') {
187 + return '/**/';
188 + }
189 + if ($m === '" "') {
190 + // component of http://tantek.com/CSS/Examples/midpass.html
191 + return '/*" "*/';
192 + }
193 + if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
194 + // component of http://tantek.com/CSS/Examples/midpass.html
195 + return '/*";}}/* */';
196 + }
197 + if ($this->_inHack) {
198 + // inversion: feeding only to one browser
199 + if (preg_match('@
200 + ^/ # comment started like /*/
201 + \\s*
202 + (\\S[\\s\\S]+?) # has at least some non-ws content
203 + \\s*
204 + /\\* # ends like /*/ or /**/
205 + @x', $m, $n)) {
206 + // end hack mode after this comment, but preserve the hack and comment content
207 + $this->_inHack = false;
208 + return "/*/{$n[1]}/**/";
209 + }
210 + }
211 + if (substr($m, -1) === '\\') { // comment ends like \*/
212 + // begin hack mode and preserve hack
213 + $this->_inHack = true;
214 + return '/*\\*/';
215 + }
216 + if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
217 + // begin hack mode and preserve hack
218 + $this->_inHack = true;
219 + return '/*/*/';
220 + }
221 + if ($this->_inHack) {
222 + // a regular comment ends hack mode but should be preserved
223 + $this->_inHack = false;
224 + return '/**/';
225 + }
226 + // Issue 107: if there's any surrounding whitespace, it may be important, so
227 + // replace the comment with a single space
228 + return $hasSurroundingWs // remove all other comments
229 + ? ' '
230 + : '';
231 + }
232 +
233 + /**
234 + * Process a font-family listing and return a replacement
235 + *
236 + * @param array $m regex matches
237 + *
238 + * @return string
239 + */
240 + protected function _fontFamilyCB($m)
241 + {
242 + /*
243 + * Update on 2023/11/07 by jsmoriss: Changed null to $limit = -1.
244 + */
245 + $pieces = preg_split( '/(\'[^\']+\'|"[^"]+")/', $m[ 1 ], $limit = -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
246 +
247 + $out = 'font-family:';
248 +
249 + while (null !== ($piece = array_shift($pieces))) {
250 +
251 + if ($piece[0] !== '"' && $piece[0] !== "'") {
252 +
253 + $piece = preg_replace('/\\s+/', ' ', $piece);
254 +
255 + $piece = preg_replace('/\\s?,\\s?/', ',', $piece);
256 + }
257 +
258 + $out .= $piece;
259 + }
260 +
261 + return $out . $m[2];
262 + }
263 + }
264 +}