PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 8.2.1
Jetpack – WP Security, Backup, Speed, & Growth v8.2.1
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 / class.jetpack-post-images.php
jetpack Last commit date
3rd-party 6 years ago _inc 6 years ago bin 6 years ago css 6 years ago extensions 6 years ago images 6 years ago json-endpoints 6 years ago languages 6 years ago modules 6 years ago sal 6 years ago src 6 years ago vendor 6 years ago views 7 years ago .svnignore 12 years ago CODE-OF-CONDUCT.md 9 years ago changelog.txt 6 years ago class.frame-nonce-preview.php 6 years ago class.jetpack-admin.php 6 years ago class.jetpack-affiliate.php 6 years ago class.jetpack-autoupdate.php 6 years ago class.jetpack-bbpress-json-api-compat.php 6 years ago class.jetpack-cli.php 6 years ago class.jetpack-client-server.php 6 years ago class.jetpack-connection-banner.php 6 years ago class.jetpack-data.php 6 years ago class.jetpack-debugger.php 7 years ago class.jetpack-error.php 10 years ago class.jetpack-gutenberg.php 6 years ago class.jetpack-heartbeat.php 6 years ago class.jetpack-idc.php 6 years ago class.jetpack-ixr-client.php 6 years ago class.jetpack-modules-list-table.php 6 years ago class.jetpack-network-sites-list-table.php 6 years ago class.jetpack-network.php 6 years ago class.jetpack-plan.php 6 years ago class.jetpack-post-images.php 6 years ago class.jetpack-twitter-cards.php 6 years ago class.jetpack-user-agent.php 6 years ago class.jetpack-xmlrpc-server.php 6 years ago class.jetpack.php 6 years ago class.json-api-endpoints.php 6 years ago class.json-api.php 6 years ago class.photon.php 6 years ago composer.json 6 years ago functions.compat.php 6 years ago functions.cookies.php 6 years ago functions.gallery.php 6 years ago functions.global.php 6 years ago functions.opengraph.php 6 years ago functions.photon.php 6 years ago jest.config.js 6 years ago jetpack.php 6 years ago json-api-config.php 10 years ago json-endpoints.php 7 years ago load-jetpack.php 6 years ago locales.php 7 years ago readme.txt 6 years ago require-lib.php 6 years ago uninstall.php 6 years ago wpml-config.xml 10 years ago
class.jetpack-post-images.php
884 lines
1 <?php
2
3 /**
4 * Useful for finding an image to display alongside/in representation of a specific post.
5 *
6 * Includes a few different methods, all of which return a similar-format array containing
7 * details of any images found. Everything can (should) be called statically, it's just a
8 * function-bucket. You can also call Jetpack_PostImages::get_image() to cycle through all of the methods until
9 * one of them finds something useful.
10 *
11 * This file is included verbatim in Jetpack
12 */
13 class Jetpack_PostImages {
14 /**
15 * If a slideshow is embedded within a post, then parse out the images involved and return them
16 */
17 static function from_slideshow( $post_id, $width = 200, $height = 200 ) {
18 $images = array();
19
20 $post = get_post( $post_id );
21
22 if ( ! $post ) {
23 return $images;
24 }
25
26 if ( ! empty( $post->post_password ) ) {
27 return $images;
28 }
29
30 if ( false === has_shortcode( $post->post_content, 'slideshow' ) ) {
31 return $images; // no slideshow - bail
32 }
33
34 $permalink = get_permalink( $post->ID );
35
36 // Mechanic: Somebody set us up the bomb
37 $old_post = $GLOBALS['post'];
38 $GLOBALS['post'] = $post;
39 $old_shortcodes = $GLOBALS['shortcode_tags'];
40 $GLOBALS['shortcode_tags'] = array( 'slideshow' => $old_shortcodes['slideshow'] );
41
42 // Find all the slideshows
43 preg_match_all( '/' . get_shortcode_regex() . '/sx', $post->post_content, $slideshow_matches, PREG_SET_ORDER );
44
45 ob_start(); // The slideshow shortcode handler calls wp_print_scripts and wp_print_styles... not too happy about that
46
47 foreach ( $slideshow_matches as $slideshow_match ) {
48 $slideshow = do_shortcode_tag( $slideshow_match );
49 if ( false === $pos = stripos( $slideshow, 'jetpack-slideshow' ) ) { // must be something wrong - or we changed the output format in which case none of the following will work
50 continue;
51 }
52 $start = strpos( $slideshow, '[', $pos );
53 $end = strpos( $slideshow, ']', $start );
54 $post_images = json_decode( wp_specialchars_decode( str_replace( "'", '"', substr( $slideshow, $start, $end - $start + 1 ) ), ENT_QUOTES ) ); // parse via JSON
55 // If the JSON didn't decode don't try and act on it.
56 if ( is_array( $post_images ) ) {
57 foreach ( $post_images as $post_image ) {
58 if ( ! $post_image_id = absint( $post_image->id ) ) {
59 continue;
60 }
61
62 $meta = wp_get_attachment_metadata( $post_image_id );
63
64 // Must be larger than 200x200 (or user-specified)
65 if ( ! isset( $meta['width'] ) || $meta['width'] < $width ) {
66 continue;
67 }
68 if ( ! isset( $meta['height'] ) || $meta['height'] < $height ) {
69 continue;
70 }
71
72 $url = wp_get_attachment_url( $post_image_id );
73
74 $images[] = array(
75 'type' => 'image',
76 'from' => 'slideshow',
77 'src' => $url,
78 'src_width' => $meta['width'],
79 'src_height' => $meta['height'],
80 'href' => $permalink,
81 );
82 }
83 }
84 }
85 ob_end_clean();
86
87 // Operator: Main screen turn on
88 $GLOBALS['shortcode_tags'] = $old_shortcodes;
89 $GLOBALS['post'] = $old_post;
90
91 return $images;
92 }
93
94 /**
95 * If a gallery is detected, then get all the images from it.
96 */
97 static function from_gallery( $post_id ) {
98 $images = array();
99
100 $post = get_post( $post_id );
101
102 if ( ! $post ) {
103 return $images;
104 }
105
106 if ( ! empty( $post->post_password ) ) {
107 return $images;
108 }
109
110 $permalink = get_permalink( $post->ID );
111
112 /**
113 * Juggle global post object because the gallery shortcode uses the
114 * global object.
115 *
116 * See core ticket:
117 * https://core.trac.wordpress.org/ticket/39304
118 */
119 if ( isset( $GLOBALS['post'] ) ) {
120 $juggle_post = $GLOBALS['post'];
121 $GLOBALS['post'] = $post;
122 $galleries = get_post_galleries( $post->ID, false );
123 $GLOBALS['post'] = $juggle_post;
124 } else {
125 $GLOBALS['post'] = $post;
126 $galleries = get_post_galleries( $post->ID, false );
127 unset( $GLOBALS['post'] );
128 }
129
130 foreach ( $galleries as $gallery ) {
131 if ( isset( $gallery['type'] ) && 'slideshow' === $gallery['type'] && ! empty( $gallery['ids'] ) ) {
132 $image_ids = explode( ',', $gallery['ids'] );
133 $image_size = isset( $gallery['size'] ) ? $gallery['size'] : 'thumbnail';
134 foreach ( $image_ids as $image_id ) {
135 $image = wp_get_attachment_image_src( $image_id, $image_size );
136 if ( ! empty( $image[0] ) ) {
137 list( $raw_src ) = explode( '?', $image[0] ); // pull off any Query string (?w=250)
138 $raw_src = wp_specialchars_decode( $raw_src ); // rawify it
139 $raw_src = esc_url_raw( $raw_src ); // clean it
140 $images[] = array(
141 'type' => 'image',
142 'from' => 'gallery',
143 'src' => $raw_src,
144 'href' => $permalink,
145 );
146 }
147 }
148 } elseif ( ! empty( $gallery['src'] ) ) {
149 foreach ( $gallery['src'] as $src ) {
150 list( $raw_src ) = explode( '?', $src ); // pull off any Query string (?w=250)
151 $raw_src = wp_specialchars_decode( $raw_src ); // rawify it
152 $raw_src = esc_url_raw( $raw_src ); // clean it
153 $images[] = array(
154 'type' => 'image',
155 'from' => 'gallery',
156 'src' => $raw_src,
157 'href' => $permalink,
158 );
159 }
160 }
161 }
162
163 return $images;
164 }
165
166 /**
167 * Get attachment images for a specified post and return them. Also make sure
168 * their dimensions are at or above a required minimum.
169 */
170 static function from_attachment( $post_id, $width = 200, $height = 200 ) {
171 $images = array();
172
173 $post = get_post( $post_id );
174
175 if ( ! empty( $post->post_password ) ) {
176 return $images;
177 }
178
179 $post_images = get_posts(
180 array(
181 'post_parent' => $post_id, // Must be children of post
182 'numberposts' => 5, // No more than 5
183 'post_type' => 'attachment', // Must be attachments
184 'post_mime_type' => 'image', // Must be images
185 'suppress_filters' => false,
186 )
187 );
188
189 if ( ! $post_images ) {
190 return $images;
191 }
192
193 $permalink = get_permalink( $post_id );
194
195 foreach ( $post_images as $post_image ) {
196 $current_image = self::get_attachment_data( $post_image->ID, $permalink, $width, $height );
197 if ( false !== $current_image ) {
198 $images[] = $current_image;
199 }
200 }
201
202 /*
203 * We only want to pass back attached images that were actually inserted.
204 * We can load up all the images found in the HTML source and then
205 * compare URLs to see if an image is attached AND inserted.
206 */
207 $html_images = self::from_html( $post_id );
208 $inserted_images = array();
209
210 foreach ( $html_images as $html_image ) {
211 $src = wp_parse_url( $html_image['src'] );
212 // strip off any query strings from src
213 if ( ! empty( $src['scheme'] ) && ! empty( $src['host'] ) ) {
214 $inserted_images[] = $src['scheme'] . '://' . $src['host'] . $src['path'];
215 } elseif ( ! empty( $src['host'] ) ) {
216 $inserted_images[] = set_url_scheme( 'http://' . $src['host'] . $src['path'] );
217 } else {
218 $inserted_images[] = site_url( '/' ) . $src['path'];
219 }
220 }
221 foreach ( $images as $i => $image ) {
222 if ( ! in_array( $image['src'], $inserted_images ) ) {
223 unset( $images[ $i ] );
224 }
225 }
226
227 return $images;
228 }
229
230 /**
231 * Check if a Featured Image is set for this post, and return it in a similar
232 * format to the other images?_from_*() methods.
233 *
234 * @param int $post_id The post ID to check
235 * @return Array containing details of the Featured Image, or empty array if none.
236 */
237 static function from_thumbnail( $post_id, $width = 200, $height = 200 ) {
238 $images = array();
239
240 $post = get_post( $post_id );
241
242 if ( ! empty( $post->post_password ) ) {
243 return $images;
244 }
245
246 if ( 'attachment' === get_post_type( $post ) && wp_attachment_is_image( $post ) ) {
247 $thumb = $post_id;
248 } else {
249 $thumb = get_post_thumbnail_id( $post );
250 }
251
252 if ( $thumb ) {
253 $meta = wp_get_attachment_metadata( $thumb );
254 // Must be larger than requested minimums
255 if ( ! isset( $meta['width'] ) || $meta['width'] < $width ) {
256 return $images;
257 }
258 if ( ! isset( $meta['height'] ) || $meta['height'] < $height ) {
259 return $images;
260 }
261
262 $too_big = ( ( ! empty( $meta['width'] ) && $meta['width'] > 1200 ) || ( ! empty( $meta['height'] ) && $meta['height'] > 1200 ) );
263
264 if (
265 $too_big &&
266 (
267 ( method_exists( 'Jetpack', 'is_module_active' ) && Jetpack::is_module_active( 'photon' ) ) ||
268 ( defined( 'IS_WPCOM' ) && IS_WPCOM )
269 )
270 ) {
271 $img_src = wp_get_attachment_image_src( $thumb, array( 1200, 1200 ) );
272 } else {
273 $img_src = wp_get_attachment_image_src( $thumb, 'full' );
274 }
275 if ( ! is_array( $img_src ) ) {
276 // If wp_get_attachment_image_src returns false but we know that there should be an image that could be used.
277 // we try a bit harder and user the data that we have.
278 $thumb_post_data = get_post( $thumb );
279 $img_src = array( $thumb_post_data->guid, $meta['width'], $meta['height'] );
280 }
281
282 $url = $img_src[0];
283 $images = array(
284 array( // Other methods below all return an array of arrays
285 'type' => 'image',
286 'from' => 'thumbnail',
287 'src' => $url,
288 'src_width' => $img_src[1],
289 'src_height' => $img_src[2],
290 'href' => get_permalink( $thumb ),
291 'alt_text' => self::get_alt_text( $thumb ),
292 ),
293 );
294
295 }
296
297 if ( empty( $images ) && ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
298 $meta_thumbnail = get_post_meta( $post_id, '_jetpack_post_thumbnail', true );
299 if ( ! empty( $meta_thumbnail ) ) {
300 if ( ! isset( $meta_thumbnail['width'] ) || $meta_thumbnail['width'] < $width ) {
301 return $images;
302 }
303
304 if ( ! isset( $meta_thumbnail['height'] ) || $meta_thumbnail['height'] < $height ) {
305 return $images;
306 }
307
308 $images = array(
309 array( // Other methods below all return an array of arrays
310 'type' => 'image',
311 'from' => 'thumbnail',
312 'src' => $meta_thumbnail['URL'],
313 'src_width' => $meta_thumbnail['width'],
314 'src_height' => $meta_thumbnail['height'],
315 'href' => $meta_thumbnail['URL'],
316 'alt_text' => self::get_alt_text( $thumb ),
317 ),
318 );
319 }
320 }
321
322 return $images;
323 }
324
325 /**
326 * Get images from Gutenberg Image blocks.
327 *
328 * @since 6.9.0
329 *
330 * @param mixed $html_or_id The HTML string to parse for images, or a post id.
331 * @param int $width Minimum Image width.
332 * @param int $height Minimum Image height.
333 */
334 public static function from_blocks( $html_or_id, $width = 200, $height = 200 ) {
335 $images = array();
336
337 $html_info = self::get_post_html( $html_or_id );
338
339 if ( empty( $html_info['html'] ) ) {
340 return $images;
341 }
342
343 // Look for block information in the HTML.
344 $blocks = parse_blocks( $html_info['html'] );
345 if ( empty( $blocks ) ) {
346 return $images;
347 }
348
349 /*
350 * Let's loop through our blocks.
351 * Some blocks may include some other blocks. Let's go 2 levels deep to look for blocks
352 * that we support and that may include images (see get_images_from_block)
353 *
354 * @to-do: instead of looping manually (that's a lot of if and loops), search recursively instead.
355 */
356 foreach ( $blocks as $block ) {
357 if ( ! self::is_nested_block( $block ) || 'core/media-text' === $block['blockName'] ) {
358 $images = self::get_images_from_block( $images, $block, $html_info, $width, $height );
359 } else {
360 foreach ( $block['innerBlocks'] as $inner_block ) {
361 if ( ! self::is_nested_block( $inner_block ) ) {
362 $images = self::get_images_from_block( $images, $inner_block, $html_info, $width, $height );
363 } else {
364 foreach ( $inner_block['innerBlocks'] as $inner_inner_block ) {
365 $images = self::get_images_from_block( $images, $inner_inner_block, $html_info, $width, $height );
366 }
367 }
368 }
369 }
370 }
371
372 /**
373 * Returning a filtered array because get_attachment_data returns false
374 * for unsuccessful attempts.
375 */
376 return array_filter( $images );
377 }
378
379 /**
380 * Very raw -- just parse the HTML and pull out any/all img tags and return their src
381 *
382 * @param mixed $html_or_id The HTML string to parse for images, or a post id.
383 * @param int $width Minimum Image width.
384 * @param int $height Minimum Image height.
385 *
386 * @uses DOMDocument
387 *
388 * @return Array containing images
389 */
390 static function from_html( $html_or_id, $width = 200, $height = 200 ) {
391 $images = array();
392
393 $html_info = self::get_post_html( $html_or_id );
394
395 if ( empty( $html_info['html'] ) ) {
396 return $images;
397 }
398
399 // Do not go any further if DOMDocument is disabled on the server.
400 if ( ! class_exists( 'DOMDocument' ) ) {
401 return $images;
402 }
403
404 // Let's grab all image tags from the HTML.
405 $dom_doc = new DOMDocument();
406
407 // The @ is not enough to suppress errors when dealing with libxml,
408 // we have to tell it directly how we want to handle errors.
409 libxml_use_internal_errors( true );
410 @$dom_doc->loadHTML( $html_info['html'] );
411 libxml_use_internal_errors( false );
412
413 $image_tags = $dom_doc->getElementsByTagName( 'img' );
414
415 // For each image Tag, make sure it can be added to the $images array, and add it.
416 foreach ( $image_tags as $image_tag ) {
417 $img_src = $image_tag->getAttribute( 'src' );
418
419 if ( empty( $img_src ) ) {
420 continue;
421 }
422
423 // Do not grab smiley images that were automatically created by WP when entering text smilies.
424 if ( stripos( $img_src, '/smilies/' ) ) {
425 continue;
426 }
427
428 $meta = array(
429 'width' => (int) $image_tag->getAttribute( 'width' ),
430 'height' => (int) $image_tag->getAttribute( 'height' ),
431 'alt_text' => $image_tag->getAttribute( 'alt' ),
432 );
433
434 /**
435 * Filters the switch to ignore minimum image size requirements. Can be used
436 * to add custom logic to image dimensions, like only enforcing one of the dimensions,
437 * or disabling it entirely.
438 *
439 * @since 6.4.0
440 *
441 * @param bool $ignore Should the image dimensions be ignored?
442 * @param array $meta Array containing image dimensions parsed from the markup.
443 */
444 $ignore_dimensions = apply_filters( 'jetpack_postimages_ignore_minimum_dimensions', false, $meta );
445
446 // Must be larger than 200x200 (or user-specified).
447 if (
448 ! $ignore_dimensions
449 && (
450 empty( $meta['width'] )
451 || empty( $meta['height'] )
452 || $meta['width'] < $width
453 || $meta['height'] < $height
454 )
455 ) {
456 continue;
457 }
458
459 $images[] = array(
460 'type' => 'image',
461 'from' => 'html',
462 'src' => $img_src,
463 'src_width' => $meta['width'],
464 'src_height' => $meta['height'],
465 'href' => $html_info['post_url'],
466 'alt_text' => $meta['alt_text'],
467 );
468 }
469 return $images;
470 }
471
472 /**
473 * @param int $post_id The post ID to check
474 * @param int $size
475 * @return Array containing details of the image, or empty array if none.
476 */
477 static function from_blavatar( $post_id, $size = 96 ) {
478
479 $permalink = get_permalink( $post_id );
480
481 if ( function_exists( 'blavatar_domain' ) && function_exists( 'blavatar_exists' ) && function_exists( 'blavatar_url' ) ) {
482 $domain = blavatar_domain( $permalink );
483
484 if ( ! blavatar_exists( $domain ) ) {
485 return array();
486 }
487
488 $url = blavatar_url( $domain, 'img', $size );
489 } else {
490 $url = get_site_icon_url( $size );
491 if ( ! $url ) {
492 return array();
493 }
494 }
495
496 return array(
497 array(
498 'type' => 'image',
499 'from' => 'blavatar',
500 'src' => $url,
501 'src_width' => $size,
502 'src_height' => $size,
503 'href' => $permalink,
504 'alt_text' => '',
505 ),
506 );
507 }
508
509 /**
510 * Gets a post image from the author avatar.
511 *
512 * @param int $post_id The post ID to check.
513 * @param int $size The size of the avatar to get.
514 * @param string $default The default image to use.
515 * @return Array containing details of the image, or empty array if none.
516 */
517 static function from_gravatar( $post_id, $size = 96, $default = false ) {
518 $post = get_post( $post_id );
519 $permalink = get_permalink( $post_id );
520
521 if ( function_exists( 'wpcom_get_avatar_url' ) ) {
522 $url = wpcom_get_avatar_url( $post->post_author, $size, $default, true );
523 if ( $url && is_array( $url ) ) {
524 $url = $url[0];
525 }
526 } else {
527 $url = get_avatar_url(
528 $post->post_author,
529 array(
530 'size' => $size,
531 'default' => $default,
532 )
533 );
534 }
535
536 return array(
537 array(
538 'type' => 'image',
539 'from' => 'gravatar',
540 'src' => $url,
541 'src_width' => $size,
542 'src_height' => $size,
543 'href' => $permalink,
544 'alt_text' => '',
545 ),
546 );
547 }
548
549 /**
550 * Run through the different methods that we have available to try to find a single good
551 * display image for this post.
552 *
553 * @param int $post_id
554 * @param array $args Other arguments (currently width and height required for images where possible to determine)
555 * @return Array containing details of the best image to be used
556 */
557 static function get_image( $post_id, $args = array() ) {
558 $image = '';
559
560 /**
561 * Fires before we find a single good image for a specific post.
562 *
563 * @since 2.2.0
564 *
565 * @param int $post_id Post ID.
566 */
567 do_action( 'jetpack_postimages_pre_get_image', $post_id );
568 $media = self::get_images( $post_id, $args );
569
570 if ( is_array( $media ) ) {
571 foreach ( $media as $item ) {
572 if ( 'image' == $item['type'] ) {
573 $image = $item;
574 break;
575 }
576 }
577 }
578
579 /**
580 * Fires after we find a single good image for a specific post.
581 *
582 * @since 2.2.0
583 *
584 * @param int $post_id Post ID.
585 */
586 do_action( 'jetpack_postimages_post_get_image', $post_id );
587
588 return $image;
589 }
590
591 /**
592 * Get an array containing a collection of possible images for this post, stopping once we hit a method
593 * that returns something useful.
594 *
595 * @param int $post_id
596 * @param array $args Optional args, see defaults list for details
597 * @return Array containing images that would be good for representing this post
598 */
599 static function get_images( $post_id, $args = array() ) {
600 // Figure out which image to attach to this post.
601 $media = false;
602
603 /**
604 * Filters the array of images that would be good for a specific post.
605 * This filter is applied before options ($args) filter the original array.
606 *
607 * @since 2.0.0
608 *
609 * @param array $media Array of images that would be good for a specific post.
610 * @param int $post_id Post ID.
611 * @param array $args Array of options to get images.
612 */
613 $media = apply_filters( 'jetpack_images_pre_get_images', $media, $post_id, $args );
614 if ( $media ) {
615 return $media;
616 }
617
618 $defaults = array(
619 'width' => 200, // Required minimum width (if possible to determine)
620 'height' => 200, // Required minimum height (if possible to determine)
621
622 'fallback_to_avatars' => false, // Optionally include Blavatar and Gravatar (in that order) in the image stack
623 'avatar_size' => 96, // Used for both Grav and Blav
624 'gravatar_default' => false, // Default image to use if we end up with no Gravatar
625
626 'from_thumbnail' => true, // Use these flags to specify which methods to use to find an image
627 'from_slideshow' => true,
628 'from_gallery' => true,
629 'from_attachment' => true,
630 'from_blocks' => true,
631 'from_html' => true,
632
633 'html_content' => '', // HTML string to pass to from_html()
634 );
635 $args = wp_parse_args( $args, $defaults );
636
637 $media = false;
638 if ( $args['from_thumbnail'] ) {
639 $media = self::from_thumbnail( $post_id, $args['width'], $args['height'] );
640 }
641 if ( ! $media && $args['from_slideshow'] ) {
642 $media = self::from_slideshow( $post_id, $args['width'], $args['height'] );
643 }
644 if ( ! $media && $args['from_gallery'] ) {
645 $media = self::from_gallery( $post_id );
646 }
647 if ( ! $media && $args['from_attachment'] ) {
648 $media = self::from_attachment( $post_id, $args['width'], $args['height'] );
649 }
650 if ( ! $media && $args['from_blocks'] ) {
651 if ( empty( $args['html_content'] ) ) {
652 $media = self::from_blocks( $post_id, $args['width'], $args['height'] ); // Use the post_id, which will load the content
653 } else {
654 $media = self::from_blocks( $args['html_content'], $args['width'], $args['height'] ); // If html_content is provided, use that
655 }
656 }
657 if ( ! $media && $args['from_html'] ) {
658 if ( empty( $args['html_content'] ) ) {
659 $media = self::from_html( $post_id, $args['width'], $args['height'] ); // Use the post_id, which will load the content
660 } else {
661 $media = self::from_html( $args['html_content'], $args['width'], $args['height'] ); // If html_content is provided, use that
662 }
663 }
664
665 if ( ! $media && $args['fallback_to_avatars'] ) {
666 $media = self::from_blavatar( $post_id, $args['avatar_size'] );
667 if ( ! $media ) {
668 $media = self::from_gravatar( $post_id, $args['avatar_size'], $args['gravatar_default'] );
669 }
670 }
671
672 /**
673 * Filters the array of images that would be good for a specific post.
674 * This filter is applied after options ($args) filter the original array.
675 *
676 * @since 2.0.0
677 *
678 * @param array $media Array of images that would be good for a specific post.
679 * @param int $post_id Post ID.
680 * @param array $args Array of options to get images.
681 */
682 return apply_filters( 'jetpack_images_get_images', $media, $post_id, $args );
683 }
684
685 /**
686 * Takes an image URL and pixel dimensions then returns a URL for the
687 * resized and cropped image.
688 *
689 * @param string $src
690 * @param int $dimension
691 * @return string Transformed image URL
692 */
693 static function fit_image_url( $src, $width, $height ) {
694 $width = (int) $width;
695 $height = (int) $height;
696
697 if ( $width < 1 || $height < 1 ) {
698 return $src;
699 }
700
701 // See if we should bypass WordPress.com SaaS resizing
702 if ( has_filter( 'jetpack_images_fit_image_url_override' ) ) {
703 /**
704 * Filters the image URL used after dimensions are set by Photon.
705 *
706 * @since 3.3.0
707 *
708 * @param string $src Image URL.
709 * @param int $width Image width.
710 * @param int $width Image height.
711 */
712 return apply_filters( 'jetpack_images_fit_image_url_override', $src, $width, $height );
713 }
714
715 // If WPCOM hosted image use native transformations
716 $img_host = wp_parse_url( $src, PHP_URL_HOST );
717 if ( '.files.wordpress.com' == substr( $img_host, -20 ) ) {
718 return add_query_arg(
719 array(
720 'w' => $width,
721 'h' => $height,
722 'crop' => 1,
723 ),
724 set_url_scheme( $src )
725 );
726 }
727
728 // Use Photon magic
729 if ( function_exists( 'jetpack_photon_url' ) ) {
730 return jetpack_photon_url( $src, array( 'resize' => "$width,$height" ) );
731 }
732
733 // Arg... no way to resize image using WordPress.com infrastructure!
734 return $src;
735 }
736
737 /**
738 * Get HTML from given post content.
739 *
740 * @since 6.9.0
741 *
742 * @param mixed $html_or_id The HTML string to parse for images, or a post id.
743 *
744 * @return array $html_info {
745 * @type string $html Post content.
746 * @type string $post_url Post URL.
747 * }
748 */
749 static function get_post_html( $html_or_id ) {
750 if ( is_numeric( $html_or_id ) ) {
751 $post = get_post( $html_or_id );
752
753 if ( empty( $post ) || ! empty( $post->post_password ) ) {
754 return '';
755 }
756
757 $html_info = array(
758 'html' => $post->post_content, // DO NOT apply the_content filters here, it will cause loops.
759 'post_url' => get_permalink( $post->ID ),
760 );
761 } else {
762 $html_info = array(
763 'html' => $html_or_id,
764 'post_url' => '',
765 );
766 }
767 return $html_info;
768 }
769
770 /**
771 * Get info about a WordPress attachment.
772 *
773 * @since 6.9.0
774 *
775 * @param int $attachment_id Attachment ID.
776 * @param string $post_url URL of the post, if we have one.
777 * @param int $width Minimum Image width.
778 * @param int $height Minimum Image height.
779 * @return array|bool Image data or false if unavailable.
780 */
781 public static function get_attachment_data( $attachment_id, $post_url = '', $width, $height ) {
782 if ( empty( $attachment_id ) ) {
783 return false;
784 }
785
786 $meta = wp_get_attachment_metadata( $attachment_id );
787
788 // The image must be larger than 200x200.
789 if ( ! isset( $meta['width'] ) || $meta['width'] < $width ) {
790 return false;
791 }
792 if ( ! isset( $meta['height'] ) || $meta['height'] < $height ) {
793 return false;
794 }
795
796 $url = wp_get_attachment_url( $attachment_id );
797
798 return array(
799 'type' => 'image',
800 'from' => 'attachment',
801 'src' => $url,
802 'src_width' => $meta['width'],
803 'src_height' => $meta['height'],
804 'href' => $post_url,
805 'alt_text' => self::get_alt_text( $attachment_id ),
806 );
807 }
808
809 /**
810 * Get the alt text for an image or other media from the Media Library.
811 *
812 * @since 7.1
813 *
814 * @param int $attachment_id The Post ID of the media.
815 * @return string The alt text value or an emptry string.
816 */
817 public static function get_alt_text( $attachment_id ) {
818 return get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
819 }
820
821 /**
822 * Get an image from a block.
823 *
824 * @since 7.8.0
825 *
826 * @param array $images Images found.
827 * @param array $block Block and its attributes.
828 * @param array $html_info Info about the post where the block is found.
829 * @param int $width Desired image width.
830 * @param int $height Desired image height.
831 *
832 * @return array Array of images found.
833 */
834 private static function get_images_from_block( $images, $block, $html_info, $width, $height ) {
835 /**
836 * Parse content from Core Image blocks.
837 * If it is an image block for an image hosted on our site, it will have an ID.
838 * If it does not have an ID, let `from_html` parse that content later,
839 * and extract an image if it has size parameters.
840 */
841 if (
842 'core/image' === $block['blockName']
843 && ! empty( $block['attrs']['id'] )
844 ) {
845 $images[] = self::get_attachment_data( $block['attrs']['id'], $html_info['post_url'], $width, $height );
846 } elseif (
847 'core/media-text' === $block['blockName']
848 && ! empty( $block['attrs']['mediaId'] )
849 ) {
850 $images[] = self::get_attachment_data( $block['attrs']['mediaId'], $html_info['post_url'], $width, $height );
851 } elseif (
852 /**
853 * Parse content from Core Gallery blocks as well from Jetpack's Tiled Gallery and Slideshow blocks.
854 * Gallery blocks include the ID of each one of the images in the gallery.
855 */
856 in_array( $block['blockName'], array( 'core/gallery', 'jetpack/tiled-gallery', 'jetpack/slideshow' ), true )
857 && ! empty( $block['attrs']['ids'] )
858 ) {
859 foreach ( $block['attrs']['ids'] as $img_id ) {
860 $images[] = self::get_attachment_data( $img_id, $html_info['post_url'], $width, $height );
861 }
862 }
863
864 return $images;
865 }
866
867 /**
868 * Check if a block has inner blocks.
869 *
870 * @since 7.8.0
871 *
872 * @param array $block Block and its attributes.
873 *
874 * @return bool
875 */
876 private static function is_nested_block( $block ) {
877 if ( ! empty( $block['innerBlocks'] ) ) {
878 return true;
879 }
880
881 return false;
882 }
883 }
884