wp/wp-includes/style-engine/class-wp-style-engine-processor.php
changeset 21 48c4eec2b7e6
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
       
     1 <?php
       
     2 /**
       
     3  * Style Engine: WP_Style_Engine_Processor class
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage StyleEngine
       
     7  * @since 6.1.0
       
     8  */
       
     9 
       
    10 /**
       
    11  * Core class used to compile styles from stores or collection of CSS rules.
       
    12  *
       
    13  * @since 6.1.0
       
    14  */
       
    15 #[AllowDynamicProperties]
       
    16 class WP_Style_Engine_Processor {
       
    17 
       
    18 	/**
       
    19 	 * A collection of Style Engine Store objects.
       
    20 	 *
       
    21 	 * @since 6.1.0
       
    22 	 * @var WP_Style_Engine_CSS_Rules_Store[]
       
    23 	 */
       
    24 	protected $stores = array();
       
    25 
       
    26 	/**
       
    27 	 * The set of CSS rules that this processor will work on.
       
    28 	 *
       
    29 	 * @since 6.1.0
       
    30 	 * @var WP_Style_Engine_CSS_Rule[]
       
    31 	 */
       
    32 	protected $css_rules = array();
       
    33 
       
    34 	/**
       
    35 	 * Adds a store to the processor.
       
    36 	 *
       
    37 	 * @since 6.1.0
       
    38 	 *
       
    39 	 * @param WP_Style_Engine_CSS_Rules_Store $store The store to add.
       
    40 	 * @return WP_Style_Engine_Processor Returns the object to allow chaining methods.
       
    41 	 */
       
    42 	public function add_store( $store ) {
       
    43 		if ( ! $store instanceof WP_Style_Engine_CSS_Rules_Store ) {
       
    44 			_doing_it_wrong(
       
    45 				__METHOD__,
       
    46 				__( '$store must be an instance of WP_Style_Engine_CSS_Rules_Store' ),
       
    47 				'6.1.0'
       
    48 			);
       
    49 			return $this;
       
    50 		}
       
    51 
       
    52 		$this->stores[ $store->get_name() ] = $store;
       
    53 
       
    54 		return $this;
       
    55 	}
       
    56 
       
    57 	/**
       
    58 	 * Adds rules to be processed.
       
    59 	 *
       
    60 	 * @since 6.1.0
       
    61 	 * @since 6.6.0 Added support for rules_group.
       
    62 	 *
       
    63 	 * @param WP_Style_Engine_CSS_Rule|WP_Style_Engine_CSS_Rule[] $css_rules A single, or an array of,
       
    64 	 *                                                                       WP_Style_Engine_CSS_Rule objects
       
    65 	 *                                                                       from a store or otherwise.
       
    66 	 * @return WP_Style_Engine_Processor Returns the object to allow chaining methods.
       
    67 	 */
       
    68 	public function add_rules( $css_rules ) {
       
    69 		if ( ! is_array( $css_rules ) ) {
       
    70 			$css_rules = array( $css_rules );
       
    71 		}
       
    72 
       
    73 		foreach ( $css_rules as $rule ) {
       
    74 			$selector    = $rule->get_selector();
       
    75 			$rules_group = $rule->get_rules_group();
       
    76 
       
    77 			/**
       
    78 			 * If there is a rules_group and it already exists in the css_rules array,
       
    79 			 * add the rule to it.
       
    80 			 * Otherwise, create a new entry for the rules_group.
       
    81 			 */
       
    82 			if ( ! empty( $rules_group ) ) {
       
    83 				if ( isset( $this->css_rules[ "$rules_group $selector" ] ) ) {
       
    84 					$this->css_rules[ "$rules_group $selector" ]->add_declarations( $rule->get_declarations() );
       
    85 					continue;
       
    86 				}
       
    87 				$this->css_rules[ "$rules_group $selector" ] = $rule;
       
    88 				continue;
       
    89 			}
       
    90 
       
    91 			// If the selector already exists, add the declarations to it.
       
    92 			if ( isset( $this->css_rules[ $selector ] ) ) {
       
    93 				$this->css_rules[ $selector ]->add_declarations( $rule->get_declarations() );
       
    94 				continue;
       
    95 			}
       
    96 			$this->css_rules[ $rule->get_selector() ] = $rule;
       
    97 		}
       
    98 
       
    99 		return $this;
       
   100 	}
       
   101 
       
   102 	/**
       
   103 	 * Gets the CSS rules as a string.
       
   104 	 *
       
   105 	 * @since 6.1.0
       
   106 	 * @since 6.4.0 The Optimization is no longer the default.
       
   107 	 *
       
   108 	 * @param array $options   {
       
   109 	 *     Optional. An array of options. Default empty array.
       
   110 	 *
       
   111 	 *     @type bool $optimize Whether to optimize the CSS output, e.g. combine rules.
       
   112 	 *                          Default false.
       
   113 	 *     @type bool $prettify Whether to add new lines and indents to output.
       
   114 	 *                          Defaults to whether the `SCRIPT_DEBUG` constant is defined.
       
   115 	 * }
       
   116 	 * @return string The computed CSS.
       
   117 	 */
       
   118 	public function get_css( $options = array() ) {
       
   119 		$defaults = array(
       
   120 			'optimize' => false,
       
   121 			'prettify' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
       
   122 		);
       
   123 		$options  = wp_parse_args( $options, $defaults );
       
   124 
       
   125 		// If we have stores, get the rules from them.
       
   126 		foreach ( $this->stores as $store ) {
       
   127 			$this->add_rules( $store->get_all_rules() );
       
   128 		}
       
   129 
       
   130 		// Combine CSS selectors that have identical declarations.
       
   131 		if ( true === $options['optimize'] ) {
       
   132 			$this->combine_rules_selectors();
       
   133 		}
       
   134 
       
   135 		// Build the CSS.
       
   136 		$css = '';
       
   137 		foreach ( $this->css_rules as $rule ) {
       
   138 			// See class WP_Style_Engine_CSS_Rule for the get_css method.
       
   139 			$css .= $rule->get_css( $options['prettify'] );
       
   140 			$css .= $options['prettify'] ? "\n" : '';
       
   141 		}
       
   142 		return $css;
       
   143 	}
       
   144 
       
   145 	/**
       
   146 	 * Combines selectors from the rules store when they have the same styles.
       
   147 	 *
       
   148 	 * @since 6.1.0
       
   149 	 */
       
   150 	private function combine_rules_selectors() {
       
   151 		// Build an array of selectors along with the JSON-ified styles to make comparisons easier.
       
   152 		$selectors_json = array();
       
   153 		foreach ( $this->css_rules as $rule ) {
       
   154 			$declarations = $rule->get_declarations()->get_declarations();
       
   155 			ksort( $declarations );
       
   156 			$selectors_json[ $rule->get_selector() ] = wp_json_encode( $declarations );
       
   157 		}
       
   158 
       
   159 		// Combine selectors that have the same styles.
       
   160 		foreach ( $selectors_json as $selector => $json ) {
       
   161 			// Get selectors that use the same styles.
       
   162 			$duplicates = array_keys( $selectors_json, $json, true );
       
   163 			// Skip if there are no duplicates.
       
   164 			if ( 1 >= count( $duplicates ) ) {
       
   165 				continue;
       
   166 			}
       
   167 
       
   168 			$declarations = $this->css_rules[ $selector ]->get_declarations();
       
   169 
       
   170 			foreach ( $duplicates as $key ) {
       
   171 				// Unset the duplicates from the $selectors_json array to avoid looping through them as well.
       
   172 				unset( $selectors_json[ $key ] );
       
   173 				// Remove the rules from the rules collection.
       
   174 				unset( $this->css_rules[ $key ] );
       
   175 			}
       
   176 			// Create a new rule with the combined selectors.
       
   177 			$duplicate_selectors                     = implode( ',', $duplicates );
       
   178 			$this->css_rules[ $duplicate_selectors ] = new WP_Style_Engine_CSS_Rule( $duplicate_selectors, $declarations );
       
   179 		}
       
   180 	}
       
   181 }