Automattic\WooCommerce\Vendor\Pelago\Emogrifier

CssInliner::collateCssRulesprivateWC 1.0

Collates the individual rules from a CssDocument object.

Method of the class: CssInliner{}

No Hooks.

Returns

Array. array<array-key, array{ media: string, selector: string, hasUnmatchablePseudo: bool, declarationsBlock: string, line: int }>> This 2-entry array has the key "inlinable" containing rules which can be inlined as style attributes and the key "uninlinable" containing rules which cannot. Each value is an array of sub-arrays with the following keys:

  • "media" (the media query string, e.g. "@media screen and (max-width: 480px)", or an empty string if not from a @media rule);
  • "selector" (the CSS selector, e.g., "*" or "header h1");
  • "hasUnmatchablePseudo" (true if that selector contains pseudo-elements or dynamic pseudo-classes such that the declarations cannot be applied inline);
  • "declarationsBlock" (the semicolon-separated CSS declarations for that selector, e.g., color: red; height: 4px;);
  • "line" (the line number, e.g. 42).

Usage

// private - for code of main (parent) class only
$result = $this->collateCssRules( $parsedCss ): array;
$parsedCss(CssDocument) (required)
.

CssInliner::collateCssRules() code WC 10.4.3

private function collateCssRules(CssDocument $parsedCss): array
{
    $matches = $parsedCss->getStyleRulesData(\array_keys($this->allowedMediaTypes));

    $preg = (new Preg())->throwExceptions($this->debug);
    $cssRules = [
        'inlinable' => [],
        'uninlinable' => [],
    ];
    foreach ($matches as $key => $cssRule) {
        if (!$cssRule->hasAtLeastOneDeclaration()) {
            continue;
        }

        $mediaQuery = $cssRule->getContainingAtRule();
        $declarationsBlock = $cssRule->getDeclarationAsText();
        $selectors = $cssRule->getSelectors();

        // Maybe exclude CSS selectors
        if (\count($this->excludedCssSelectors) > 0) {
            // Normalize spaces, line breaks & tabs
            $selectorsNormalized = \array_map(static function (string $selector) use ($preg): string {
                return $preg->replace('@\\s++@u', ' ', $selector);
            }, $selectors);

            $selectors = \array_filter($selectorsNormalized, function (string $selector): bool {
                return !isset($this->excludedCssSelectors[$selector]);
            });
        }

        foreach ($selectors as $selector) {
            // don't process pseudo-elements and behavioral (dynamic) pseudo-classes;
            // only allow structural pseudo-classes
            $hasPseudoElement = \strpos($selector, '::') !== false;
            $hasUnmatchablePseudo = $hasPseudoElement || $this->hasUnsupportedPseudoClass($selector);

            $parsedCssRule = [
                'media' => $mediaQuery,
                'selector' => $selector,
                'hasUnmatchablePseudo' => $hasUnmatchablePseudo,
                'declarationsBlock' => $declarationsBlock,
                // keep track of where it appears in the file, since order is important
                'line' => $key,
            ];
            $ruleType = (!$cssRule->hasContainingAtRule() && !$hasUnmatchablePseudo) ? 'inlinable' : 'uninlinable';
            $cssRules[$ruleType][] = $parsedCssRule;
        }
    }

    \usort(
        $cssRules['inlinable'],
        /**
         * @param array{selector: string, line: int, ...} $first
         * @param array{selector: string, line: int, ...} $second
         */
        function (array $first, array $second): int {
            return $this->sortBySelectorPrecedence($first, $second);
        }
    );

    return $cssRules;
}