PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
← All changes | vendor/matthiasmullie/minify/src/CSS.php +165 -47 3.3.1 → 4.7.0 View file →
@@ -12,8 +12,9 @@
12 12
13 13 namespace MatthiasMullie\Minify;
14 14
15 15 use MatthiasMullie\Minify\Exceptions\FileImportException;
16 +use MatthiasMullie\Minify\Exceptions\PatternMatchException;
16 17 use MatthiasMullie\PathConverter\Converter;
17 18 use MatthiasMullie\PathConverter\ConverterInterface;
18 19
19 20 /**
@@ -105,13 +106,13 @@
105 106
106 107 /**
107 108 * Combine CSS from import statements.
108 109 *
109 - * Import statements will be loaded and their content merged into the original
110 - * file, to save HTTP requests.
110 + * \@import's will be loaded and their content merged into the original file,
111 + * to save HTTP requests.
111 112 *
112 - * @param string $source The file to combine imports for
113 - * @param string $content The CSS content to combine imports for
113 + * @param string $source The file to combine imports for
114 + * @param string $content The CSS content to combine imports for
114 115 * @param string[] $parents Parent paths, for circular reference checks
115 116 *
116 117 * @return string
117 118 *
@@ -244,9 +245,9 @@
244 245 *
245 246 * @url(image.jpg) images will be loaded and their content merged into the
246 247 * original file, to save HTTP requests.
247 248 *
248 - * @param string $source The file to import files for
249 + * @param string $source The file to import files for
249 250 * @param string $content The CSS content to import files for
250 251 *
251 252 * @return string
252 253 */
@@ -295,8 +296,10 @@
295 296 * @param string[optional] $path Path to write the data to
296 297 * @param string[] $parents Parent paths, for circular reference checks
297 298 *
298 299 * @return string The minified data
300 + *
301 + * @throws PatternMatchException
299 302 */
300 303 public function execute($path = null, $parents = array())
301 304 {
302 305 $content = '';
@@ -315,9 +318,11 @@
315 318 $this->extractCustomProperties();
316 319 $css = $this->replace($css);
317 320
318 321 $css = $this->stripWhitespace($css);
319 - $css = $this->shortenColors($css);
322 + $css = $this->convertLegacyColors($css);
323 + $css = $this->cleanupModernColors($css);
324 + $css = $this->shortenHEXColors($css);
320 325 $css = $this->shortenZeroes($css);
321 326 $css = $this->shortenFontWeights($css);
322 327 $css = $this->stripEmptyTags($css);
323 328
@@ -354,9 +359,9 @@
354 359 * will have to be updated when a file is being saved at another location
355 360 * (e.g. ../../images/image.gif, if the new CSS file is 1 folder deeper).
356 361 *
357 362 * @param ConverterInterface $converter Relative path converter
358 - * @param string $content The CSS content to update relative urls for
363 + * @param string $content The CSS content to update relative urls for
359 364 *
360 365 * @return string
361 366 */
362 367 protected function move(ConverterInterface $converter, $content)
@@ -479,61 +484,86 @@
479 484 return str_replace($search, $replace, $content);
480 485 }
481 486
482 487 /**
483 - * Shorthand hex color codes.
484 - * #FF0000 -> #F00.
488 + * Shorthand HEX color codes.
489 + * #FF0000FF -> #f00 -> red
490 + * #FF00FF00 -> transparent.
485 491 *
486 - * @param string $content The CSS content to shorten the hex color codes for
492 + * @param string $content The CSS content to shorten the HEX color codes for
487 493 *
488 494 * @return string
489 495 */
490 - protected function shortenColors($content)
496 + protected function shortenHexColors($content)
491 497 {
492 - $content = preg_replace('/(?<=[: ])#([0-9a-z])\\1([0-9a-z])\\2([0-9a-z])\\3(?:([0-9a-z])\\4)?(?=[; }])/i', '#$1$2$3$4', $content);
498 + // shorten repeating patterns within HEX ..
499 + $content = preg_replace('/(?<=[: ])#([0-9a-f])\\1([0-9a-f])\\2([0-9a-f])\\3(?:([0-9a-f])\\4)?(?=[; }])/i', '#$1$2$3$4', $content);
493 500
494 - // remove alpha channel if it's pointless...
495 - $content = preg_replace('/(?<=[: ])#([0-9a-z]{6})ff?(?=[; }])/i', '#$1', $content);
496 - $content = preg_replace('/(?<=[: ])#([0-9a-z]{3})f?(?=[; }])/i', '#$1', $content);
501 + // remove alpha channel if it's pointless ..
502 + $content = preg_replace('/(?<=[: ])#([0-9a-f]{6})ff(?=[; }])/i', '#$1', $content);
503 + $content = preg_replace('/(?<=[: ])#([0-9a-f]{3})f(?=[; }])/i', '#$1', $content);
497 504
505 + // replace `transparent` with shortcut ..
506 + $content = preg_replace('/(?<=[: ])#[0-9a-f]{6}00(?=[; }])/i', '#fff0', $content);
507 +
498 508 $colors = array(
509 + // make these more readable
510 + '#00f' => 'blue',
511 + '#dc143c' => 'crimson',
512 + '#0ff' => 'cyan',
513 + '#8b0000' => 'darkred',
514 + '#696969' => 'dimgray',
515 + '#ff69b4' => 'hotpink',
516 + '#0f0' => 'lime',
517 + '#fdf5e6' => 'oldlace',
518 + '#87ceeb' => 'skyblue',
519 + '#d8bfd8' => 'thistle',
499 520 // we can shorten some even more by replacing them with their color name
500 - '#F0FFFF' => 'azure',
501 - '#F5F5DC' => 'beige',
502 - '#A52A2A' => 'brown',
503 - '#FF7F50' => 'coral',
504 - '#FFD700' => 'gold',
521 + '#f0ffff' => 'azure',
522 + '#f5f5dc' => 'beige',
523 + '#ffe4c4' => 'bisque',
524 + '#a52a2a' => 'brown',
525 + '#ff7f50' => 'coral',
526 + '#ffd700' => 'gold',
505 527 '#808080' => 'gray',
506 528 '#008000' => 'green',
507 - '#4B0082' => 'indigo',
508 - '#FFFFF0' => 'ivory',
509 - '#F0E68C' => 'khaki',
510 - '#FAF0E6' => 'linen',
529 + '#4b0082' => 'indigo',
530 + '#fffff0' => 'ivory',
531 + '#f0e68c' => 'khaki',
532 + '#faf0e6' => 'linen',
511 533 '#800000' => 'maroon',
512 534 '#000080' => 'navy',
513 535 '#808000' => 'olive',
514 - '#CD853F' => 'peru',
515 - '#FFC0CB' => 'pink',
516 - '#DDA0DD' => 'plum',
536 + '#ffa500' => 'orange',
537 + '#da70d6' => 'orchid',
538 + '#cd853f' => 'peru',
539 + '#ffc0cb' => 'pink',
540 + '#dda0dd' => 'plum',
517 541 '#800080' => 'purple',
518 - '#F00' => 'red',
519 - '#FA8072' => 'salmon',
520 - '#A0522D' => 'sienna',
521 - '#C0C0C0' => 'silver',
522 - '#FFFAFA' => 'snow',
523 - '#D2B48C' => 'tan',
524 - '#FF6347' => 'tomato',
525 - '#EE82EE' => 'violet',
526 - '#F5DEB3' => 'wheat',
542 + '#f00' => 'red',
543 + '#fa8072' => 'salmon',
544 + '#a0522d' => 'sienna',
545 + '#c0c0c0' => 'silver',
546 + '#fffafa' => 'snow',
547 + '#d2b48c' => 'tan',
548 + '#008080' => 'teal',
549 + '#ff6347' => 'tomato',
550 + '#ee82ee' => 'violet',
551 + '#f5deb3' => 'wheat',
527 552 // or the other way around
528 - 'WHITE' => '#fff',
529 - 'BLACK' => '#000',
553 + 'black' => '#000',
554 + 'fuchsia' => '#f0f',
555 + 'magenta' => '#f0f',
556 + 'white' => '#fff',
557 + 'yellow' => '#ff0',
558 + // and also `transparent`
559 + 'transparent' => '#fff0',
530 560 );
531 561
532 562 return preg_replace_callback(
533 563 '/(?<=[: ])(' . implode('|', array_keys($colors)) . ')(?=[; }])/i',
534 564 function ($match) use ($colors) {
535 - return $colors[strtoupper($match[0])];
565 + return $colors[strtolower($match[0])];
536 566 },
537 567 $content
538 568 );
539 569 }
@@ -538,8 +568,73 @@
538 568 );
539 569 }
540 570
541 571 /**
572 + * Convert RGB|HSL color codes.
573 + * rgb(255,0,0,.5) -> rgb(255 0 0 / .5).
574 + * rgb(255,0,0) -> #f00.
575 + *
576 + * @param string $content The CSS content to shorten the RGB color codes for
577 + *
578 + * @return string
579 + */
580 + protected function convertLegacyColors($content)
581 + {
582 + /*
583 + https://drafts.csswg.org/css-color/#color-syntax-legacy
584 + https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb
585 + https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl
586 + */
587 +
588 + // convert legacy color syntax
589 + $content = preg_replace('/(rgb)a?\(\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0,1]?(?:\.[0-9]*)?)\s*\)/i', '$1($2 $3 $4 / $5)', $content);
590 + $content = preg_replace('/(rgb)a?\(\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*,\s*([0-9]{1,3}%?)\s*\)/i', '$1($2 $3 $4)', $content);
591 + $content = preg_replace('/(hsl)a?\(\s*([0-9]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9]{1,3}%)\s*,\s*([0-9]{1,3}%)\s*,\s*([0,1]?(?:\.[0-9]*)?)\s*\)/i', '$1($2 $3 $4 / $5)', $content);
592 + $content = preg_replace('/(hsl)a?\(\s*([0-9]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9]{1,3}%)\s*,\s*([0-9]{1,3}%)\s*\)/i', '$1($2 $3 $4)', $content);
593 +
594 + // convert `rgb` to `hex`
595 + $dec = '([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])';
596 +
597 + return preg_replace_callback(
598 + "/rgb\($dec $dec $dec\)/i",
599 + function ($match) {
600 + return sprintf('#%02x%02x%02x', $match[1], $match[2], $match[3]);
601 + },
602 + $content
603 + );
604 + }
605 +
606 + /**
607 + * Cleanup RGB|HSL|HWB|LCH|LAB
608 + * rgb(255 0 0 / 1) -> rgb(255 0 0).
609 + * rgb(255 0 0 / 0) -> transparent.
610 + *
611 + * @param string $content The CSS content to cleanup HSL|HWB|LCH|LAB
612 + *
613 + * @return string
614 + */
615 + protected function cleanupModernColors($content)
616 + {
617 + /*
618 + https://drafts.csswg.org/css-color/#color-syntax-modern
619 + https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb
620 + https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch
621 + https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab
622 + https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
623 + https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab
624 + */
625 + $tag = '(rgb|hsl|hwb|(?:(?:ok)?(?:lch|lab)))';
626 +
627 + // remove alpha channel if it's pointless ..
628 + $content = preg_replace('/' . $tag . '\(\s*([^\s)]+)\s+([^\s)]+)\s+([^\s)]+)\s+\/\s+1(?:(?:\.\d?)*|00%)?\s*\)/i', '$1($2 $3 $4)', $content);
629 +
630 + // replace `transparent` with shortcut ..
631 + $content = preg_replace('/' . $tag . '\(\s*[^\s)]+\s+[^\s)]+\s+[^\s)]+\s+\/\s+0(?:[\.0%]*)?\s*\)/i', '#fff0', $content);
632 +
633 + return $content;
634 + }
635 +
636 + /**
542 637 * Shorten CSS font weights.
543 638 *
544 639 * @param string $content The CSS content to shorten the font weights for
545 640 *
@@ -640,24 +735,26 @@
640 735 *
641 736 * @param string $content The CSS content to strip the whitespace for
642 737 *
643 738 * @return string
739 + *
740 + * @throws PatternMatchException
644 741 */
645 742 protected function stripWhitespace($content)
646 743 {
647 744 // remove leading & trailing whitespace
648 - $content = preg_replace('/^\s*/m', '', $content);
649 - $content = preg_replace('/\s*$/m', '', $content);
745 + $content = $this->pregReplace('/^\s*/m', '', $content);
746 + $content = $this->pregReplace('/\s*$/m', '', $content);
650 747
651 748 // replace newlines with a single space
652 - $content = preg_replace('/\s+/', ' ', $content);
749 + $content = $this->pregReplace('/\s+/', ' ', $content);
653 750
654 751 // remove whitespace around meta characters
655 752 // inspired by stackoverflow.com/questions/15195750/minify-compress-css-with-regex
656 - $content = preg_replace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
657 - $content = preg_replace('/([\[(:>\+])\s+/', '$1', $content);
658 - $content = preg_replace('/\s+([\]\)>\+])/', '$1', $content);
659 - $content = preg_replace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
753 + $content = $this->pregReplace('/\s*([\*$~^|]?+=|[{};,>~]|!important\b)\s*/', '$1', $content);
754 + $content = $this->pregReplace('/([\[(:>\+])\s+/', '$1', $content);
755 + $content = $this->pregReplace('/\s+([\]\)>\+])/', '$1', $content);
756 + $content = $this->pregReplace('/\s+(:)(?![^\}]*\{)/', '$1', $content);
660 757
661 758 // whitespace around + and - can only be stripped inside some pseudo-
662 759 // classes, like `:nth-child(3+2n)`
663 760 // not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
@@ -662,14 +759,35 @@
662 759 // classes, like `:nth-child(3+2n)`
663 760 // not in things like `calc(3px + 2px)`, shorthands like `3px -2px`, or
664 761 // selectors like `div.weird- p`
665 762 $pseudos = array('nth-child', 'nth-last-child', 'nth-last-of-type', 'nth-of-type');
666 - $content = preg_replace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
763 + $content = $this->pregReplace('/:(' . implode('|', $pseudos) . ')\(\s*([+-]?)\s*(.+?)\s*([+-]?)\s*(.*?)\s*\)/', ':$1($2$3$4$5)', $content);
667 764
668 765 // remove semicolon/whitespace followed by closing bracket
669 766 $content = str_replace(';}', '}', $content);
670 767
671 768 return trim($content);
769 + }
770 +
771 + /**
772 + * Perform a preg_replace and check for errors.
773 + *
774 + * @param string $pattern Pattern
775 + * @param string $replacement Replacement
776 + * @param string $subject String to process
777 + *
778 + * @return string
779 + *
780 + * @throws PatternMatchException
781 + */
782 + protected function pregReplace($pattern, $replacement, $subject)
783 + {
784 + $result = preg_replace($pattern, $replacement, $subject);
785 + if ($result === null) {
786 + throw PatternMatchException::fromLastError("Failed to replace with pattern '$pattern'");
787 + }
788 +
789 + return $result;
672 790 }
673 791
674 792 /**
675 793 * Replace all occurrences of functions that may contain math, where