PluginProbe ʕ •ᴥ•ʔ
FrontBlocks for Gutenberg/GeneratePress / 1.0.3
FrontBlocks for Gutenberg/GeneratePress v1.0.3
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 9 months ago Carousel.php 9 months ago Gallery.php 9 months ago InsertPost.php 9 months ago StickyColumn.php 9 months ago Testimonials.php 9 months ago
Animations.php
251 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 $dist_dir = WP_DEBUG ? 'animations/' : 'dist/';
48
49 // Enqueue custom animations CSS.
50 wp_enqueue_style(
51 'frontblocks-animations',
52 FRBL_PLUGIN_URL . 'assets/' . $dist_dir . 'frontblocks-animations.css',
53 array(),
54 FRBL_VERSION
55 );
56
57 wp_enqueue_script(
58 'frontblocks-animations-custom',
59 FRBL_PLUGIN_URL . 'assets/' . $dist_dir . ( WP_DEBUG ? 'frontblocks-animations.js' : 'frontblocks-animations-min.js' ),
60 array(),
61 FRBL_VERSION,
62 true
63 );
64 }
65
66 /**
67 * Enqueue block editor assets.
68 *
69 * @return void
70 */
71 public function enqueue_block_editor_assets() {
72 $dist_dir = WP_DEBUG ? 'animations/' : 'dist/';
73
74 // Enqueue custom animations CSS for editor.
75 wp_enqueue_style(
76 'frontblocks-animations-editor',
77 FRBL_PLUGIN_URL . 'assets/' . $dist_dir . 'frontblocks-animations.css',
78 array(),
79 FRBL_VERSION
80 );
81
82 // Enqueue custom block editor script.
83 wp_enqueue_script(
84 'frontblocks-animation-editor',
85 FRBL_PLUGIN_URL . 'assets/dist/frontblocks-animation-option.js',
86 array( 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n' ),
87 FRBL_VERSION,
88 true
89 );
90
91 // Localize script with custom CSS URL.
92 wp_localize_script(
93 'frontblocks-animation-editor',
94 'frontblocksAnimationData',
95 array(
96 'customCss' => FRBL_PLUGIN_URL . 'assets/' . $dist_dir . 'frontblocks-animations.css',
97 )
98 );
99 }
100
101 /**
102 * Register animation attributes for all blocks.
103 *
104 * @return void
105 */
106 public function register_animation_attributes() {
107 // This script runs on the client side to add animation attributes to all blocks.
108 wp_add_inline_script(
109 'wp-blocks',
110 "
111 wp.hooks.addFilter(
112 'blocks.registerBlockType',
113 'frontblocks/animation-attributes',
114 function( settings, name ) {
115 // Exclude Gravity Forms blocks from animation attributes.
116 if ( name && name.indexOf('gravityforms/') === 0 ) {
117 return settings;
118 }
119
120 // Defensive check for settings object.
121 if ( ! settings || typeof settings !== 'object' ) {
122 return settings;
123 }
124
125 // Ensure attributes property exists and is an object.
126 if ( ! settings.attributes || typeof settings.attributes !== 'object' || Array.isArray( settings.attributes ) ) {
127 settings.attributes = {};
128 }
129
130 // Use spread operator for safer attribute merging.
131 try {
132 settings.attributes = {
133 ...settings.attributes,
134 frblAnimation: {
135 type: 'string',
136 default: ''
137 },
138 frblAnimationDelay: {
139 type: 'number',
140 default: 0
141 },
142 frblAnimationDuration: {
143 type: 'number',
144 default: 1
145 },
146 frblAnimationRepeat: {
147 type: 'boolean',
148 default: false
149 },
150 frblAnimationInfinite: {
151 type: 'boolean',
152 default: false
153 }
154 };
155 } catch( error ) {
156 return settings;
157 }
158
159 return settings;
160 }
161 );
162 "
163 );
164 }
165
166 /**
167 * Add animation classes to blocks on frontend render.
168 *
169 * @param string $block_content Block content.
170 * @param array $block Block data.
171 * @return string Modified block content.
172 */
173 public function add_animation_classes_to_blocks( $block_content, $block ) {
174 if ( empty( $block['attrs'] ) ) {
175 return $block_content;
176 }
177
178 $attrs = $block['attrs'];
179
180 if ( ! isset( $attrs['frblAnimation'] ) || empty( $attrs['frblAnimation'] ) ) {
181 return $block_content;
182 }
183
184 $properties = array();
185 $animation = $properties['animation'] = $attrs['frblAnimation'];
186 $delay = $properties['delay'] = isset( $attrs['frblAnimationDelay'] ) ? $attrs['frblAnimationDelay'] : 0;
187 $duration = $properties['duration'] = isset( $attrs['frblAnimationDuration'] ) ? $attrs['frblAnimationDuration'] : 1;
188 $repeat = $properties['repeat'] = isset( $attrs['frblAnimationRepeat'] ) ? $attrs['frblAnimationRepeat'] : false;
189 $infinite_repeat = $properties['infinite_repeat'] = isset( $attrs['frblAnimationInfinite'] ) ? $attrs['frblAnimationInfinite'] : false;
190
191 // Build style attributes.
192 $style_attr = '';
193 if ( $delay > 0 ) {
194 $style_attr .= '--animate-delay:' . esc_attr( $delay ) . 's;';
195 }
196
197 if ( $duration !== 1 ) {
198 $style_attr .= '--animate-duration:' . esc_attr( $duration ) . 's;';
199 }
200
201 if ( $infinite_repeat ) {
202 $style_attr .= '--animate-repeat:infinite;';
203 } elseif ( $repeat ) {
204 $style_attr .= '--animate-repeat:2;';
205 }
206
207 // Add animation classes and styles to the first HTML tag.
208 $block_content = preg_replace_callback(
209 '/^<([a-z][a-z0-9]*)\s*((?:[^>]|\\n)*?)(?:style="([^"]*?)")?([^>]*?)>/i',
210 function ( $matches ) use ( $properties, $style_attr ) {
211 $tag = $matches[1] ?? 'div';
212 $beginning = $matches[2] ?? '';
213 $existing_style = $matches[3] ?? '';
214 $ending = $matches[4] ?? '';
215
216 $classes = 'animate__animated animate__' . esc_attr( $properties['animation'] );
217
218 // Add classes to existing class attribute or create new one.
219 if ( strpos( $beginning . $ending, 'class="' ) !== false ) {
220 $beginning = preg_replace(
221 '/class="([^"]*)"/',
222 'class="$1 ' . $classes . '"',
223 $beginning . $ending,
224 1
225 );
226 } else {
227 $beginning .= ' class="' . $classes . '"';
228 }
229
230 $beginning .= ' data-frontblocks-animation="' . esc_attr( $properties['animation'] ) . '"';
231 $beginning .= ' data-frontblocks-animation-delay="' . esc_attr( $properties['delay'] ) . '"';
232 $beginning .= ' data-frontblocks-animation-duration="' . esc_attr( $properties['duration'] ) . '"';
233 $beginning .= ' data-frontblocks-animation-repeat="' . esc_attr( $properties['repeat'] ) . '"';
234 $beginning .= ' data-frontblocks-animation-infinite="' . esc_attr( $properties['infinite_repeat'] ) . '"';
235
236 // Add styles if needed.
237 if ( ! empty( $style_attr ) ) {
238 $combined_style = $existing_style . ( ! empty( $existing_style ) ? ';' : '' ) . $style_attr;
239 return '<' . $tag . ' ' . $beginning . ' style="' . $combined_style . '">';
240 }
241
242 return '<' . $tag . ' ' . $beginning . '>';
243 },
244 $block_content,
245 1
246 );
247
248 return $block_content;
249 }
250 }
251