• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / dd6e866a9e6d253114633104d9e3858d807178ba

19 Jun 2024 10:03AM UTC coverage: 48.628% (-4.3%) from 52.936%
dd6e866a9e6d253114633104d9e3858d807178ba

push

github

web-flow
Merge pull request #21431 from Yoast/21429-update-copy-in-the-introduction-and-consent-modals

Updates the copy for the introduction and consent modals

7441 of 13454 branches covered (55.31%)

Branch coverage included in aggregate %.

0 of 3 new or added lines in 2 files covered. (0.0%)

3718 existing lines in 107 files now uncovered.

25100 of 53464 relevant lines covered (46.95%)

62392.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.13
/inc/class-wpseo-image-utils.php
1
<?php
2
/**
3
 * WPSEO plugin file.
4
 *
5
 * @package WPSEO
6
 */
7

8
/**
9
 * WPSEO_Image_Utils.
10
 */
11
class WPSEO_Image_Utils {
12

13
        /**
14
         * Find an attachment ID for a given URL.
15
         *
16
         * @param string $url The URL to find the attachment for.
17
         *
18
         * @return int The found attachment ID, or 0 if none was found.
19
         */
20
        public static function get_attachment_by_url( $url ) {
×
21
                /*
22
                 * As get_attachment_by_url won't work on resized versions of images,
23
                 * we strip out the size part of an image URL.
24
                 */
25
                $url = preg_replace( '/(.*)-\d+x\d+\.(jpg|png|gif)$/', '$1.$2', $url );
×
26

27
                static $uploads;
×
28

29
                if ( $uploads === null ) {
×
30
                        $uploads = wp_get_upload_dir();
×
31
                }
32

33
                // Don't try to do this for external URLs.
34
                if ( strpos( $url, $uploads['baseurl'] ) !== 0 ) {
×
35
                        return 0;
×
36
                }
37

38
                if ( function_exists( 'wpcom_vip_attachment_url_to_postid' ) ) {
×
39
                        // @codeCoverageIgnoreStart -- We can't test this properly.
40
                        return (int) wpcom_vip_attachment_url_to_postid( $url );
×
41
                        // @codeCoverageIgnoreEnd -- The rest we _can_ test.
42
                }
43

44
                return self::attachment_url_to_postid( $url );
×
45
        }
46

47
        /**
48
         * Implements the attachment_url_to_postid with use of WP Cache.
49
         *
50
         * @param string $url The attachment URL for which we want to know the Post ID.
51
         *
52
         * @return int The Post ID belonging to the attachment, 0 if not found.
53
         */
54
        protected static function attachment_url_to_postid( $url ) {
×
55
                $cache_key = sprintf( 'yoast_attachment_url_post_id_%s', md5( $url ) );
×
56

57
                // Set the ID based on the hashed URL in the cache.
58
                $id = wp_cache_get( $cache_key );
×
59

60
                if ( $id === 'not_found' ) {
×
61
                        return 0;
×
62
                }
63

64
                // ID is found in cache, return.
65
                if ( $id !== false ) {
×
66
                        return $id;
×
67
                }
68

69
                // Note: We use the WP COM version if we can, see above.
70
                $id = attachment_url_to_postid( $url );
×
71

72
                if ( empty( $id ) ) {
×
73
                        /**
74
                         * If no ID was found, maybe we're dealing with a scaled big image. So, let's try that.
75
                         *
76
                         * @see https://core.trac.wordpress.org/ticket/51058
77
                         */
78
                        $id = self::get_scaled_image_id( $url );
×
79
                }
80

81
                if ( empty( $id ) ) {
×
82
                        wp_cache_set( $cache_key, 'not_found', '', ( 12 * HOUR_IN_SECONDS + wp_rand( 0, ( 4 * HOUR_IN_SECONDS ) ) ) );
×
83
                        return 0;
×
84
                }
85

86
                // We have the Post ID, but it's not in the cache yet. We do that here and return.
87
                wp_cache_set( $cache_key, $id, '', ( 24 * HOUR_IN_SECONDS + wp_rand( 0, ( 12 * HOUR_IN_SECONDS ) ) ) );
×
88
                return $id;
×
89
        }
90

91
        /**
92
         * Tries getting the ID of a potentially scaled image.
93
         *
94
         * @param string $url The URL of the image.
95
         *
96
         * @return int|false The ID of the image or false for failure.
97
         */
98
        protected static function get_scaled_image_id( $url ) {
×
99
                $path_parts = pathinfo( $url );
×
100
                if ( isset( $path_parts['dirname'], $path_parts['filename'], $path_parts['extension'] ) ) {
×
101
                        $scaled_url = trailingslashit( $path_parts['dirname'] ) . $path_parts['filename'] . '-scaled.' . $path_parts['extension'];
×
102

103
                        return attachment_url_to_postid( $scaled_url );
×
104
                }
105

106
                return false;
×
107
        }
108

109
        /**
110
         * Retrieves the image data.
111
         *
112
         * @param array $image         Image array with URL and metadata.
113
         * @param int   $attachment_id Attachment ID.
114
         *
115
         * @return false|array {
116
         *     Array of image data
117
         *
118
         *     @type string $alt      Image's alt text.
119
         *     @type string $path     Path of image.
120
         *     @type int    $width    Width of image.
121
         *     @type int    $height   Height of image.
122
         *     @type string $type     Image's MIME type.
123
         *     @type string $size     Image's size.
124
         *     @type string $url      Image's URL.
125
         *     @type int    $filesize The file size in bytes, if already set.
126
         * }
127
         */
UNCOV
128
        public static function get_data( $image, $attachment_id ) {
×
UNCOV
129
                if ( ! is_array( $image ) ) {
×
UNCOV
130
                        return false;
×
131
                }
132

133
                // Deals with non-set keys and values being null or false.
UNCOV
134
                if ( empty( $image['width'] ) || empty( $image['height'] ) ) {
×
UNCOV
135
                        return false;
×
136
                }
137

UNCOV
138
                $image['id']     = $attachment_id;
×
UNCOV
139
                $image['alt']    = self::get_alt_tag( $attachment_id );
×
UNCOV
140
                $image['pixels'] = ( (int) $image['width'] * (int) $image['height'] );
×
141

UNCOV
142
                if ( ! isset( $image['type'] ) ) {
×
UNCOV
143
                        $image['type'] = get_post_mime_type( $attachment_id );
×
144
                }
145

146
                /**
147
                 * Filter: 'wpseo_image_data' - Filter image data.
148
                 *
149
                 * Elements with keys not listed in the section will be discarded.
150
                 *
151
                 * @param array $image_data {
152
                 *     Array of image data
153
                 *
154
                 *     @type int    id       Image's ID as an attachment.
155
                 *     @type string alt      Image's alt text.
156
                 *     @type string path     Image's path.
157
                 *     @type int    width    Width of image.
158
                 *     @type int    height   Height of image.
159
                 *     @type int    pixels   Number of pixels in the image.
160
                 *     @type string type     Image's MIME type.
161
                 *     @type string size     Image's size.
162
                 *     @type string url      Image's URL.
163
                 *     @type int    filesize The file size in bytes, if already set.
164
                 * }
165
                 * @param int   $attachment_id Attachment ID.
166
                 */
UNCOV
167
                $image = apply_filters( 'wpseo_image_data', $image, $attachment_id );
×
168

169
                // Keep only the keys we need, and nothing else.
UNCOV
170
                return array_intersect_key( $image, array_flip( [ 'id', 'alt', 'path', 'width', 'height', 'pixels', 'type', 'size', 'url', 'filesize' ] ) );
×
171
        }
172

173
        /**
174
         * Checks a size version of an image to see if it's not too heavy.
175
         *
176
         * @param array $image Image to check the file size of.
177
         *
178
         * @return bool True when the image is within limits, false if not.
179
         */
180
        public static function has_usable_file_size( $image ) {
×
181
                if ( ! is_array( $image ) || $image === [] ) {
×
182
                        return false;
×
183
                }
184

185
                /**
186
                 * Filter: 'wpseo_image_image_weight_limit' - Determines what the maximum weight
187
                 * (in bytes) of an image is allowed to be, default is 2 MB.
188
                 *
189
                 * @param int $max_bytes The maximum weight (in bytes) of an image.
190
                 */
191
                $max_size = apply_filters( 'wpseo_image_image_weight_limit', 2097152 );
×
192

193
                // We cannot check without a path, so assume it's fine.
194
                if ( ! isset( $image['path'] ) ) {
×
195
                        return true;
×
196
                }
197

198
                return ( self::get_file_size( $image ) <= $max_size );
×
199
        }
200

201
        /**
202
         * Find the right version of an image based on size.
203
         *
204
         * @param int          $attachment_id Attachment ID.
205
         * @param string|array $size          Size name, or array of width and height in pixels (e.g [800,400]).
206
         *
207
         * @return array|false Returns an array with image data on success, false on failure.
208
         */
UNCOV
209
        public static function get_image( $attachment_id, $size ) {
×
UNCOV
210
                $image = false;
×
UNCOV
211
                if ( $size === 'full' ) {
×
UNCOV
212
                        $image = self::get_full_size_image_data( $attachment_id );
×
213
                }
214

UNCOV
215
                if ( ! $image ) {
×
UNCOV
216
                        $image = image_get_intermediate_size( $attachment_id, $size );
×
217
                }
218

UNCOV
219
                if ( ! is_array( $image ) ) {
×
UNCOV
220
                        $image_src = wp_get_attachment_image_src( $attachment_id, $size );
×
UNCOV
221
                        if ( is_array( $image_src ) && isset( $image_src[1] ) && isset( $image_src[2] ) ) {
×
222
                                $image           = [];
×
223
                                $image['url']    = $image_src[0];
×
224
                                $image['width']  = $image_src[1];
×
225
                                $image['height'] = $image_src[2];
×
226
                                $image['size']   = 'full';
×
227
                        }
228
                }
229

UNCOV
230
                if ( ! $image ) {
×
UNCOV
231
                        return false;
×
232
                }
233

UNCOV
234
                if ( ! isset( $image['size'] ) ) {
×
235
                        $image['size'] = $size;
×
236
                }
237

UNCOV
238
                return self::get_data( $image, $attachment_id );
×
239
        }
240

241
        /**
242
         * Returns the image data for the full size image.
243
         *
244
         * @param int $attachment_id Attachment ID.
245
         *
246
         * @return array|false Array when there is a full size image. False if not.
247
         */
248
        protected static function get_full_size_image_data( $attachment_id ) {
×
249
                $image = wp_get_attachment_metadata( $attachment_id );
×
250
                if ( ! is_array( $image ) ) {
×
251
                        return false;
×
252
                }
253

254
                $image['url']  = wp_get_attachment_image_url( $attachment_id, 'full' );
×
255
                $image['path'] = get_attached_file( $attachment_id );
×
256
                $image['size'] = 'full';
×
257

258
                return $image;
×
259
        }
260

261
        /**
262
         * Finds the full file path for a given image file.
263
         *
264
         * @param string $path The relative file path.
265
         *
266
         * @return string The full file path.
267
         */
UNCOV
268
        public static function get_absolute_path( $path ) {
×
UNCOV
269
                static $uploads;
×
270

UNCOV
271
                if ( $uploads === null ) {
×
272
                        $uploads = wp_get_upload_dir();
×
273
                }
274

275
                // Add the uploads basedir if the path does not start with it.
UNCOV
276
                if ( empty( $uploads['error'] ) && strpos( $path, $uploads['basedir'] ) !== 0 ) {
×
UNCOV
277
                        return $uploads['basedir'] . DIRECTORY_SEPARATOR . ltrim( $path, DIRECTORY_SEPARATOR );
×
278
                }
279

UNCOV
280
                return $path;
×
281
        }
282

283
        /**
284
         * Get the relative path of the image.
285
         *
286
         * @param string $img Image URL.
287
         *
288
         * @return string The expanded image URL.
289
         */
290
        public static function get_relative_path( $img ) {
×
291
                if ( $img[0] !== '/' ) {
×
292
                        return $img;
×
293
                }
294

295
                // If it's a relative URL, it's relative to the domain, not necessarily to the WordPress install, we
296
                // want to preserve domain name and URL scheme (http / https) though.
297
                $parsed_url = wp_parse_url( home_url() );
×
298
                $img        = $parsed_url['scheme'] . '://' . $parsed_url['host'] . $img;
×
299

300
                return $img;
×
301
        }
302

303
        /**
304
         * Get the image file size.
305
         *
306
         * @param array $image An image array object.
307
         *
308
         * @return int The file size in bytes.
309
         */
310
        public static function get_file_size( $image ) {
×
311
                if ( isset( $image['filesize'] ) ) {
×
312
                        return $image['filesize'];
×
313
                }
314

315
                if ( ! isset( $image['path'] ) ) {
×
316
                        return 0;
×
317
                }
318

319
                // If the file size for the file is over our limit, we're going to go for a smaller version.
320
                if ( function_exists( 'wp_filesize' ) ) {
×
321
                        return wp_filesize( self::get_absolute_path( $image['path'] ) );
×
322
                }
323

324
                return file_exists( $image['path'] ) ? (int) filesize( $image['path'] ) : 0;
×
325
        }
326

327
        /**
328
         * Returns the different image variations for consideration.
329
         *
330
         * @param int $attachment_id The attachment to return the variations for.
331
         *
332
         * @return array The different variations possible for this attachment ID.
333
         */
334
        public static function get_variations( $attachment_id ) {
×
335
                $variations = [];
×
336

337
                foreach ( self::get_sizes() as $size ) {
×
338
                        $variation = self::get_image( $attachment_id, $size );
×
339

340
                        // The get_image function returns false if the size doesn't exist for this attachment.
341
                        if ( $variation ) {
×
342
                                $variations[] = $variation;
×
343
                        }
344
                }
345

346
                return $variations;
×
347
        }
348

349
        /**
350
         * Check original size of image. If original image is too small, return false, else return true.
351
         *
352
         * Filters a list of variations by a certain set of usable dimensions.
353
         *
354
         * @param array $usable_dimensions {
355
         *    The parameters to check against.
356
         *
357
         *    @type int    $min_width     Minimum width of image.
358
         *    @type int    $max_width     Maximum width of image.
359
         *    @type int    $min_height    Minimum height of image.
360
         *    @type int    $max_height    Maximum height of image.
361
         * }
362
         * @param array $variations        The variations that should be considered.
363
         *
364
         * @return array Whether a variation is fit for display or not.
365
         */
UNCOV
366
        public static function filter_usable_dimensions( $usable_dimensions, $variations ) {
×
UNCOV
367
                $filtered = [];
×
368

UNCOV
369
                foreach ( $variations as $variation ) {
×
UNCOV
370
                        $dimensions = $variation;
×
371

UNCOV
372
                        if ( self::has_usable_dimensions( $dimensions, $usable_dimensions ) ) {
×
UNCOV
373
                                $filtered[] = $variation;
×
374
                        }
375
                }
376

UNCOV
377
                return $filtered;
×
378
        }
379

380
        /**
381
         * Filters a list of variations by (disk) file size.
382
         *
383
         * @param array $variations The variations to consider.
384
         *
385
         * @return array The validations that pass the required file size limits.
386
         */
387
        public static function filter_usable_file_size( $variations ) {
×
388
                foreach ( $variations as $variation ) {
×
389
                        // We return early to prevent measuring the file size of all the variations.
390
                        if ( self::has_usable_file_size( $variation ) ) {
×
391
                                return [ $variation ];
×
392
                        }
393
                }
394

395
                return [];
×
396
        }
397

398
        /**
399
         * Retrieve the internal WP image file sizes.
400
         *
401
         * @return array An array of image sizes.
402
         */
403
        public static function get_sizes() {
×
404
                /**
405
                 * Filter: 'wpseo_image_sizes' - Determines which image sizes we'll loop through to get an appropriate image.
406
                 *
407
                 * @param array<string> $sizes The array of image sizes to loop through.
408
                 */
409
                return apply_filters( 'wpseo_image_sizes', [ 'full', 'large', 'medium_large' ] );
×
410
        }
411

412
        /**
413
         * Grabs an image alt text.
414
         *
415
         * @param int $attachment_id The attachment ID.
416
         *
417
         * @return string The image alt text.
418
         */
419
        public static function get_alt_tag( $attachment_id ) {
×
420
                return (string) get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
×
421
        }
422

423
        /**
424
         * Checks whether an img sizes up to the parameters.
425
         *
426
         * @param array $dimensions        The image values.
427
         * @param array $usable_dimensions The parameters to check against.
428
         *
429
         * @return bool True if the image has usable measurements, false if not.
430
         */
431
        private static function has_usable_dimensions( $dimensions, $usable_dimensions ) {
×
432
                foreach ( [ 'width', 'height' ] as $param ) {
×
433
                        $minimum = $usable_dimensions[ 'min_' . $param ];
×
434
                        $maximum = $usable_dimensions[ 'max_' . $param ];
×
435

436
                        $current = $dimensions[ $param ];
×
437
                        if ( ( $current < $minimum ) || ( $current > $maximum ) ) {
×
438
                                return false;
×
439
                        }
440
                }
441

442
                return true;
×
443
        }
444

445
        /**
446
         * Gets the post's first usable content image. Null if none is available.
447
         *
448
         * @param int|null $post_id The post id.
449
         *
450
         * @return string|null The image URL.
451
         */
452
        public static function get_first_usable_content_image_for_post( $post_id = null ) {
×
453
                $post = get_post( $post_id );
×
454

455
                // We know get_post() returns the post or null.
456
                if ( ! $post ) {
×
457
                        return null;
×
458
                }
459

460
                $image_finder = new WPSEO_Content_Images();
×
461
                $images       = $image_finder->get_images( $post->ID, $post );
×
462

463
                return self::get_first_image( $images );
×
464
        }
465

466
        /**
467
         * Gets the term's first usable content image. Null if none is available.
468
         *
469
         * @param int $term_id The term id.
470
         *
471
         * @return string|null The image URL.
472
         */
473
        public static function get_first_content_image_for_term( $term_id ) {
2✔
474
                $term_description = term_description( $term_id );
2✔
475

476
                // We know term_description() returns a string which may be empty.
477
                if ( $term_description === '' ) {
2✔
478
                        return null;
×
479
                }
480

481
                $image_finder = new WPSEO_Content_Images();
2✔
482
                $images       = $image_finder->get_images_from_content( $term_description );
2✔
483

484
                return self::get_first_image( $images );
2✔
485
        }
486

487
        /**
488
         * Retrieves an attachment ID for an image uploaded in the settings.
489
         *
490
         * Due to self::get_attachment_by_url returning 0 instead of false.
491
         * 0 is also a possibility when no ID is available.
492
         *
493
         * @param string $setting The setting the image is stored in.
494
         *
495
         * @return int|bool The attachment id, or false or 0 if no ID is available.
496
         */
497
        public static function get_attachment_id_from_settings( $setting ) {
×
498
                $image_id = WPSEO_Options::get( $setting . '_id', false );
×
499
                if ( $image_id ) {
×
500
                        return $image_id;
×
501
                }
502

503
                $image = WPSEO_Options::get( $setting, false );
×
504
                if ( $image ) {
×
505
                        // There is not an option to put a URL in an image field in the settings anymore, only to upload it through the media manager.
506
                        // This means an attachment always exists, so doing this is only needed once.
507
                        $image_id = self::get_attachment_by_url( $image );
×
508
                }
509

510
                // Only store a new ID if it is not 0, to prevent an update loop.
511
                if ( $image_id ) {
×
512
                        WPSEO_Options::set( $setting . '_id', $image_id );
×
513
                }
514

515
                return $image_id;
×
516
        }
517

518
        /**
519
         * Retrieves the first possible image url from an array of images.
520
         *
521
         * @param array $images The array to extract image url from.
522
         *
523
         * @return string|null The extracted image url when found, null when not found.
524
         */
525
        protected static function get_first_image( $images ) {
8✔
526
                if ( ! is_array( $images ) ) {
8✔
527
                        return null;
2✔
528
                }
529

530
                $images = array_filter( $images );
6✔
531
                if ( empty( $images ) ) {
6✔
532
                        return null;
2✔
533
                }
534

535
                return reset( $images );
4✔
536
        }
537
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc