PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 15.0.3
Jetpack – WP Security, Backup, Speed, & Growth v15.0.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / extensions / blocks / slideshow / slideshow.php
jetpack / extensions / blocks / slideshow Last commit date
slideshow.php 1 year ago
slideshow.php
465 lines
1 <?php
2 /**
3 * Slideshow Block.
4 *
5 * @since 7.1.0
6 *
7 * @package automattic/jetpack
8 */
9
10 namespace Automattic\Jetpack\Extensions\Slideshow;
11
12 use Automattic\Jetpack\Blocks;
13 use Jetpack_Gutenberg;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit( 0 );
17 }
18
19 /**
20 * Registers the block for use in Gutenberg
21 * This is done via an action so that we can disable
22 * registration if we need to.
23 */
24 function register_block() {
25 Blocks::jetpack_register_block(
26 __DIR__,
27 array(
28 'render_callback' => __NAMESPACE__ . '\load_assets',
29 'render_email_callback' => __NAMESPACE__ . '\render_email',
30 )
31 );
32 }
33 add_action( 'init', __NAMESPACE__ . '\register_block' );
34
35 /**
36 * Slideshow block registration/dependency declaration.
37 *
38 * @param array $attr Array containing the slideshow block attributes.
39 * @param string $content String containing the slideshow block content.
40 *
41 * @return string
42 */
43 function load_assets( $attr, $content ) {
44 Jetpack_Gutenberg::load_assets_as_required( __DIR__ );
45 if ( Blocks::is_amp_request() ) {
46 return render_amp( $attr );
47 }
48
49 // Enqueue Swiper bundle for dynamic loading
50 if ( ! is_admin() && ! Blocks::is_amp_request() ) {
51 enqueue_swiper_library();
52 }
53
54 return $content;
55 }
56
57 /**
58 * Render slideshow block for email.
59 *
60 * @since 15.0
61 *
62 * @param string $block_content The original block HTML content.
63 * @param array $parsed_block The parsed block data including attributes.
64 * @param object $rendering_context Email rendering context.
65 *
66 * @return string
67 */
68 function render_email( $block_content, array $parsed_block, $rendering_context ) {
69 // Validate input parameters and required dependencies
70 if ( ! isset( $parsed_block['attrs'] ) || ! is_array( $parsed_block['attrs'] ) ||
71 ! class_exists( '\Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper' ) ||
72 ! class_exists( '\Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper' ) ) {
73 return '';
74 }
75
76 // Email rendering configuration - only extract values used multiple times
77 $email_grid_padding_margin = 20; // Total padding/margin space for grid layout
78 $email_common_margin = 16; // Common margin/padding value used multiple times
79 $email_cell_padding = 8; // Cell padding used in multiple places
80
81 $attr = $parsed_block['attrs'];
82
83 // Process images for email rendering
84 $images = process_slideshow_images_for_email( $attr );
85
86 if ( empty( $images ) ) {
87 return '';
88 }
89
90 // Determine target width from the email layout if available
91 $target_width = get_email_target_width( $rendering_context );
92
93 // Build grid content
94 $grid_content = '';
95 $images_per_row = 2; // Two images per row for better email compatibility
96 $image_width = floor( ( $target_width - $email_grid_padding_margin ) / $images_per_row ); // Account for padding/margins
97
98 // Create rows
99 $image_chunks = array_chunk( $images, $images_per_row );
100
101 foreach ( $image_chunks as $row_images ) {
102 $grid_content .= '<table role="presentation" style="width: 100%; border-collapse: collapse; margin: 0 0 ' . $email_common_margin . 'px 0; table-layout: fixed;"><tr>';
103
104 foreach ( $row_images as $image ) {
105 $grid_content .= sprintf(
106 '<td style="width: %dpx; padding: %dpx; vertical-align: top; text-align: center; font-family: Arial, sans-serif;">',
107 $image_width,
108 $email_cell_padding
109 );
110
111 // Build individual image content
112 $grid_content .= sprintf(
113 '<img src="%s" alt="%s" style="width: 100%%; max-width: %dpx; height: auto; display: block; border: 0; margin: 0 auto; border-radius: 4px;" />',
114 esc_url( $image['url'] ),
115 esc_attr( $image['alt'] ),
116 $image_width - $email_common_margin // Account for padding
117 );
118
119 // Add caption if available
120 if ( ! empty( $image['caption'] ) ) {
121 $grid_content .= sprintf(
122 '<p style="margin: 12px 0 0 0; padding: 0; font-size: 14px; color: #666666; line-height: 1.4; text-align: center; font-family: Arial, sans-serif;">%s</p>',
123 esc_html( wp_strip_all_tags( $image['caption'] ) )
124 );
125 }
126
127 $grid_content .= '</td>';
128 }
129
130 // Fill remaining cells if odd number of images in last row
131 $remaining_cells = $images_per_row - count( $row_images );
132 for ( $i = 0; $i < $remaining_cells; $i++ ) {
133 $grid_content .= sprintf( '<td style="width: %dpx; padding: %dpx;"></td>', $image_width, $email_cell_padding );
134 }
135
136 $grid_content .= '</tr></table>';
137 }
138
139 // Use Table_Wrapper_Helper for consistent email rendering
140 $image_table_attrs = array(
141 'style' => 'margin: ' . $email_common_margin . 'px 0; padding: 0; border-collapse: collapse;',
142 'width' => $target_width,
143 );
144
145 $html = \Automattic\WooCommerce\EmailEditor\Integrations\Utils\Table_Wrapper_Helper::render_table_wrapper( $grid_content, $image_table_attrs );
146
147 // Add margin below the block
148 $html .= '<div style="margin-bottom: 2em;"></div>';
149
150 return $html;
151 }
152
153 /**
154 * Render slideshow block for AMP
155 *
156 * @param array $attr Array containing the slideshow block attributes.
157 *
158 * @return string
159 */
160 function render_amp( $attr ) {
161 if ( empty( $attr['ids'] ) ) {
162 return '';
163 }
164
165 static $wp_block_jetpack_slideshow_id = 0;
166 ++$wp_block_jetpack_slideshow_id;
167
168 $ids = $attr['ids'];
169 $autoplay = empty( $attr['autoplay'] ) ? false : true;
170 $extras = array(
171 'wp-amp-block',
172 $autoplay ? 'wp-block-jetpack-slideshow__autoplay' : null,
173 $autoplay ? 'wp-block-jetpack-slideshow__autoplay-playing' : null,
174 );
175 $classes = Blocks::classes( Blocks::get_block_feature( __DIR__ ), $attr, $extras );
176
177 return sprintf(
178 '<div class="%1$s" id="wp-block-jetpack-slideshow__%2$d"><div class="wp-block-jetpack-slideshow_container swiper">%3$s%4$s%5$s</div></div>',
179 esc_attr( $classes ),
180 absint( $wp_block_jetpack_slideshow_id ),
181 amp_carousel( $attr, $wp_block_jetpack_slideshow_id ),
182 $autoplay ? autoplay_ui( $wp_block_jetpack_slideshow_id ) : '',
183 render_paginator( $ids, $wp_block_jetpack_slideshow_id )
184 );
185 }
186
187 /**
188 * Generate amp-carousel markup
189 *
190 * @param array $attr Array of block attributes.
191 * @param int $block_ordinal The ordinal number of the block, used in unique ID.
192 *
193 * @return string amp-carousel markup.
194 */
195 function amp_carousel( $attr, $block_ordinal ) {
196 $ids = empty( $attr['ids'] ) ? array() : $attr['ids'];
197 $first_image = wp_get_attachment_metadata( $ids[0] );
198 $delay = empty( $attr['delay'] ) ? 3 : absint( $attr['delay'] );
199 $autoplay = empty( $attr['autoplay'] ) ? false : $attr['autoplay'];
200 $width = empty( $first_image['width'] ) ? 800 : $first_image['width'];
201 $height = empty( $first_image['height'] ) ? 600 : $first_image['height'];
202 return sprintf(
203 '<amp-carousel width="%1$d" height="%2$d" layout="responsive" type="slides" data-next-button-aria-label="%3$s" data-prev-button-aria-label="%4$s" controls loop %5$s id="wp-block-jetpack-slideshow__amp-carousel__%6$s" on="slideChange:wp-block-jetpack-slideshow__amp-pagination__%6$s.toggle(index=event.index, value=true)">%7$s</amp-carousel>',
204 esc_attr( $width ),
205 esc_attr( $height ),
206 esc_attr__( 'Next Slide', 'jetpack' ),
207 esc_attr__( 'Previous Slide', 'jetpack' ),
208 $autoplay ? 'autoplay delay=' . esc_attr( $delay * 1000 ) : '',
209 absint( $block_ordinal ),
210 implode( '', slides( $ids, $width, $height ) )
211 );
212 }
213
214 /**
215 * Generate array of slides markup
216 *
217 * @param array $ids Array of image ids.
218 * @param int $width Width of the container.
219 * @param int $height Height of the container.
220 *
221 * @return array Array of slides markup.
222 */
223 function slides( $ids = array(), $width = 400, $height = 300 ) {
224 return array_map(
225 function ( $id ) use ( $width, $height ) {
226 $caption = wp_get_attachment_caption( $id );
227 $figcaption = $caption ? sprintf(
228 '<figcaption class="wp-block-jetpack-slideshow_caption gallery-caption">%s</figcaption>',
229 wp_kses_post( $caption )
230 ) : '';
231 $image = wp_get_attachment_image(
232 $id,
233 array( $width, $height ),
234 false,
235 array(
236 'class' => 'wp-block-jetpack-slideshow_image',
237 'object-fit' => 'contain',
238 )
239 );
240 return sprintf(
241 '<div class="wp-block-jetpack-slideshow_slide"><figure>%s%s</figure></div>',
242 $image,
243 $figcaption
244 );
245 },
246 $ids
247 );
248 }
249
250 /**
251 * Render blocks paginator section
252 *
253 * @param array $ids Array of image ids.
254 * @param int $block_ordinal The ordinal number of the block, used in unique ID.
255 *
256 * @return array Array of bullets markup.
257 */
258 function render_paginator( $ids = array(), $block_ordinal = 0 ) {
259 $total = count( $ids );
260
261 if ( $total < 6 ) {
262 return bullets( $ids, $block_ordinal );
263 }
264
265 return sprintf(
266 '<div class="swiper-pagination-simple">%s / %s</div>',
267 absint( $block_ordinal ),
268 absint( $total )
269 );
270 }
271
272 /**
273 * Generate array of bullets markup
274 *
275 * @param array $ids Array of image ids.
276 * @param int $block_ordinal The ordinal number of the block, used in unique ID.
277 *
278 * @return array Array of bullets markup.
279 */
280 function bullets( $ids = array(), $block_ordinal = 0 ) {
281 $buttons = array_map(
282 function ( $index ) {
283 $aria_label = sprintf(
284 /* translators: %d: Slide number. */
285 __( 'Go to slide %d', 'jetpack' ),
286 absint( $index + 1 )
287 );
288 return sprintf(
289 '<button option="%d" class="swiper-pagination-bullet" tabindex="0" role="button" aria-label="%s" %s></button>',
290 absint( $index ),
291 esc_attr( $aria_label ),
292 0 === $index ? 'selected' : ''
293 );
294 },
295 array_keys( $ids )
296 );
297
298 return sprintf(
299 '<amp-selector id="wp-block-jetpack-slideshow__amp-pagination__%1$d" class="wp-block-jetpack-slideshow_pagination swiper-pagination swiper-pagination-custom amp-pagination" on="select:wp-block-jetpack-slideshow__amp-carousel__%1$d.goToSlide(index=event.targetOption)" layout="container">%2$s</amp-selector>',
300 absint( $block_ordinal ),
301 implode( '', $buttons )
302 );
303 }
304
305 /**
306 * Generate autoplay play/pause UI.
307 *
308 * @param int $block_ordinal The ordinal number of the block, used in unique ID.
309 *
310 * @return string Autoplay UI markup.
311 */
312 function autoplay_ui( $block_ordinal = 0 ) {
313 $block_id = sprintf(
314 'wp-block-jetpack-slideshow__%d',
315 absint( $block_ordinal )
316 );
317 $amp_carousel_id = sprintf(
318 'wp-block-jetpack-slideshow__amp-carousel__%d',
319 absint( $block_ordinal )
320 );
321 $autoplay_pause = sprintf(
322 '<a aria-label="%s" class="wp-block-jetpack-slideshow_button-pause" role="button" on="tap:%s.toggleAutoplay(toggleOn=false),%s.toggleClass(class=wp-block-jetpack-slideshow__autoplay-playing,force=false)"></a>',
323 esc_attr__( 'Pause Slideshow', 'jetpack' ),
324 esc_attr( $amp_carousel_id ),
325 esc_attr( $block_id )
326 );
327 $autoplay_play = sprintf(
328 '<a aria-label="%s" class="wp-block-jetpack-slideshow_button-play" role="button" on="tap:%s.toggleAutoplay(toggleOn=true),%s.toggleClass(class=wp-block-jetpack-slideshow__autoplay-playing,force=true)"></a>',
329 esc_attr__( 'Play Slideshow', 'jetpack' ),
330 esc_attr( $amp_carousel_id ),
331 esc_attr( $block_id )
332 );
333 return $autoplay_pause . $autoplay_play;
334 }
335
336 /**
337 * Enqueue Swiper library assets for dynamic loading.
338 *
339 * @return void
340 */
341 function enqueue_swiper_library() {
342 $swiper_js_path = Jetpack_Gutenberg::get_blocks_directory() . 'swiper.js';
343 $swiper_css_path = Jetpack_Gutenberg::get_blocks_directory() . 'swiper' . ( is_rtl() ? '.rtl' : '' ) . '.css';
344
345 if ( Jetpack_Gutenberg::block_has_asset( $swiper_js_path ) ) {
346 wp_enqueue_script(
347 'jetpack-swiper-library',
348 plugins_url( $swiper_js_path, JETPACK__PLUGIN_FILE ),
349 array(),
350 JETPACK__VERSION,
351 true
352 );
353 }
354
355 if ( Jetpack_Gutenberg::block_has_asset( $swiper_css_path ) ) {
356 wp_enqueue_style(
357 'jetpack-swiper-library',
358 plugins_url( $swiper_css_path, JETPACK__PLUGIN_FILE ),
359 array(),
360 JETPACK__VERSION
361 );
362 }
363 }
364
365 /**
366 * Get target width for email rendering.
367 *
368 * @param object $rendering_context Email rendering context.
369 * @return int Target width in pixels.
370 */
371 function get_email_target_width( $rendering_context ) {
372 $target_width = 600; // Default
373
374 if ( ! empty( $rendering_context ) && is_object( $rendering_context ) && method_exists( $rendering_context, 'get_layout_width_without_padding' ) ) {
375 $layout_width_px = $rendering_context->get_layout_width_without_padding();
376 if ( is_string( $layout_width_px ) ) {
377 $parsed_width = \Automattic\WooCommerce\EmailEditor\Integrations\Utils\Styles_Helper::parse_value( $layout_width_px );
378 if ( $parsed_width > 0 ) {
379 $target_width = $parsed_width;
380 }
381 }
382 }
383
384 return $target_width;
385 }
386
387 /**
388 * Process slideshow images for email rendering.
389 *
390 * @param array $attr Block attributes containing image data.
391 * @return array Processed image data for email rendering.
392 */
393 function process_slideshow_images_for_email( $attr ) {
394 $images = array();
395
396 // Get images from IDs (primary data source)
397 if ( ! empty( $attr['ids'] ) && is_array( $attr['ids'] ) ) {
398 foreach ( $attr['ids'] as $index => $id ) {
399 // Validate ID is a positive integer
400 $id = absint( $id );
401 if ( ! $id ) {
402 continue;
403 }
404
405 $image_url = wp_get_attachment_image_url( $id, 'medium' );
406
407 // Sanitize alt text from post meta
408 $alt_text = get_post_meta( $id, '_wp_attachment_image_alt', true );
409 $alt_text = sanitize_text_field( $alt_text );
410
411 // Get caption from attachment post (stored in post_excerpt)
412 $attachment_post = get_post( $id );
413 $caption = '';
414
415 // First try to get caption from images array if available (with validation)
416 if ( ! empty( $attr['images'] ) && is_array( $attr['images'] ) && isset( $attr['images'][ $index ]['caption'] ) ) {
417 $caption = wp_strip_all_tags( $attr['images'][ $index ]['caption'] );
418 }
419
420 // If no caption in images array, get it from attachment post
421 if ( empty( $caption ) && $attachment_post && ! empty( $attachment_post->post_excerpt ) ) {
422 $caption = wp_strip_all_tags( $attachment_post->post_excerpt );
423 }
424
425 if ( $image_url ) {
426 $images[] = array(
427 'url' => $image_url,
428 'alt' => $alt_text,
429 'caption' => $caption,
430 'id' => $id,
431 );
432 }
433 }
434 } elseif ( ! empty( $attr['images'] ) && is_array( $attr['images'] ) ) {
435 // Fall back to images array if IDs aren't available (for testing)
436 foreach ( $attr['images'] as $image_data ) {
437 if ( ! empty( $image_data['url'] ) ) {
438 // Validate and sanitize URL
439 $url = esc_url_raw( $image_data['url'] );
440 if ( ! $url || ! wp_http_validate_url( $url ) ) {
441 continue;
442 }
443
444 // Sanitize alt text
445 $alt_text = ! empty( $image_data['alt'] ) ? sanitize_text_field( $image_data['alt'] ) : '';
446
447 // Sanitize caption
448 $caption = ! empty( $image_data['caption'] ) ? wp_strip_all_tags( $image_data['caption'] ) : '';
449
450 // Validate ID if present
451 $id = ! empty( $image_data['id'] ) ? absint( $image_data['id'] ) : 0;
452
453 $images[] = array(
454 'url' => $url,
455 'alt' => $alt_text,
456 'caption' => $caption,
457 'id' => $id,
458 );
459 }
460 }
461 }
462
463 return $images;
464 }
465