• 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

0.0
/inc/sitemaps/class-sitemap-image-parser.php
1
<?php
2
/**
3
 * WPSEO plugin file.
4
 *
5
 * @package WPSEO\XML_Sitemaps
6
 */
7

8
/**
9
 * Parses images from the given post.
10
 */
11
class WPSEO_Sitemap_Image_Parser {
12

13
        /**
14
         * Holds the home_url() value to speed up loops.
15
         *
16
         * @var string
17
         */
18
        protected $home_url = '';
19

20
        /**
21
         * Holds site URL hostname.
22
         *
23
         * @var string
24
         */
25
        protected $host = '';
26

27
        /**
28
         * Holds site URL protocol.
29
         *
30
         * @var string
31
         */
32
        protected $scheme = 'http';
33

34
        /**
35
         * Cached set of attachments for multiple posts.
36
         *
37
         * @var array
38
         */
39
        protected $attachments = [];
40

41
        /**
42
         * Holds blog charset value for use in DOM parsing.
43
         *
44
         * @var string
45
         */
46
        protected $charset = 'UTF-8';
47

48
        /**
49
         * Set up URL properties for reuse.
50
         */
51
        public function __construct() {
×
52

53
                $this->home_url = home_url();
×
54
                $parsed_home    = wp_parse_url( $this->home_url );
×
55

56
                if ( ! empty( $parsed_home['host'] ) ) {
×
57
                        $this->host = str_replace( 'www.', '', $parsed_home['host'] );
×
58
                }
59

60
                if ( ! empty( $parsed_home['scheme'] ) ) {
×
61
                        $this->scheme = $parsed_home['scheme'];
×
62
                }
63

64
                $this->charset = esc_attr( get_bloginfo( 'charset' ) );
×
65
        }
66

67
        /**
68
         * Get set of image data sets for the given post.
69
         *
70
         * @param object $post Post object to get images for.
71
         *
72
         * @return array
73
         */
UNCOV
74
        public function get_images( $post ) {
×
75

UNCOV
76
                $images = [];
×
77

UNCOV
78
                if ( ! is_object( $post ) ) {
×
79
                        return $images;
×
80
                }
81

UNCOV
82
                $thumbnail_id = get_post_thumbnail_id( $post->ID );
×
83

UNCOV
84
                if ( $thumbnail_id ) {
×
85

86
                        $src      = $this->get_absolute_url( $this->image_url( $thumbnail_id ) );
×
87
                        $images[] = $this->get_image_item( $post, $src );
×
88
                }
89

90
                /**
91
                 * Filter: 'wpseo_sitemap_content_before_parse_html_images' - Filters the post content
92
                 * before it is parsed for images.
93
                 *
94
                 * @param string $content The raw/unprocessed post content.
95
                 */
UNCOV
96
                $content = apply_filters( 'wpseo_sitemap_content_before_parse_html_images', $post->post_content );
×
97

UNCOV
98
                $unfiltered_images = $this->parse_html_images( $content );
×
99

UNCOV
100
                foreach ( $unfiltered_images as $image ) {
×
UNCOV
101
                        $images[] = $this->get_image_item( $post, $image['src'] );
×
102
                }
103

UNCOV
104
                foreach ( $this->parse_galleries( $content, $post->ID ) as $attachment ) {
×
105
                        $src      = $this->get_absolute_url( $this->image_url( $attachment->ID ) );
×
106
                        $images[] = $this->get_image_item( $post, $src );
×
107
                }
108

UNCOV
109
                if ( $post->post_type === 'attachment' && wp_attachment_is_image( $post ) ) {
×
110
                        $src      = $this->get_absolute_url( $this->image_url( $post->ID ) );
×
111
                        $images[] = $this->get_image_item( $post, $src );
×
112
                }
113

UNCOV
114
                foreach ( $images as $key => $image ) {
×
115

UNCOV
116
                        if ( empty( $image['src'] ) ) {
×
117
                                unset( $images[ $key ] );
×
118
                        }
119
                }
120

121
                /**
122
                 * Filter images to be included for the post in XML sitemap.
123
                 *
124
                 * @param array $images  Array of image items.
125
                 * @param int   $post_id ID of the post.
126
                 */
UNCOV
127
                $image_list = apply_filters( 'wpseo_sitemap_urlimages', $images, $post->ID );
×
UNCOV
128
                if ( isset( $image_list ) && is_array( $image_list ) ) {
×
UNCOV
129
                        $images = $image_list;
×
130
                }
131

UNCOV
132
                return $images;
×
133
        }
134

135
        /**
136
         * Get the images in the term description.
137
         *
138
         * @param object $term Term to get images from description for.
139
         *
140
         * @return array
141
         */
142
        public function get_term_images( $term ) {
×
143

144
                $images = $this->parse_html_images( $term->description );
×
145

146
                foreach ( $this->parse_galleries( $term->description ) as $attachment ) {
×
147

148
                        $images[] = [
×
149
                                'src'   => $this->get_absolute_url( $this->image_url( $attachment->ID ) ),
×
UNCOV
150
                        ];
×
151
                }
152

153
                /**
154
                 * Filter images to be included for the term in XML sitemap.
155
                 *
156
                 * @param array $image_list Array of image items.
157
                 * @param int   $term_id    ID of the post.
158
                 */
159
                $image_list = apply_filters( 'wpseo_sitemap_urlimages_term', $images, $term->term_id );
×
160
                if ( isset( $image_list ) && is_array( $image_list ) ) {
×
161
                        $images = $image_list;
×
162
                }
163

164
                return $images;
×
165
        }
166

167
        /**
168
         * Parse `<img />` tags in content.
169
         *
170
         * @param string $content Content string to parse.
171
         *
172
         * @return array
173
         */
174
        private function parse_html_images( $content ) {
×
175

176
                $images = [];
×
177

178
                if ( ! class_exists( 'DOMDocument' ) ) {
×
179
                        return $images;
×
180
                }
181

182
                if ( empty( $content ) ) {
×
183
                        return $images;
×
184
                }
185

186
                // Prevent DOMDocument from bubbling warnings about invalid HTML.
187
                libxml_use_internal_errors( true );
×
188

189
                $post_dom = new DOMDocument();
×
190
                $post_dom->loadHTML( '<?xml encoding="' . $this->charset . '">' . $content );
×
191

192
                // Clear the errors, so they don't get kept in memory.
193
                libxml_clear_errors();
×
194

195
                /**
196
                 * Image attribute.
197
                 *
198
                 * @var DOMElement $img
199
                 */
200
                foreach ( $post_dom->getElementsByTagName( 'img' ) as $img ) {
×
201

202
                        $src = $img->getAttribute( 'src' );
×
203

204
                        if ( empty( $src ) ) {
×
205
                                continue;
×
206
                        }
207

208
                        $class = $img->getAttribute( 'class' );
×
209

210
                        if ( // This detects WP-inserted images, which we need to upsize. R.
211
                                ! empty( $class )
×
212
                                && ( strpos( $class, 'size-full' ) === false )
×
213
                                && preg_match( '|wp-image-(?P<id>\d+)|', $class, $matches )
×
214
                                && get_post_status( $matches['id'] )
×
215
                        ) {
216
                                $query_params = wp_parse_url( $src, PHP_URL_QUERY );
×
217
                                $src          = $this->image_url( $matches['id'] );
×
218

219
                                if ( $query_params ) {
×
220
                                        $src .= '?' . $query_params;
×
221
                                }
222
                        }
223

224
                        $src = $this->get_absolute_url( $src );
×
225

226
                        if ( strpos( $src, $this->host ) === false ) {
×
227
                                continue;
×
228
                        }
229

230
                        if ( $src !== esc_url( $src, null, 'attribute' ) ) {
×
231
                                continue;
×
232
                        }
233

234
                        $images[] = [
×
235
                                'src'   => $src,
×
UNCOV
236
                        ];
×
237
                }
238

239
                return $images;
×
240
        }
241

242
        /**
243
         * Parse gallery shortcodes in a given content.
244
         *
245
         * @param string $content Content string.
246
         * @param int    $post_id Optional. ID of post being parsed.
247
         *
248
         * @return array Set of attachment objects.
249
         */
250
        protected function parse_galleries( $content, $post_id = 0 ) {
×
251

252
                $attachments = [];
×
253
                $galleries   = $this->get_content_galleries( $content );
×
254

255
                foreach ( $galleries as $gallery ) {
×
256

257
                        $id = $post_id;
×
258

259
                        if ( ! empty( $gallery['id'] ) ) {
×
260
                                $id = intval( $gallery['id'] );
×
261
                        }
262

263
                        // Forked from core gallery_shortcode() to have exact same logic. R.
264
                        if ( ! empty( $gallery['ids'] ) ) {
×
265
                                $gallery['include'] = $gallery['ids'];
×
266
                        }
267

268
                        $gallery_attachments = $this->get_gallery_attachments( $id, $gallery );
×
269

270
                        $attachments = array_merge( $attachments, $gallery_attachments );
×
271
                }
272

273
                return array_unique( $attachments, SORT_REGULAR );
×
274
        }
275

276
        /**
277
         * Retrieves galleries from the passed content.
278
         *
279
         * Forked from core to skip executing shortcodes for performance.
280
         *
281
         * @param string $content Content to parse for shortcodes.
282
         *
283
         * @return array A list of arrays, each containing gallery data.
284
         */
285
        protected function get_content_galleries( $content ) {
×
286

287
                $galleries = [];
×
288

289
                if ( ! preg_match_all( '/' . get_shortcode_regex( [ 'gallery' ] ) . '/s', $content, $matches, PREG_SET_ORDER ) ) {
×
290
                        return $galleries;
×
291
                }
292

293
                foreach ( $matches as $shortcode ) {
×
294

295
                        $attributes = shortcode_parse_atts( $shortcode[3] );
×
296

297
                        if ( $attributes === '' ) { // Valid shortcode without any attributes. R.
×
298
                                $attributes = [];
×
299
                        }
300

301
                        $galleries[] = $attributes;
×
302
                }
303

304
                return $galleries;
×
305
        }
306

307
        /**
308
         * Get image item array with filters applied.
309
         *
310
         * @param WP_Post $post Post object for the context.
311
         * @param string  $src  Image URL.
312
         *
313
         * @return array
314
         */
315
        protected function get_image_item( $post, $src ) {
×
316

317
                $image = [];
×
318

319
                /**
320
                 * Filter image URL to be included in XML sitemap for the post.
321
                 *
322
                 * @param string $src  Image URL.
323
                 * @param object $post Post object.
324
                 */
325
                $image['src'] = apply_filters( 'wpseo_xml_sitemap_img_src', $src, $post );
×
326

327
                /**
328
                 * Filter image data to be included in XML sitemap for the post.
329
                 *
330
                 * @param array  $image {
331
                 *     Array of image data.
332
                 *
333
                 *     @type string  $src   Image URL.
334
                 * }
335
                 *
336
                 * @param object $post  Post object.
337
                 */
338
                return apply_filters( 'wpseo_xml_sitemap_img', $image, $post );
×
339
        }
340

341
        /**
342
         * Get attached image URL with filters applied. Adapted from core for speed.
343
         *
344
         * @param int $post_id ID of the post.
345
         *
346
         * @return string
347
         */
348
        private function image_url( $post_id ) {
×
349

350
                static $uploads;
×
351

352
                if ( empty( $uploads ) ) {
×
353
                        $uploads = wp_upload_dir();
×
354
                }
355

356
                if ( $uploads['error'] !== false ) {
×
357
                        return '';
×
358
                }
359

360
                $file = get_post_meta( $post_id, '_wp_attached_file', true );
×
361

362
                if ( empty( $file ) ) {
×
363
                        return '';
×
364
                }
365

366
                // Check that the upload base exists in the file location.
367
                if ( strpos( $file, $uploads['basedir'] ) === 0 ) {
×
368
                        $src = str_replace( $uploads['basedir'], $uploads['baseurl'], $file );
×
369
                }
370
                elseif ( strpos( $file, 'wp-content/uploads' ) !== false ) {
×
371
                        $src = $uploads['baseurl'] . substr( $file, ( strpos( $file, 'wp-content/uploads' ) + 18 ) );
×
372
                }
373
                else {
374
                        // It's a newly uploaded file, therefore $file is relative to the baseurl.
375
                        $src = $uploads['baseurl'] . '/' . $file;
×
376
                }
377

378
                return apply_filters( 'wp_get_attachment_url', $src, $post_id );
×
379
        }
380

381
        /**
382
         * Make absolute URL for domain or protocol-relative one.
383
         *
384
         * @param string $src URL to process.
385
         *
386
         * @return string
387
         */
388
        protected function get_absolute_url( $src ) {
×
389

390
                if ( empty( $src ) || ! is_string( $src ) ) {
×
391
                        return $src;
×
392
                }
393

394
                if ( YoastSEO()->helpers->url->is_relative( $src ) === true ) {
×
395

396
                        if ( $src[0] !== '/' ) {
×
397
                                return $src;
×
398
                        }
399

400
                        // The URL is relative, we'll have to make it absolute.
401
                        return $this->home_url . $src;
×
402
                }
403

404
                if ( strpos( $src, 'http' ) !== 0 ) {
×
405
                        // Protocol relative URL, we add the scheme as the standard requires a protocol.
406
                        return $this->scheme . ':' . $src;
×
407
                }
408

409
                return $src;
×
410
        }
411

412
        /**
413
         * Returns the attachments for a gallery.
414
         *
415
         * @param int   $id      The post ID.
416
         * @param array $gallery The gallery config.
417
         *
418
         * @return array The selected attachments.
419
         */
420
        protected function get_gallery_attachments( $id, $gallery ) {
×
421

422
                // When there are attachments to include.
423
                if ( ! empty( $gallery['include'] ) ) {
×
424
                        return $this->get_gallery_attachments_for_included( $gallery['include'] );
×
425
                }
426

427
                // When $id is empty, just return empty array.
428
                if ( empty( $id ) ) {
×
429
                        return [];
×
430
                }
431

432
                return $this->get_gallery_attachments_for_parent( $id, $gallery );
×
433
        }
434

435
        /**
436
         * Returns the attachments for the given ID.
437
         *
438
         * @param int   $id      The post ID.
439
         * @param array $gallery The gallery config.
440
         *
441
         * @return array The selected attachments.
442
         */
443
        protected function get_gallery_attachments_for_parent( $id, $gallery ) {
×
UNCOV
444
                $query = [
×
445
                        'posts_per_page' => -1,
×
446
                        'post_parent'    => $id,
×
UNCOV
447
                ];
×
448

449
                // When there are posts that should be excluded from result set.
450
                if ( ! empty( $gallery['exclude'] ) ) {
×
451
                        $query['post__not_in'] = wp_parse_id_list( $gallery['exclude'] );
×
452
                }
453

454
                return $this->get_attachments( $query );
×
455
        }
456

457
        /**
458
         * Returns an array with attachments for the post IDs that will be included.
459
         *
460
         * @param array $included_ids Array with IDs to include.
461
         *
462
         * @return array The found attachments.
463
         */
464
        protected function get_gallery_attachments_for_included( $included_ids ) {
×
465
                $ids_to_include = wp_parse_id_list( $included_ids );
×
466
                $attachments    = $this->get_attachments(
×
UNCOV
467
                        [
×
468
                                'posts_per_page' => count( $ids_to_include ),
×
469
                                'post__in'       => $ids_to_include,
×
UNCOV
470
                        ]
×
UNCOV
471
                );
×
472

473
                $gallery_attachments = [];
×
474
                foreach ( $attachments as $val ) {
×
475
                        $gallery_attachments[ $val->ID ] = $val;
×
476
                }
477

478
                return $gallery_attachments;
×
479
        }
480

481
        /**
482
         * Returns the attachments.
483
         *
484
         * @param array $args Array with query args.
485
         *
486
         * @return array The found attachments.
487
         */
488
        protected function get_attachments( $args ) {
×
UNCOV
489
                $default_args = [
×
490
                        'post_status'         => 'inherit',
×
UNCOV
491
                        'post_type'           => 'attachment',
×
UNCOV
492
                        'post_mime_type'      => 'image',
×
493

494
                        // Defaults taken from function get_posts.
UNCOV
495
                        'orderby'             => 'date',
×
UNCOV
496
                        'order'               => 'DESC',
×
UNCOV
497
                        'meta_key'            => '',
×
UNCOV
498
                        'meta_value'          => '',
×
UNCOV
499
                        'suppress_filters'    => true,
×
UNCOV
500
                        'ignore_sticky_posts' => true,
×
UNCOV
501
                        'no_found_rows'       => true,
×
UNCOV
502
                ];
×
503

504
                $args = wp_parse_args( $args, $default_args );
×
505

506
                $get_attachments = new WP_Query();
×
507
                return $get_attachments->query( $args );
×
508
        }
509
}
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