163 lines
4.6 KiB
PHP
163 lines
4.6 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Style Engine: WP_Style_Engine_Processor class
|
||
|
*
|
||
|
* @package WordPress
|
||
|
* @subpackage StyleEngine
|
||
|
* @since 6.1.0
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Core class used to compile styles from stores or collection of CSS rules.
|
||
|
*
|
||
|
* @since 6.1.0
|
||
|
*/
|
||
|
#[AllowDynamicProperties]
|
||
|
class WP_Style_Engine_Processor {
|
||
|
|
||
|
/**
|
||
|
* A collection of Style Engine Store objects.
|
||
|
*
|
||
|
* @since 6.1.0
|
||
|
* @var WP_Style_Engine_CSS_Rules_Store[]
|
||
|
*/
|
||
|
protected $stores = array();
|
||
|
|
||
|
/**
|
||
|
* The set of CSS rules that this processor will work on.
|
||
|
*
|
||
|
* @since 6.1.0
|
||
|
* @var WP_Style_Engine_CSS_Rule[]
|
||
|
*/
|
||
|
protected $css_rules = array();
|
||
|
|
||
|
/**
|
||
|
* Adds a store to the processor.
|
||
|
*
|
||
|
* @since 6.1.0
|
||
|
*
|
||
|
* @param WP_Style_Engine_CSS_Rules_Store $store The store to add.
|
||
|
* @return WP_Style_Engine_Processor Returns the object to allow chaining methods.
|
||
|
*/
|
||
|
public function add_store( $store ) {
|
||
|
if ( ! $store instanceof WP_Style_Engine_CSS_Rules_Store ) {
|
||
|
_doing_it_wrong(
|
||
|
__METHOD__,
|
||
|
__( '$store must be an instance of WP_Style_Engine_CSS_Rules_Store' ),
|
||
|
'6.1.0'
|
||
|
);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
$this->stores[ $store->get_name() ] = $store;
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds rules to be processed.
|
||
|
*
|
||
|
* @since 6.1.0
|
||
|
*
|
||
|
* @param WP_Style_Engine_CSS_Rule|WP_Style_Engine_CSS_Rule[] $css_rules A single, or an array of,
|
||
|
* WP_Style_Engine_CSS_Rule objects
|
||
|
* from a store or otherwise.
|
||
|
* @return WP_Style_Engine_Processor Returns the object to allow chaining methods.
|
||
|
*/
|
||
|
public function add_rules( $css_rules ) {
|
||
|
if ( ! is_array( $css_rules ) ) {
|
||
|
$css_rules = array( $css_rules );
|
||
|
}
|
||
|
|
||
|
foreach ( $css_rules as $rule ) {
|
||
|
$selector = $rule->get_selector();
|
||
|
if ( isset( $this->css_rules[ $selector ] ) ) {
|
||
|
$this->css_rules[ $selector ]->add_declarations( $rule->get_declarations() );
|
||
|
continue;
|
||
|
}
|
||
|
$this->css_rules[ $rule->get_selector() ] = $rule;
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the CSS rules as a string.
|
||
|
*
|
||
|
* @since 6.1.0
|
||
|
* @since 6.4.0 The Optimization is no longer the default.
|
||
|
*
|
||
|
* @param array $options {
|
||
|
* Optional. An array of options. Default empty array.
|
||
|
*
|
||
|
* @type bool $optimize Whether to optimize the CSS output, e.g. combine rules.
|
||
|
* Default false.
|
||
|
* @type bool $prettify Whether to add new lines and indents to output.
|
||
|
* Defaults to whether the `SCRIPT_DEBUG` constant is defined.
|
||
|
* }
|
||
|
* @return string The computed CSS.
|
||
|
*/
|
||
|
public function get_css( $options = array() ) {
|
||
|
$defaults = array(
|
||
|
'optimize' => false,
|
||
|
'prettify' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
|
||
|
);
|
||
|
$options = wp_parse_args( $options, $defaults );
|
||
|
|
||
|
// If we have stores, get the rules from them.
|
||
|
foreach ( $this->stores as $store ) {
|
||
|
$this->add_rules( $store->get_all_rules() );
|
||
|
}
|
||
|
|
||
|
// Combine CSS selectors that have identical declarations.
|
||
|
if ( true === $options['optimize'] ) {
|
||
|
$this->combine_rules_selectors();
|
||
|
}
|
||
|
|
||
|
// Build the CSS.
|
||
|
$css = '';
|
||
|
foreach ( $this->css_rules as $rule ) {
|
||
|
$css .= $rule->get_css( $options['prettify'] );
|
||
|
$css .= $options['prettify'] ? "\n" : '';
|
||
|
}
|
||
|
return $css;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Combines selectors from the rules store when they have the same styles.
|
||
|
*
|
||
|
* @since 6.1.0
|
||
|
*/
|
||
|
private function combine_rules_selectors() {
|
||
|
// Build an array of selectors along with the JSON-ified styles to make comparisons easier.
|
||
|
$selectors_json = array();
|
||
|
foreach ( $this->css_rules as $rule ) {
|
||
|
$declarations = $rule->get_declarations()->get_declarations();
|
||
|
ksort( $declarations );
|
||
|
$selectors_json[ $rule->get_selector() ] = wp_json_encode( $declarations );
|
||
|
}
|
||
|
|
||
|
// Combine selectors that have the same styles.
|
||
|
foreach ( $selectors_json as $selector => $json ) {
|
||
|
// Get selectors that use the same styles.
|
||
|
$duplicates = array_keys( $selectors_json, $json, true );
|
||
|
// Skip if there are no duplicates.
|
||
|
if ( 1 >= count( $duplicates ) ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$declarations = $this->css_rules[ $selector ]->get_declarations();
|
||
|
|
||
|
foreach ( $duplicates as $key ) {
|
||
|
// Unset the duplicates from the $selectors_json array to avoid looping through them as well.
|
||
|
unset( $selectors_json[ $key ] );
|
||
|
// Remove the rules from the rules collection.
|
||
|
unset( $this->css_rules[ $key ] );
|
||
|
}
|
||
|
// Create a new rule with the combined selectors.
|
||
|
$duplicate_selectors = implode( ',', $duplicates );
|
||
|
$this->css_rules[ $duplicate_selectors ] = new WP_Style_Engine_CSS_Rule( $duplicate_selectors, $declarations );
|
||
|
}
|
||
|
}
|
||
|
}
|