PluginProbe
Gutenify – Visual Site Builder Blocks & Starter Templates / 1.7.0
Gutenify – Visual Site Builder Blocks & Starter Templates v1.7.0
1.9.0 1.8.0 1.7.0 1.6.6 1.6.5 1.6.4 trunk 0.0.1 0.0.2 0.0.3 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 74 releases
gutenify / core / inc / blocks / class-dynamic-block-classname.php

class-dynamic-block-classname.php in Gutenify – Visual Site Builder Blocks & Starter Templates 1.7.0, at core/inc/blocks/class-dynamic-block-classname.php

465 lines 17.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Dynamic Block Classname Handler
4 *
5 * This file contains the `Dynamic_Block_Classname` class, which allows the dynamic addition
6 * of CSS classnames or inline styles to Gutenberg blocks during rendering.
7 *
8 * @package gutenify
9 * @subpackage Functions
10 * @since 1.0.0
11 */
12
13 namespace gutenify;
14
15 defined( 'ABSPATH' ) || exit; // Prevent direct access to the file.
16
17 /**
18 * Class Dynamic_Block_Classname.
19 *
20 * Handles dynamic addition of CSS classnames to Gutenberg blocks.
21 */
22 class Dynamic_Block_Classname {
23
24 /**
25 * Initializes the class by hooking into 'render_block'.
26 */
27 public static function init() {
28 add_filter( 'render_block', array( __CLASS__, 'render_block' ), 10, 3 );
29 }
30
31 /**
32 * Hook callback for modifying block output during rendering.
33 *
34 * @param string $block_content The original block HTML.
35 * @param array $block The block settings.
36 * @param object $instance The block instance (for reusable blocks).
37 * @return string Modified block HTML after applying custom filters.
38 */
39 public static function render_block( $block_content, $block, $instance ) {
40 // Skip processing for empty blocks or specific block types.
41 if ( empty( $block['blockName'] ) || in_array( $block['blockName'], array( 'structured-content/faq-item', 'structured-content/faq' ), true ) ) {
42 return $block_content;
43 }
44
45 // Generate a unique CSS class ID for this block.
46 $block_id = wp_unique_id( 'gtfy-' );
47
48 $html_processor = new \WP_HTML_Tag_Processor( $block_content );
49 if ( $html_processor->next_tag() ) {
50 $html_processor->add_class( $block_id );
51 }
52
53 // Enqueue dynamic styles if the block is valid.
54 if ( is_array( $block ) && ! empty( $block ) ) {
55 self::enqueue_dyanmic_style( $block, $block_id, $instance );
56 }
57
58 // Get the updated HTML content.
59 $updated_html = $html_processor->get_updated_html();
60
61 // Apply general and block-specific filters before returning.
62 $filter_prefix = 'gutenify_render_block';
63 $updated_html = apply_filters( $filter_prefix, $updated_html, $block, $instance, $block_id );
64 return apply_filters( $filter_prefix . '_' . $block['blockName'], $updated_html, $block, $instance, $block_id );
65 }
66
67 /**
68 * Enqueues dynamic styles for the block.
69 *
70 * @param array $block The block settings.
71 * @param string $block_id Unique ID for the block instance.
72 * @param object $instance The block instance.
73 */
74 public static function enqueue_dyanmic_style( $block, $block_id, $instance ) {
75 if ( empty( $block['blockName'] ) ) {
76 return false; // Exit early if the block has no name.
77 }
78
79 // Create a unique style handle based on the block name and block ID.
80 $handle = 'gutenify_' . str_replace( '/', '_', $block['blockName'] ) . '_' . $block_id;
81
82 // Register and enqueue an empty stylesheet for attaching inline styles.
83 wp_register_style( $handle, false );
84 wp_enqueue_style( $handle );
85
86 // Initialize CSS variable.
87 $css = '';
88
89 if ( ! in_array( $block['blockName'], array( 'gutenify/button' ), true ) ) {
90 $css = self::spacing_style( $block, $block_id, $instance );
91 }
92
93 $css .= self::position_style( $block, $block_id, $instance );
94 $css .= self::transform_style( $block, $block_id, $instance );
95 $css .= self::effects_style( $block, $block_id, $instance );
96 $css .= self::colors_style( $block, $block_id, $instance );
97 $css .= self::transition_style( $block, $block_id, $instance );
98 $css .= self::box_shadow_style( $block, $block_id, $instance );
99 $css .= self::layout_style( $block, $block_id, $instance );
100 $css .= self::container_layout_style( $block, $block_id, $instance );
101
102 // Add the generated inline styles to the registered handle.
103 wp_add_inline_style( $handle, $css );
104 }
105
106 /**
107 * Generates dynamic spacing styles for the block.
108 *
109 * @param array $block The block settings.
110 * @param string $block_id Unique ID for the block instance.
111 * @param object $instance The block instance.
112 * @return string CSS styles.
113 */
114 public static function spacing_style( $block, $block_id, $instance ) {
115 // Initialize the CSS output variable.
116 $css = '';
117
118 // Get default margin from instance attributes.
119 $margin = ! empty( $instance->attributes['blockAdvanceOptions']['margin'] ) ? $instance->attributes['blockAdvanceOptions']['margin'] : array();
120
121 // Merge with block-level margin if provided.
122 if ( ! empty( $block['attrs']['blockAdvanceOptions']['margin'] ) ) {
123 $margin = wp_parse_args( $block['attrs']['blockAdvanceOptions']['margin'], $margin );
124 }
125
126 // Generate margin CSS.
127 $css .= Dynamic_Styles::get_spacing_with_media( '.' . $block_id, $margin, 'margin-' );
128
129 // Get default padding from instance attributes.
130 $padding = ! empty( $instance->attributes['blockAdvanceOptions']['padding'] ) ? $instance->attributes['blockAdvanceOptions']['padding'] : array();
131
132 // Merge with block-level padding if provided.
133 if ( ! empty( $block['attrs']['blockAdvanceOptions']['padding'] ) ) {
134 $padding = wp_parse_args( $block['attrs']['blockAdvanceOptions']['padding'], $padding );
135 }
136
137 // Generate padding CSS.
138 $css .= Dynamic_Styles::get_spacing_with_media( '.' . $block_id, $padding, 'padding-' );
139
140 // Return the combined spacing styles.
141 return $css;
142 }
143
144 /**
145 * Generates dynamic position styles (position, offsets, z-index, width,
146 * height, overflow) for the block, including any block-level custom
147 * breakpoints (e.g. AdvancedGroup's `customBlockBreakpoints` attribute).
148 *
149 * @param array $block The block settings.
150 * @param string $block_id Unique ID for the block instance.
151 * @param object $instance The block instance.
152 * @return string CSS styles.
153 */
154 public static function position_style( $block, $block_id, $instance ) {
155 $position = ! empty( $instance->attributes['advancedStyling']['position']['normal'] ) ? $instance->attributes['advancedStyling']['position']['normal'] : array();
156
157 if ( ! empty( $block['attrs']['advancedStyling']['position']['normal'] ) ) {
158 $position = wp_parse_args( $block['attrs']['advancedStyling']['position']['normal'], $position );
159 }
160
161 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
162 ? $block['attrs']['customBlockBreakpoints']
163 : array();
164
165 $css = '';
166
167 if ( ! empty( $position ) ) {
168 $css .= Dynamic_Styles::get_position_with_media( '.' . $block_id, $position, $custom_breakpoints );
169 }
170
171 // Hover/Active/Focus-within variants — evaluated independently of the
172 // Normal bucket above, since a block can have a state-only effect
173 // (e.g. "scale up on hover") with no base position/transform at all.
174 $css .= Dynamic_Styles::get_state_variants_css(
175 '.' . $block_id,
176 $block['attrs'] ?? array(),
177 $instance->attributes,
178 'position',
179 $custom_breakpoints,
180 function ( $sel, $bucket, $cbp ) {
181 return Dynamic_Styles::get_position_with_media( $sel, $bucket, $cbp );
182 }
183 );
184
185 return $css;
186 }
187
188 /**
189 * Generates dynamic transform styles (transform, transform-origin) for
190 * the block, including any block-level custom breakpoints.
191 *
192 * @param array $block The block settings.
193 * @param string $block_id Unique ID for the block instance.
194 * @param object $instance The block instance.
195 * @return string CSS styles.
196 */
197 public static function transform_style( $block, $block_id, $instance ) {
198 $transform = ! empty( $instance->attributes['advancedStyling']['transform']['normal'] ) ? $instance->attributes['advancedStyling']['transform']['normal'] : array();
199
200 if ( ! empty( $block['attrs']['advancedStyling']['transform']['normal'] ) ) {
201 $transform = wp_parse_args( $block['attrs']['advancedStyling']['transform']['normal'], $transform );
202 }
203
204 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
205 ? $block['attrs']['customBlockBreakpoints']
206 : array();
207
208 $css = '';
209
210 if ( ! empty( $transform ) ) {
211 $css .= Dynamic_Styles::get_transform_with_media( '.' . $block_id, $transform, $custom_breakpoints );
212 }
213
214 // Hover/Active/Focus-within variants — see position_style() above for
215 // why this runs regardless of whether the Normal bucket was empty.
216 $css .= Dynamic_Styles::get_state_variants_css(
217 '.' . $block_id,
218 $block['attrs'] ?? array(),
219 $instance->attributes,
220 'transform',
221 $custom_breakpoints,
222 function ( $sel, $bucket, $cbp ) {
223 return Dynamic_Styles::get_transform_with_media( $sel, $bucket, $cbp );
224 }
225 );
226
227 return $css;
228 }
229
230 /**
231 * Generates dynamic effects styles (opacity, filter, backdrop-filter) for
232 * the block, including any block-level custom breakpoints.
233 *
234 * @param array $block The block settings.
235 * @param string $block_id Unique ID for the block instance.
236 * @param object $instance The block instance.
237 * @return string CSS styles.
238 */
239 public static function effects_style( $block, $block_id, $instance ) {
240 $effects = ! empty( $instance->attributes['advancedStyling']['effects']['normal'] ) ? $instance->attributes['advancedStyling']['effects']['normal'] : array();
241
242 if ( ! empty( $block['attrs']['advancedStyling']['effects']['normal'] ) ) {
243 $effects = wp_parse_args( $block['attrs']['advancedStyling']['effects']['normal'], $effects );
244 }
245
246 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
247 ? $block['attrs']['customBlockBreakpoints']
248 : array();
249
250 $css = '';
251
252 if ( ! empty( $effects ) ) {
253 $css .= Dynamic_Styles::get_effects_with_media( '.' . $block_id, $effects, $custom_breakpoints );
254 }
255
256 // Hover/Active/Focus-within variants — see position_style() above for
257 // why this runs regardless of whether the Normal bucket was empty.
258 $css .= Dynamic_Styles::get_state_variants_css(
259 '.' . $block_id,
260 $block['attrs'] ?? array(),
261 $instance->attributes,
262 'effects',
263 $custom_breakpoints,
264 function ( $sel, $bucket, $cbp ) {
265 return Dynamic_Styles::get_effects_with_media( $sel, $bucket, $cbp );
266 }
267 );
268
269 return $css;
270 }
271
272 /**
273 * Generates dynamic color styles (background-color, color) for the
274 * block, including any block-level custom breakpoints.
275 *
276 * @param array $block The block settings.
277 * @param string $block_id Unique ID for the block instance.
278 * @param object $instance The block instance.
279 * @return string CSS styles.
280 */
281 public static function colors_style( $block, $block_id, $instance ) {
282 $colors = ! empty( $instance->attributes['advancedStyling']['colors']['normal'] ) ? $instance->attributes['advancedStyling']['colors']['normal'] : array();
283
284 if ( ! empty( $block['attrs']['advancedStyling']['colors']['normal'] ) ) {
285 $colors = wp_parse_args( $block['attrs']['advancedStyling']['colors']['normal'], $colors );
286 }
287
288 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
289 ? $block['attrs']['customBlockBreakpoints']
290 : array();
291
292 $css = '';
293
294 if ( ! empty( $colors ) ) {
295 $css .= Dynamic_Styles::get_colors_with_media( '.' . $block_id, $colors, $custom_breakpoints );
296 }
297
298 // Hover/Active/Focus-within variants — see position_style() above for
299 // why this runs regardless of whether the Normal bucket was empty.
300 $css .= Dynamic_Styles::get_state_variants_css(
301 '.' . $block_id,
302 $block['attrs'] ?? array(),
303 $instance->attributes,
304 'colors',
305 $custom_breakpoints,
306 function ( $sel, $bucket, $cbp ) {
307 return Dynamic_Styles::get_colors_with_media( $sel, $bucket, $cbp );
308 }
309 );
310
311 return $css;
312 }
313
314 /**
315 * Generates dynamic `transition-duration`/`transition-timing-function`/
316 * `transition-delay` CSS for the block, including any block-level custom
317 * breakpoints. Normal-only — unlike position/transform/effects/colors,
318 * this deliberately does NOT call get_state_variants_css(): `transition`
319 * must live on the resting selector to animate a state change in both
320 * directions (entering AND leaving :hover/:active/:focus-within), so it
321 * has no Hover/Active/Focus bucket of its own to read.
322 *
323 * @param array $block The block settings.
324 * @param string $block_id Unique ID for the block instance.
325 * @param object $instance The block instance.
326 * @return string CSS styles.
327 */
328 public static function transition_style( $block, $block_id, $instance ) {
329 $transition = ! empty( $instance->attributes['advancedStyling']['transition']['normal'] ) ? $instance->attributes['advancedStyling']['transition']['normal'] : array();
330
331 if ( ! empty( $block['attrs']['advancedStyling']['transition']['normal'] ) ) {
332 $transition = wp_parse_args( $block['attrs']['advancedStyling']['transition']['normal'], $transition );
333 }
334
335 if ( empty( $transition ) ) {
336 return '';
337 }
338
339 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
340 ? $block['attrs']['customBlockBreakpoints']
341 : array();
342
343 return Dynamic_Styles::get_transition_with_media( '.' . $block_id, $transition, $custom_breakpoints );
344 }
345
346 /**
347 * Generates dynamic `box-shadow` CSS for the block, including any
348 * block-level custom breakpoints. State-crossed like colors_style() —
349 * box-shadow-on-hover is a common effect.
350 *
351 * @param array $block The block settings.
352 * @param string $block_id Unique ID for the block instance.
353 * @param object $instance The block instance.
354 * @return string CSS styles.
355 */
356 public static function box_shadow_style( $block, $block_id, $instance ) {
357 $box_shadow = ! empty( $instance->attributes['advancedStyling']['boxShadow']['normal'] ) ? $instance->attributes['advancedStyling']['boxShadow']['normal'] : array();
358
359 if ( ! empty( $block['attrs']['advancedStyling']['boxShadow']['normal'] ) ) {
360 $box_shadow = wp_parse_args( $block['attrs']['advancedStyling']['boxShadow']['normal'], $box_shadow );
361 }
362
363 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
364 ? $block['attrs']['customBlockBreakpoints']
365 : array();
366
367 $css = '';
368
369 if ( ! empty( $box_shadow ) ) {
370 $css .= Dynamic_Styles::get_box_shadow_with_media( '.' . $block_id, $box_shadow, $custom_breakpoints );
371 }
372
373 // Hover/Active/Focus-within variants — see position_style() above for why this runs regardless of whether the Normal bucket was empty.
374 $css .= Dynamic_Styles::get_state_variants_css(
375 '.' . $block_id,
376 $block['attrs'] ?? array(),
377 $instance->attributes,
378 'boxShadow',
379 $custom_breakpoints,
380 function ( $sel, $bucket, $cbp ) {
381 return Dynamic_Styles::get_box_shadow_with_media( $sel, $bucket, $cbp );
382 }
383 );
384
385 return $css;
386 }
387
388 /**
389 * Generates dynamic `flex-grow`/`flex-shrink`/`flex-basis`/`align-self`/
390 * `order`/`cursor` CSS for the block, including any block-level custom
391 * breakpoints. Normal-only — see get_layout_with_media()'s docblock for
392 * why this has no Hover/Active/Focus variant.
393 *
394 * @param array $block The block settings.
395 * @param string $block_id Unique ID for the block instance.
396 * @param object $instance The block instance.
397 * @return string CSS styles.
398 */
399 public static function layout_style( $block, $block_id, $instance ) {
400 $layout = ! empty( $instance->attributes['advancedStyling']['layout']['normal'] ) ? $instance->attributes['advancedStyling']['layout']['normal'] : array();
401
402 if ( ! empty( $block['attrs']['advancedStyling']['layout']['normal'] ) ) {
403 $layout = wp_parse_args( $block['attrs']['advancedStyling']['layout']['normal'], $layout );
404 }
405
406 if ( empty( $layout ) ) {
407 return '';
408 }
409
410 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
411 ? $block['attrs']['customBlockBreakpoints']
412 : array();
413
414 return Dynamic_Styles::get_layout_with_media( '.' . $block_id, $layout, $custom_breakpoints );
415 }
416
417 /**
418 * Generates dynamic `flex-direction`/`flex-wrap`/`gap`/`align-items`/
419 * `justify-content` CSS for the block — the CONTAINER side of flex/grid
420 * layout (how this block lays out its children), as opposed to
421 * layout_style() above (the CHILD side). State-crossed like colors_style()
422 * — these fields share the same resolved Display value the "Position"
423 * section's Display field already supports per state.
424 *
425 * @param array $block The block settings.
426 * @param string $block_id Unique ID for the block instance.
427 * @param object $instance The block instance.
428 * @return string CSS styles.
429 */
430 public static function container_layout_style( $block, $block_id, $instance ) {
431 $container_layout = ! empty( $instance->attributes['advancedStyling']['containerLayout']['normal'] ) ? $instance->attributes['advancedStyling']['containerLayout']['normal'] : array();
432
433 if ( ! empty( $block['attrs']['advancedStyling']['containerLayout']['normal'] ) ) {
434 $container_layout = wp_parse_args( $block['attrs']['advancedStyling']['containerLayout']['normal'], $container_layout );
435 }
436
437 $custom_breakpoints = ! empty( $block['attrs']['customBlockBreakpoints'] ) && is_array( $block['attrs']['customBlockBreakpoints'] )
438 ? $block['attrs']['customBlockBreakpoints']
439 : array();
440
441 $css = '';
442
443 if ( ! empty( $container_layout ) ) {
444 $css .= Dynamic_Styles::get_container_layout_with_media( '.' . $block_id, $container_layout, $custom_breakpoints );
445 }
446
447 // Hover/Active/Focus-within variants — see position_style() above for why this runs regardless of whether the Normal bucket was empty.
448 $css .= Dynamic_Styles::get_state_variants_css(
449 '.' . $block_id,
450 $block['attrs'] ?? array(),
451 $instance->attributes,
452 'containerLayout',
453 $custom_breakpoints,
454 function ( $sel, $bucket, $cbp ) {
455 return Dynamic_Styles::get_container_layout_with_media( $sel, $bucket, $cbp );
456 }
457 );
458
459 return $css;
460 }
461 }
462
463 // Initialize the class.
464 Dynamic_Block_Classname::init();
465