PluginProbe ʕ •ᴥ•ʔ
FrontBlocks for Gutenberg/GeneratePress / ci-artifacts
FrontBlocks for Gutenberg/GeneratePress vci-artifacts
trunk 0.2.0 0.2.1 0.2.2 0.2.3 0.2.4 0.2.5 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 ci-artifacts
frontblocks / includes / Frontend / Animations.php
frontblocks / includes / Frontend Last commit date
Animations.php 1 month ago BackButton.php 7 months ago BeforeAfter.php 1 month ago BlockPatterns.php 4 months ago Carousel.php 1 month ago ContainerEdgeAlignment.php 1 month ago Counter.php 1 month ago Events.php 6 months ago FaqSchema.php 1 month ago FluidTypography.php 4 months ago Gallery.php 8 months ago GravityFormsInline.php 1 month ago Headline.php 1 month ago InsertPost.php 1 month ago ProductCategories.php 8 months ago ReadingProgress.php 7 months ago ReadingTime.php 8 months ago ShapeAnimations.php 1 month ago StackedImages.php 4 months ago StickyColumn.php 1 month ago Testimonials.php 8 months ago TextAnimation.php 1 month ago
Animations.php
354 lines
1 <?php
2 /**
3 * Animations module for FrontBlocks.
4 *
5 * @package FrontBlocks
6 * @author David Perez <david@close.technology>
7 * @copyright 2023 Closemarketing
8 * @version 1.0
9 */
10
11 namespace FrontBlocks\Frontend;
12
13 defined( 'ABSPATH' ) || exit;
14
15 /**
16 * Animations class.
17 *
18 * @since 1.0.0
19 */
20 class Animations {
21
22 /**
23 * Constructor.
24 */
25 public function __construct() {
26 $this->init_hooks();
27 }
28
29 /**
30 * Initialize hooks.
31 *
32 * @return void
33 */
34 private function init_hooks() {
35 add_action( 'init', array( $this, 'register_scripts' ) );
36 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ), 5 );
37 add_action( 'enqueue_block_editor_assets', array( $this, 'register_animation_attributes' ), 15 );
38 add_filter( 'render_block', array( $this, 'add_animation_classes_to_blocks' ), 10, 2 );
39 }
40
41 /**
42 * Register frontend scripts and styles for conditional enqueueing.
43 *
44 * @return void
45 */
46 public function register_scripts() {
47 wp_register_style(
48 'frontblocks-animations',
49 FRBL_PLUGIN_URL . 'assets/animations/frontblocks-animations.css',
50 array(),
51 FRBL_VERSION
52 );
53
54 wp_register_script(
55 'frontblocks-animations-custom',
56 FRBL_PLUGIN_URL . 'assets/animations/frontblocks-animations.js',
57 array(),
58 FRBL_VERSION,
59 true
60 );
61 }
62
63 /**
64 * Enqueue block editor assets.
65 *
66 * @return void
67 */
68 public function enqueue_block_editor_assets() {
69 // Enqueue custom animations CSS for editor (reuse registered frontend style).
70 wp_enqueue_style( 'frontblocks-animations' );
71
72 // Enqueue custom block editor script.
73 wp_enqueue_script(
74 'frontblocks-animation-editor',
75 FRBL_PLUGIN_URL . 'assets/animations/frontblocks-animation-option.js',
76 array( 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n' ),
77 FRBL_VERSION,
78 true
79 );
80
81 // Set script translations for JavaScript.
82 wp_set_script_translations(
83 'frontblocks-animation-editor',
84 'frontblocks'
85 );
86
87 // Localize script with custom CSS URL.
88 wp_localize_script(
89 'frontblocks-animation-editor',
90 'frontblocksAnimationData',
91 array(
92 'customCss' => FRBL_PLUGIN_URL . 'assets/animations/frontblocks-animations.css',
93 )
94 );
95 }
96
97 /**
98 * Register animation attributes for all blocks.
99 *
100 * @return void
101 */
102 public function register_animation_attributes() {
103 // This script runs on the client side to add animation attributes to all blocks.
104 wp_add_inline_script(
105 'wp-blocks',
106 "
107 wp.hooks.addFilter(
108 'blocks.registerBlockType',
109 'frontblocks/animation-attributes',
110 function( settings, name ) {
111 // Exclude Gravity Forms blocks from animation attributes.
112 if ( name && name.indexOf('gravityforms/') === 0 ) {
113 return settings;
114 }
115
116 // Defensive check for settings object.
117 if ( ! settings || typeof settings !== 'object' ) {
118 return settings;
119 }
120
121 // Ensure attributes property exists and is an object.
122 if ( ! settings.attributes || typeof settings.attributes !== 'object' || Array.isArray( settings.attributes ) ) {
123 settings.attributes = {};
124 }
125
126 // Use spread operator for safer attribute merging.
127 try {
128 settings.attributes = {
129 ...settings.attributes,
130 frblAnimation: {
131 type: 'string',
132 default: ''
133 },
134 frblAnimationDelay: {
135 type: 'number',
136 default: 0
137 },
138 frblAnimationDuration: {
139 type: 'number',
140 default: 1
141 },
142 frblAnimationRepeat: {
143 type: 'boolean',
144 default: false
145 },
146 frblAnimationInfinite: {
147 type: 'boolean',
148 default: false
149 },
150 frblDisableAnimationMobile: {
151 type: 'boolean',
152 default: false
153 },
154 frblGlassEffect: {
155 type: 'boolean',
156 default: false
157 },
158 frblGlassBlur: {
159 type: 'number',
160 default: 10
161 },
162 frblHoverBgScale: {
163 type: 'boolean',
164 default: false
165 },
166 frblHoverBgScaleAmount: {
167 type: 'number',
168 default: 1.1
169 }
170 };
171 } catch( error ) {
172 return settings;
173 }
174
175 return settings;
176 }
177 );
178 "
179 );
180 }
181
182 /**
183 * Add animation classes to blocks on frontend render.
184 *
185 * @param string $block_content Block content.
186 * @param array $block Block data.
187 * @return string Modified block content.
188 */
189 public function add_animation_classes_to_blocks( $block_content, $block ) {
190 if ( empty( $block['attrs'] ) ) {
191 return $block_content;
192 }
193
194 $attrs = $block['attrs'];
195
196 // Check if either animation, glass effect or hover bg scale is set.
197 $has_animation = isset( $attrs['frblAnimation'] ) && ! empty( $attrs['frblAnimation'] );
198 $has_glass_effect = isset( $attrs['frblGlassEffect'] ) && $attrs['frblGlassEffect'];
199 $has_hover_bg_scale = isset( $attrs['frblHoverBgScale'] ) && $attrs['frblHoverBgScale'];
200
201 if ( ! $has_animation && ! $has_glass_effect && ! $has_hover_bg_scale ) {
202 return $block_content;
203 }
204
205 // Enqueue frontend assets only when a block with animation features is present.
206 if ( ! wp_style_is( 'frontblocks-animations', 'enqueued' ) ) {
207 wp_enqueue_style( 'frontblocks-animations' );
208 }
209 if ( ! wp_script_is( 'frontblocks-animations-custom', 'enqueued' ) ) {
210 wp_enqueue_script( 'frontblocks-animations-custom' );
211 }
212
213 $properties = array();
214
215 // Animation properties.
216 if ( $has_animation ) {
217 $animation = $attrs['frblAnimation'];
218 $properties['animation'] = $animation;
219 $delay = isset( $attrs['frblAnimationDelay'] ) ? $attrs['frblAnimationDelay'] : 0;
220 $properties['delay'] = $delay;
221 $duration = isset( $attrs['frblAnimationDuration'] ) ? $attrs['frblAnimationDuration'] : 1;
222 $properties['duration'] = $duration;
223 $repeat = isset( $attrs['frblAnimationRepeat'] ) ? $attrs['frblAnimationRepeat'] : false;
224 $properties['repeat'] = $repeat;
225 $infinite_repeat = isset( $attrs['frblAnimationInfinite'] ) ? $attrs['frblAnimationInfinite'] : false;
226 $properties['infinite_repeat'] = $infinite_repeat;
227 $disable_mobile = isset( $attrs['frblDisableAnimationMobile'] ) ? $attrs['frblDisableAnimationMobile'] : false;
228 $properties['disable_mobile'] = $disable_mobile;
229 }
230
231 // Glass effect properties.
232 if ( $has_glass_effect ) {
233 $properties['glass_effect'] = true;
234 $properties['glass_blur'] = isset( $attrs['frblGlassBlur'] ) ? $attrs['frblGlassBlur'] : 10;
235 }
236
237 // Hover background scale properties.
238 if ( $has_hover_bg_scale ) {
239 $properties['hover_bg_scale'] = true;
240 $properties['hover_bg_scale_amount'] = isset( $attrs['frblHoverBgScaleAmount'] ) ? $attrs['frblHoverBgScaleAmount'] : 1.1;
241 }
242
243 // Build style attributes.
244 $style_attr = '';
245
246 // Animation styles.
247 if ( $has_animation ) {
248 if ( $properties['delay'] > 0 ) {
249 $style_attr .= '--animate-delay:' . esc_attr( $properties['delay'] ) . 's;';
250 }
251
252 if ( 1 !== $properties['duration'] ) {
253 $style_attr .= '--animate-duration:' . esc_attr( $properties['duration'] ) . 's;';
254 }
255
256 if ( $properties['infinite_repeat'] ) {
257 $style_attr .= '--animate-repeat:infinite;';
258 } elseif ( $properties['repeat'] ) {
259 $style_attr .= '--animate-repeat:2;';
260 }
261 }
262
263 // Glass effect styles.
264 if ( $has_glass_effect ) {
265 $blur_value = $properties['glass_blur'];
266 $style_attr .= 'backdrop-filter:blur(' . esc_attr( $blur_value ) . 'px);';
267 $style_attr .= '-webkit-backdrop-filter:blur(' . esc_attr( $blur_value ) . 'px);';
268 }
269
270 // Hover background scale styles.
271 if ( $has_hover_bg_scale ) {
272 $scale_amount = $properties['hover_bg_scale_amount'];
273 $style_attr .= '--frbl-hover-scale:' . esc_attr( $scale_amount ) . ';';
274 }
275
276 // Add animation classes and styles to the first HTML tag.
277 $block_content = preg_replace_callback(
278 '/^<([a-z][a-z0-9]*)\s*((?:[^>]|\\n)*?)(?:style="([^"]*?)")?([^>]*?)>/i',
279 function ( $matches ) use ( $properties, $style_attr, $has_animation, $has_glass_effect, $has_hover_bg_scale ) {
280 $tag = $matches[1] ?? 'div';
281 $beginning = $matches[2] ?? '';
282 $existing_style = $matches[3] ?? '';
283 $ending = $matches[4] ?? '';
284
285 $classes = '';
286
287 // Add animation classes.
288 if ( $has_animation ) {
289 $classes = 'animate__animated animate__' . esc_attr( $properties['animation'] );
290
291 if ( isset( $properties['disable_mobile'] ) && $properties['disable_mobile'] ) {
292 $classes .= ' frbl-no-mobile-animation';
293 }
294 }
295
296 // Add glass effect class.
297 if ( $has_glass_effect ) {
298 $classes .= ( ! empty( $classes ) ? ' ' : '' ) . 'frbl-glass-effect';
299 }
300
301 // Add hover background scale class.
302 if ( $has_hover_bg_scale ) {
303 $classes .= ( ! empty( $classes ) ? ' ' : '' ) . 'frbl-hover-bg-scale';
304 }
305
306 // Add classes to existing class attribute or create new one.
307 if ( ! empty( $classes ) ) {
308 if ( strpos( $beginning . $ending, 'class="' ) !== false ) {
309 $beginning = preg_replace(
310 '/class="([^"]*)"/',
311 'class="$1 ' . $classes . '"',
312 $beginning . $ending,
313 1
314 );
315 } else {
316 $beginning .= ' class="' . $classes . '"';
317 }
318 }
319
320 // Add animation data attributes.
321 if ( $has_animation ) {
322 $beginning .= ' data-frontblocks-animation="' . esc_attr( $properties['animation'] ) . '"';
323 $beginning .= ' data-frontblocks-animation-delay="' . esc_attr( $properties['delay'] ) . '"';
324 $beginning .= ' data-frontblocks-animation-duration="' . esc_attr( $properties['duration'] ) . '"';
325 $beginning .= ' data-frontblocks-animation-repeat="' . esc_attr( $properties['repeat'] ) . '"';
326 $beginning .= ' data-frontblocks-animation-infinite="' . esc_attr( $properties['infinite_repeat'] ) . '"';
327 }
328
329 // Add glass effect data attributes.
330 if ( $has_glass_effect ) {
331 $beginning .= ' data-frontblocks-glass-blur="' . esc_attr( $properties['glass_blur'] ) . '"';
332 }
333
334 // Add hover background scale data attributes.
335 if ( $has_hover_bg_scale ) {
336 $beginning .= ' data-frontblocks-hover-scale="' . esc_attr( $properties['hover_bg_scale_amount'] ) . '"';
337 }
338
339 // Add styles if needed.
340 if ( ! empty( $style_attr ) ) {
341 $combined_style = $existing_style . ( ! empty( $existing_style ) ? ';' : '' ) . $style_attr;
342 return '<' . $tag . ' ' . $beginning . ' style="' . $combined_style . '">';
343 }
344
345 return '<' . $tag . ' ' . $beginning . '>';
346 },
347 $block_content,
348 1
349 );
350
351 return $block_content;
352 }
353 }
354