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