PluginProbe
Elementor Website Builder – more than just a page builder / 3.31.4
Elementor Website Builder – more than just a page builder v3.31.4
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / atomic-widgets / styles / atomic-styles-manager.php

atomic-styles-manager.php in Elementor Website Builder – more than just a page builder 3.31.4, at modules/atomic-widgets/styles/atomic-styles-manager.php

225 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\AtomicWidgets\Styles;
4
5 use Elementor\Core\Base\Document;
6 use Elementor\Core\Breakpoints\Breakpoint;
7 use Elementor\Core\Utils\Collection;
8 use Elementor\Modules\AtomicWidgets\Memo;
9 use Elementor\Modules\AtomicWidgets\Cache_Validity;
10 use Elementor\Plugin;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit; // Exit if accessed directly.
14 }
15
16 class Atomic_Styles_Manager {
17 private static ?self $instance = null;
18
19 /**
20 * @var array<string, array{styles: callable, cache_keys: array<string>}>
21 */
22 private array $registered_styles_by_key = [];
23
24 private Cache_Validity $cache_validity;
25
26 private array $post_ids = [];
27
28 private CSS_Files_Manager $css_files_manager;
29
30 const DEFAULT_BREAKPOINT = 'desktop';
31
32 private array $fonts = [];
33
34 public function __construct() {
35 $this->css_files_manager = new CSS_Files_Manager();
36 $this->cache_validity = new Cache_Validity();
37 }
38
39 public static function instance() {
40 if ( ! self::$instance ) {
41 self::$instance = new self();
42 }
43
44 return self::$instance;
45 }
46
47 public function register_hooks() {
48 add_action( 'elementor/frontend/after_enqueue_post_styles', fn() => $this->enqueue_styles() );
49 add_action( 'elementor/post/render', function( $post_id ) {
50 $this->post_ids[] = $post_id;
51 } );
52 }
53
54 public function register( string $key, callable $get_style_defs, array $cache_keys ) {
55 $this->registered_styles_by_key[ $key ] = [
56 'get_styles' => $get_style_defs,
57 'cache_keys' => $cache_keys,
58 ];
59 }
60
61 private function enqueue_styles() {
62 if ( empty( $this->post_ids ) ) {
63 return;
64 }
65
66 do_action( 'elementor/atomic-widgets/styles/register', $this, $this->post_ids );
67
68 $get_styles_memo = new Memo();
69
70 $styles_by_key = Collection::make( $this->registered_styles_by_key )
71 ->map_with_keys( fn ( $style_params, $style_key ) => [
72 $style_key => [
73 'get_styles' => $get_styles_memo->memoize( $style_key, $style_params['get_styles'] ),
74 'cache_keys' => $style_params['cache_keys'],
75 ],
76 ])
77 ->all();
78
79 $this->before_render( $styles_by_key );
80
81 $this->render( $styles_by_key );
82
83 $this->after_render( $styles_by_key );
84 }
85
86 private function before_render( array $styles_by_key ) {
87 $this->fonts = [];
88
89 foreach ( $styles_by_key as $style_key => $style_params ) {
90 $cache_keys = $style_params['cache_keys'];
91
92 // This cache validity check is of the general style, and used to reset dependencies that can only be evaluated
93 // upon the style rendering flow (i.e. when cache is invalid).
94 // (the corresponding css files cache validity includes also the file's breakpoint in the cache keys array)
95 if ( ! $this->cache_validity->is_valid( $cache_keys ) ) {
96 Style_Fonts::make( $style_key )->clear();
97 }
98
99 // We should validate it after this iteration
100 $this->cache_validity->validate( $cache_keys );
101 }
102 }
103
104 private function render( array $styles_by_key ) {
105 $group_by_breakpoint_memo = new Memo();
106 $breakpoints = $this->get_breakpoints();
107
108 foreach ( $breakpoints as $breakpoint_key ) {
109 foreach ( $styles_by_key as $style_key => $style_params ) {
110 $cache_keys = $style_params['cache_keys'];
111 $render_css = fn() => $this->render_css_by_breakpoints( $style_params['get_styles'], $style_key, $breakpoint_key, $group_by_breakpoint_memo );
112
113 $breakpoint_media = $this->get_breakpoint_media( $breakpoint_key );
114
115 if ( ! $breakpoint_media ) {
116 continue;
117 }
118
119 $breakpoint_cache_keys = array_merge( $cache_keys, [ $breakpoint_key ] );
120
121 $style_file = $this->css_files_manager->get(
122 $style_key . '-' . $breakpoint_key,
123 $breakpoint_media,
124 $render_css,
125 $this->cache_validity->is_valid( $breakpoint_cache_keys )
126 );
127
128 $this->cache_validity->validate( $breakpoint_cache_keys );
129
130 if ( ! $style_file ) {
131 continue;
132 }
133
134 wp_enqueue_style(
135 $style_file->get_handle(),
136 $style_file->get_url(),
137 [],
138 $style_file->get_media()
139 );
140 }
141 }
142 }
143
144 private function render_css( array $styles, string $style_key ) {
145 $style_fonts = Style_Fonts::make( $style_key );
146
147 return Styles_Renderer::make(
148 Plugin::$instance->breakpoints->get_breakpoints_config()
149 )->on_prop_transform( function( $key, $value ) use ( $style_fonts ) {
150 if ( 'font-family' !== $key ) {
151 return;
152 }
153
154 $style_fonts->add( $value );
155 } )->render( $styles );
156 }
157
158 private function get_breakpoint_media( string $breakpoint_key ): ?string {
159 $breakpoint_config = Plugin::$instance->breakpoints->get_breakpoints_config()[ $breakpoint_key ] ?? null;
160
161 return $breakpoint_config ? Styles_Renderer::get_media_query( $breakpoint_config ) : 'all';
162 }
163
164 private function render_css_by_breakpoints( callable $get_styles, string $style_key, string $breakpoint_key, Memo $group_by_breakpoint_memo ) {
165 $memo_key = $style_key . '-' . $breakpoint_key;
166 $get_grouped_styles = $group_by_breakpoint_memo->memoize( $memo_key, fn() => $this->group_by_breakpoint( $get_styles() ) );
167 $grouped_styles = $get_grouped_styles();
168
169 return $this->render_css( $grouped_styles[ $breakpoint_key ] ?? [], $style_key );
170 }
171
172 private function group_by_breakpoint( $styles ) {
173 return Collection::make( $styles )->reduce( function( $group, $style ) {
174 Collection::make( $style['variants'] )->each( function( $variant ) use ( &$group, $style ) {
175 $breakpoint = $variant['meta']['breakpoint'] ?? self::DEFAULT_BREAKPOINT;
176
177 if ( ! isset( $group[ $breakpoint ][ $style['id'] ] ) ) {
178 $group[ $breakpoint ][ $style['id'] ] = [
179 'id' => $style['id'],
180 'type' => $style['type'],
181 'variants' => [],
182 ];
183 }
184
185 $group[ $breakpoint ][ $style['id'] ]['variants'][] = $variant;
186 } );
187
188 return $group;
189 }, [] );
190 }
191
192 private function get_breakpoints() {
193 return Collection::make( Plugin::$instance->breakpoints->get_breakpoints() )
194 ->map( fn( Breakpoint $breakpoint ) => $breakpoint->get_name() )
195 ->reverse()
196 ->prepend( self::DEFAULT_BREAKPOINT )
197 ->all();
198 }
199
200 private function after_render( array $styles_by_key ) {
201 foreach ( $styles_by_key as $style_key => $style_params ) {
202 $this->add_fonts_to_enqueue( $style_key );
203 }
204
205 $this->enqueue_fonts();
206 }
207
208 private function add_fonts_to_enqueue( string $style_key ) {
209 $style_fonts = Style_Fonts::make( $style_key );
210
211 $this->fonts = array_unique(
212 array_merge(
213 $this->fonts,
214 array_values( $style_fonts->get() )
215 )
216 );
217 }
218
219 private function enqueue_fonts() {
220 foreach ( $this->fonts as $font ) {
221 Plugin::instance()->frontend->enqueue_font( $font );
222 }
223 }
224 }
225