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

Yoast / wordpress-seo / 6c9a496186af09ad5b9d1b8a59520a14b7920b96

15 Feb 2026 10:29PM UTC coverage: 52.986% (+0.01%) from 52.975%
6c9a496186af09ad5b9d1b8a59520a14b7920b96

push

github

web-flow
Merge pull request #22986 from Yoast/JRF/QA/use-more-specific-check

CS/QA: use slightly more specific checks in a few places

8482 of 15955 branches covered (53.16%)

Branch coverage included in aggregate %.

32462 of 61318 relevant lines covered (52.94%)

48791.32 hits per line

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

75.95
/src/integrations/front-end-integration.php
1
<?php
2

3
namespace Yoast\WP\SEO\Integrations;
4

5
use WP_HTML_Tag_Processor;
6
use WPSEO_Replace_Vars;
7
use Yoast\WP\SEO\Conditionals\Dynamic_Product_Permalinks_Conditional;
8
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
9
use Yoast\WP\SEO\Conditionals\WooCommerce_Version_Conditional;
10
use Yoast\WP\SEO\Context\Meta_Tags_Context;
11
use Yoast\WP\SEO\Helpers\Options_Helper;
12
use Yoast\WP\SEO\Helpers\Permalink_Helper;
13
use Yoast\WP\SEO\Memoizers\Meta_Tags_Context_Memoizer;
14
use Yoast\WP\SEO\Presenters\Abstract_Indexable_Presenter;
15
use Yoast\WP\SEO\Presenters\Debug\Marker_Close_Presenter;
16
use Yoast\WP\SEO\Presenters\Debug\Marker_Open_Presenter;
17
use Yoast\WP\SEO\Presenters\Title_Presenter;
18
use Yoast\WP\SEO\Repositories\Indexable_Repository;
19
use Yoast\WP\SEO\Surfaces\Helpers_Surface;
20
use YoastSEO_Vendor\Symfony\Component\DependencyInjection\ContainerInterface;
21

22
/**
23
 * Class Front_End_Integration.
24
 */
25
class Front_End_Integration implements Integration_Interface {
26

27
        /**
28
         * The memoizer for the meta tags context.
29
         *
30
         * @var Meta_Tags_Context_Memoizer
31
         */
32
        private $context_memoizer;
33

34
        /**
35
         * The container.
36
         *
37
         * @var ContainerInterface
38
         */
39
        protected $container;
40

41
        /**
42
         * Represents the options helper.
43
         *
44
         * @var Options_Helper
45
         */
46
        protected $options;
47

48
        /**
49
         * Represents the permalink helper.
50
         *
51
         * @var Permalink_Helper
52
         */
53
        protected $permalink_helper;
54

55
        /**
56
         * The helpers surface.
57
         *
58
         * @var Helpers_Surface
59
         */
60
        protected $helpers;
61

62
        /**
63
         * The indexable repository.
64
         *
65
         * @var Indexable_Repository
66
         */
67
        protected $indexable_repository;
68

69
        /**
70
         * The replace vars helper.
71
         *
72
         * @var WPSEO_Replace_Vars
73
         */
74
        protected $replace_vars;
75

76
        /**
77
         * The presenters we loop through on each page load.
78
         *
79
         * @var string[]
80
         */
81
        protected $base_presenters = [
82
                'Title',
83
                'Meta_Description',
84
                'Robots',
85
        ];
86

87
        /**
88
         * The presenters we loop through on each page load.
89
         *
90
         * @var string[]
91
         */
92
        protected $indexing_directive_presenters = [
93
                'Canonical',
94
                'Rel_Prev',
95
                'Rel_Next',
96
        ];
97

98
        /**
99
         * The Open Graph specific presenters.
100
         *
101
         * @var string[]
102
         */
103
        protected $open_graph_presenters = [
104
                'Open_Graph\Locale',
105
                'Open_Graph\Type',
106
                'Open_Graph\Title',
107
                'Open_Graph\Description',
108
                'Open_Graph\Url',
109
                'Open_Graph\Site_Name',
110
                'Open_Graph\Article_Publisher',
111
                'Open_Graph\Article_Author',
112
                'Open_Graph\Article_Published_Time',
113
                'Open_Graph\Article_Modified_Time',
114
                'Open_Graph\Image',
115
                'Meta_Author',
116
        ];
117

118
        /**
119
         * The Open Graph specific presenters that should be output on error pages.
120
         *
121
         * @var array<string>
122
         */
123
        protected $open_graph_error_presenters = [
124
                'Open_Graph\Locale',
125
                'Open_Graph\Title',
126
                'Open_Graph\Site_Name',
127
        ];
128

129
        /**
130
         * The Twitter card specific presenters.
131
         *
132
         * @var array<string>
133
         */
134
        protected $twitter_card_presenters = [
135
                'Twitter\Card',
136
                'Twitter\Title',
137
                'Twitter\Description',
138
                'Twitter\Image',
139
                'Twitter\Creator',
140
                'Twitter\Site',
141
        ];
142

143
        /**
144
         * The Slack specific presenters.
145
         *
146
         * @var array<string>
147
         */
148
        protected $slack_presenters = [
149
                'Slack\Enhanced_Data',
150
        ];
151

152
        /**
153
         * The Webmaster verification specific presenters.
154
         *
155
         * @var array<string>
156
         */
157
        protected $webmaster_verification_presenters = [
158
                'Webmaster\Ahrefs',
159
                'Webmaster\Baidu',
160
                'Webmaster\Bing',
161
                'Webmaster\Google',
162
                'Webmaster\Pinterest',
163
                'Webmaster\Yandex',
164
        ];
165

166
        /**
167
         * Presenters that are only needed on singular pages.
168
         *
169
         * @var array<string>
170
         */
171
        protected $singular_presenters = [
172
                'Meta_Author',
173
                'Open_Graph\Article_Author',
174
                'Open_Graph\Article_Publisher',
175
                'Open_Graph\Article_Published_Time',
176
                'Open_Graph\Article_Modified_Time',
177
                'Twitter\Creator',
178
                'Slack\Enhanced_Data',
179
        ];
180

181
        /**
182
         * The presenters we want to be last in our output.
183
         *
184
         * @var array<string>
185
         */
186
        protected $closing_presenters = [
187
                'Schema',
188
        ];
189

190
        /**
191
         * The next output.
192
         *
193
         * @var string
194
         */
195
        protected $next;
196

197
        /**
198
         * The prev output.
199
         *
200
         * @var string
201
         */
202
        protected $prev;
203

204
        /**
205
         * Returns the conditionals based on which this loadable should be active.
206
         *
207
         * @return array<string> The conditionals.
208
         */
209
        public static function get_conditionals() {
2✔
210
                return [ Front_End_Conditional::class ];
2✔
211
        }
212

213
        /**
214
         * Front_End_Integration constructor.
215
         *
216
         * @codeCoverageIgnore It sets dependencies.
217
         *
218
         * @param Meta_Tags_Context_Memoizer $context_memoizer     The meta tags context memoizer.
219
         * @param ContainerInterface         $service_container    The DI container.
220
         * @param Options_Helper             $options              The options helper.
221
         * @param Helpers_Surface            $helpers              The helpers surface.
222
         * @param WPSEO_Replace_Vars         $replace_vars         The replace vars helper.
223
         * @param Indexable_Repository       $indexable_repository The indexable repository.
224
         * @param Permalink_Helper           $permalink_helper     The permalink helper.
225
         */
226
        public function __construct(
227
                Meta_Tags_Context_Memoizer $context_memoizer,
228
                ContainerInterface $service_container,
229
                Options_Helper $options,
230
                Helpers_Surface $helpers,
231
                WPSEO_Replace_Vars $replace_vars,
232
                Indexable_Repository $indexable_repository,
233
                Permalink_Helper $permalink_helper
234
        ) {
235
                $this->container            = $service_container;
236
                $this->context_memoizer     = $context_memoizer;
237
                $this->options              = $options;
238
                $this->helpers              = $helpers;
239
                $this->replace_vars         = $replace_vars;
240
                $this->indexable_repository = $indexable_repository;
241
                $this->permalink_helper     = $permalink_helper;
242
        }
243

244
        /**
245
         * Registers the appropriate hooks to show the SEO metadata on the frontend.
246
         *
247
         * Removes some actions to remove metadata that WordPress shows on the frontend,
248
         * to avoid duplicate and/or mismatched metadata.
249
         *
250
         * @return void
251
         */
252
        public function register_hooks() {
2✔
253
                \add_filter( 'render_block', [ $this, 'query_loop_next_prev' ], 1, 2 );
2✔
254

255
                \add_action( 'wp_head', [ $this, 'call_wpseo_head' ], 1 );
2✔
256
                // Filter the title for compatibility with other plugins and themes.
257
                \add_filter( 'wp_title', [ $this, 'filter_title' ], 15 );
2✔
258
                // Filter the title for compatibility with block-based themes.
259
                \add_filter( 'pre_get_document_title', [ $this, 'filter_title' ], 15 );
2✔
260

261
                // Removes our robots presenter from the list when wp_robots is handling this.
262
                \add_filter( 'wpseo_frontend_presenter_classes', [ $this, 'filter_robots_presenter' ] );
2✔
263

264
                \add_action( 'wpseo_head', [ $this, 'present_head' ], -9999 );
2✔
265
                \add_action( 'wpseo_head', [ $this, 'update_outdated_permalink' ], -10_000 );
2✔
266

267
                \remove_action( 'wp_head', 'rel_canonical' );
2✔
268
                \remove_action( 'wp_head', 'index_rel_link' );
2✔
269
                \remove_action( 'wp_head', 'start_post_rel_link' );
2✔
270
                \remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head' );
2✔
271
                \remove_action( 'wp_head', 'noindex', 1 );
2✔
272
                \remove_action( 'wp_head', '_wp_render_title_tag', 1 );
2✔
273
                \remove_action( 'wp_head', '_block_template_render_title_tag', 1 );
2✔
274
                \remove_action( 'wp_head', 'gutenberg_render_title_tag', 1 );
2✔
275
        }
276

277
        /**
278
         * Filters the title, mainly used for compatibility reasons.
279
         *
280
         * @return string
281
         */
282
        public function filter_title() {
×
283
                $context = $this->context_memoizer->for_current_page();
×
284

285
                $title_presenter = new Title_Presenter();
×
286

287
                /** This filter is documented in src/integrations/front-end-integration.php */
288
                $title_presenter->presentation = \apply_filters( 'wpseo_frontend_presentation', $context->presentation, $context );
×
289
                $title_presenter->replace_vars = $this->replace_vars;
×
290
                $title_presenter->helpers      = $this->helpers;
×
291

292
                \remove_filter( 'pre_get_document_title', [ $this, 'filter_title' ], 15 );
×
293
                $title = \esc_html( $title_presenter->get() );
×
294
                \add_filter( 'pre_get_document_title', [ $this, 'filter_title' ], 15 );
×
295

296
                return $title;
×
297
        }
298

299
        /**
300
         * Checks if the current entity has a permalink that has a mismatch
301
         * with the permalink stored in its indexable. If they differ, purges the indexable's
302
         * permalink so it will be recalculated in the same request.
303
         *
304
         * @return void
305
         */
306
        public function update_outdated_permalink() {
2✔
307
                $dynamic_permalinks_conditional = new Dynamic_Product_Permalinks_Conditional();
2✔
308
                if ( ! $dynamic_permalinks_conditional->is_met() ) {
2✔
309
                        return;
2✔
310
                }
311

312
                $woocommerce_version_conditional = new WooCommerce_Version_Conditional();
×
313
                if ( ! $woocommerce_version_conditional->is_met() ) {
×
314
                        return;
×
315
                }
316

317
                $context = $this->context_memoizer->for_current_page();
×
318

319
                // We're adding this fix only for products because of the 10.5 Woo release. We might expand this for all cases in the future.
320
                if ( $context->indexable->object_sub_type !== 'product' ) {
×
321
                        return;
×
322
                }
323

324
                $current_permalink   = $this->permalink_helper->get_permalink_for_post( $context->indexable->object_sub_type, $context->indexable->object_id );
×
325
                $indexable_permalink = $context->indexable->permalink;
×
326

327
                // Only purge if the permalinks differ.
328
                if ( $current_permalink !== $indexable_permalink ) {
×
329
                        $this->indexable_repository->reset_permalink(
×
330
                                $context->indexable->object_type,
×
331
                                $context->indexable->object_sub_type,
×
332
                                $context->indexable->object_id
×
333
                        );
×
334

335
                        // Clear the memoizer caches so present_head() sees the updated indexable.
336
                        $this->context_memoizer->clear_for_current_page();
×
337
                        $this->context_memoizer->clear( $context->indexable );
×
338
                }
339
        }
340

341
        /**
342
         * Filters the next and prev links in the query loop block.
343
         *
344
         * @param string                   $html  The HTML output.
345
         * @param array<string|array|null> $block The block.
346
         * @return string The filtered HTML output.
347
         */
348
        public function query_loop_next_prev( $html, $block ) {
6✔
349
                if ( $block['blockName'] === 'core/query' ) {
6✔
350
                        // Check that the query does not inherit the main query.
351
                        if ( isset( $block['attrs']['query']['inherit'] ) && ! $block['attrs']['query']['inherit'] ) {
2✔
352
                                \add_filter( 'wpseo_adjacent_rel_url', [ $this, 'adjacent_rel_url' ], 1, 3 );
2✔
353
                        }
354
                }
355

356
                if ( $block['blockName'] === 'core/query-pagination-next' ) {
6✔
357
                        $this->next = $html;
2✔
358
                }
359

360
                if ( $block['blockName'] === 'core/query-pagination-previous' ) {
6✔
361
                        $this->prev = $html;
2✔
362
                }
363

364
                return $html;
6✔
365
        }
366

367
        /**
368
         * Returns correct adjacent pages when Query loop block does not inherit query from template.
369
         * Prioritizes existing prev and next links.
370
         * Includes a safety check for full urls though it is not expected in the query pagination block.
371
         *
372
         * @param string                      $link         The current link.
373
         * @param string                      $rel          Link relationship, prev or next.
374
         * @param Indexable_Presentation|null $presentation The indexable presentation.
375
         *
376
         * @return string The correct link.
377
         */
378
        public function adjacent_rel_url( $link, $rel, $presentation = null ) {
24✔
379
                // Prioritize existing prev and next links.
380
                if ( $link ) {
24✔
381
                        return $link;
4✔
382
                }
383

384
                // Safety check for rel value.
385
                if ( $rel !== 'next' && $rel !== 'prev' ) {
20✔
386
                        return $link;
4✔
387
                }
388

389
                // Check $this->next or $this->prev for existing links.
390
                if ( $this->$rel === null ) {
16✔
391
                        return $link;
4✔
392
                }
393

394
                $processor = new WP_HTML_Tag_Processor( $this->$rel );
12✔
395

396
                if ( ! $processor->next_tag( [ 'tag_name' => 'a' ] ) ) {
12✔
397
                        return $link;
×
398
                }
399

400
                $href = $processor->get_attribute( 'href' );
12✔
401

402
                if ( ! $href ) {
12✔
403
                        return $link;
×
404
                }
405

406
                // Safety check for full url, not expected.
407
                if ( \strpos( $href, 'http' ) === 0 ) {
12✔
408
                        return $href;
4✔
409
                }
410

411
                // Check if $href is relative and append last part of the url to permalink.
412
                if ( \strpos( $href, '/' ) === 0 ) {
8✔
413
                        $href_parts = \explode( '/', $href );
8✔
414
                        return $presentation->permalink . \end( $href_parts );
8✔
415
                }
416

417
                return $link;
×
418
        }
419

420
        /**
421
         * Filters our robots presenter, but only when wp_robots is attached to the wp_head action.
422
         *
423
         * @param array<string> $presenters The presenters for current page.
424
         *
425
         * @return array<string> The filtered presenters.
426
         */
427
        public function filter_robots_presenter( $presenters ) {
8✔
428
                if ( ! \function_exists( 'wp_robots' ) ) {
8✔
429
                        return $presenters;
×
430
                }
431

432
                if ( ! \has_action( 'wp_head', 'wp_robots' ) ) {
8✔
433
                        return $presenters;
4✔
434
                }
435

436
                if ( \wp_is_serving_rest_request() ) {
4✔
437
                        return $presenters;
2✔
438
                }
439

440
                return \array_diff( $presenters, [ 'Yoast\\WP\\SEO\\Presenters\\Robots_Presenter' ] );
2✔
441
        }
442

443
        /**
444
         * Presents the head in the front-end. Resets wp_query if it's not the main query.
445
         *
446
         * @codeCoverageIgnore It just calls a WordPress function.
447
         *
448
         * @return void
449
         */
450
        public function call_wpseo_head() {
451
                global $wp_query;
452

453
                $old_wp_query = $wp_query;
454
                // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query -- Reason: The recommended function, wp_reset_postdata, doesn't reset wp_query.
455
                \wp_reset_query();
456

457
                \do_action( 'wpseo_head' );
458

459
                // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Reason: we have to restore the query.
460
                $GLOBALS['wp_query'] = $old_wp_query;
461
        }
462

463
        /**
464
         * Echoes all applicable presenters for a page.
465
         *
466
         * @return void
467
         */
468
        public function present_head() {
2✔
469
                $context    = $this->context_memoizer->for_current_page();
2✔
470
                $presenters = $this->get_presenters( $context->page_type, $context );
2✔
471

472
                /**
473
                 * Filter 'wpseo_frontend_presentation' - Allow filtering the presentation used to output our meta values.
474
                 *
475
                 * @param Indexable_Presention $presentation The indexable presentation.
476
                 * @param Meta_Tags_Context    $context      The meta tags context for the current page.
477
                 */
478
                $presentation = \apply_filters( 'wpseo_frontend_presentation', $context->presentation, $context );
2✔
479

480
                echo \PHP_EOL;
2✔
481
                foreach ( $presenters as $presenter ) {
2✔
482
                        $presenter->presentation = $presentation;
2✔
483
                        $presenter->helpers      = $this->helpers;
2✔
484
                        $presenter->replace_vars = $this->replace_vars;
2✔
485

486
                        $output = $presenter->present();
2✔
487
                        if ( ! empty( $output ) ) {
2✔
488
                                // phpcs:ignore WordPress.Security.EscapeOutput -- Presenters are responsible for correctly escaping their output.
489
                                echo "\t" . $output . \PHP_EOL;
2✔
490
                        }
491
                }
492
                echo \PHP_EOL . \PHP_EOL;
2✔
493
        }
494

495
        /**
496
         * Returns all presenters for this page.
497
         *
498
         * @param string                 $page_type The page type.
499
         * @param Meta_Tags_Context|null $context   The meta tags context for the current page.
500
         *
501
         * @return Abstract_Indexable_Presenter[] The presenters.
502
         */
503
        public function get_presenters( $page_type, $context = null ) {
14✔
504
                $context ??= $this->context_memoizer->for_current_page();
14✔
505

506
                $needed_presenters = $this->get_needed_presenters( $page_type );
14✔
507

508
                $callback   = static function ( $presenter ) {
14✔
509
                        if ( ! \class_exists( $presenter ) ) {
14✔
510
                                return null;
×
511
                        }
512
                        return new $presenter();
14✔
513
                };
14✔
514
                $presenters = \array_filter( \array_map( $callback, $needed_presenters ) );
14✔
515

516
                /**
517
                 * Filter 'wpseo_frontend_presenters' - Allow filtering the presenter instances in or out of the request.
518
                 *
519
                 * @param Abstract_Indexable_Presenter[] $presenters List of presenter instances.
520
                 * @param Meta_Tags_Context              $context    The meta tags context for the current page.
521
                 */
522
                $presenter_instances = \apply_filters( 'wpseo_frontend_presenters', $presenters, $context );
14✔
523

524
                if ( ! \is_array( $presenter_instances ) ) {
14✔
525
                        $presenter_instances = $presenters;
×
526
                }
527

528
                $is_presenter_callback = static function ( $presenter_instance ) {
14✔
529
                        return $presenter_instance instanceof Abstract_Indexable_Presenter;
14✔
530
                };
14✔
531
                $presenter_instances   = \array_filter( $presenter_instances, $is_presenter_callback );
14✔
532

533
                return \array_merge(
14✔
534
                        [ new Marker_Open_Presenter() ],
14✔
535
                        $presenter_instances,
14✔
536
                        [ new Marker_Close_Presenter() ]
14✔
537
                );
14✔
538
        }
539

540
        /**
541
         * Generate the array of presenters we need for the current request.
542
         *
543
         * @param string $page_type The page type we're retrieving presenters for.
544
         *
545
         * @return string[] The presenters.
546
         */
547
        private function get_needed_presenters( $page_type ) {
14✔
548
                $presenters = $this->get_presenters_for_page_type( $page_type );
14✔
549

550
                $presenters = $this->maybe_remove_title_presenter( $presenters );
14✔
551

552
                $callback   = static function ( $presenter ) {
14✔
553
                        return "Yoast\WP\SEO\Presenters\\{$presenter}_Presenter";
14✔
554
                };
14✔
555
                $presenters = \array_map( $callback, $presenters );
14✔
556

557
                /**
558
                 * Filter 'wpseo_frontend_presenter_classes' - Allow filtering presenters in or out of the request.
559
                 *
560
                 * @param array  $presenters List of presenters.
561
                 * @param string $page_type  The current page type.
562
                 */
563
                $presenters = \apply_filters( 'wpseo_frontend_presenter_classes', $presenters, $page_type );
14✔
564

565
                return $presenters;
14✔
566
        }
567

568
        /**
569
         * Filters the presenters based on the page type.
570
         *
571
         * @param string $page_type The page type.
572
         *
573
         * @return string[] The presenters.
574
         */
575
        private function get_presenters_for_page_type( $page_type ) {
14✔
576
                if ( $page_type === 'Error_Page' ) {
14✔
577
                        $presenters = $this->base_presenters;
8✔
578
                        if ( $this->options->get( 'opengraph' ) === true ) {
8✔
579
                                $presenters = \array_merge( $presenters, $this->open_graph_error_presenters );
8✔
580
                        }
581
                        return \array_merge( $presenters, $this->closing_presenters );
8✔
582
                }
583

584
                $presenters = $this->get_all_presenters();
6✔
585
                if ( \in_array( $page_type, [ 'Static_Home_Page', 'Home_Page' ], true ) ) {
6✔
586
                        $presenters = \array_merge( $presenters, $this->webmaster_verification_presenters );
2✔
587
                }
588

589
                // Filter out the presenters only needed for singular pages on non-singular pages.
590
                if ( ! \in_array( $page_type, [ 'Post_Type', 'Static_Home_Page' ], true ) ) {
6✔
591
                        $presenters = \array_diff( $presenters, $this->singular_presenters );
2✔
592
                }
593

594
                // Filter out `twitter:data` presenters for static home pages.
595
                if ( $page_type === 'Static_Home_Page' ) {
6✔
596
                        $presenters = \array_diff( $presenters, $this->slack_presenters );
2✔
597
                }
598

599
                return $presenters;
6✔
600
        }
601

602
        /**
603
         * Returns a list of all available presenters based on settings.
604
         *
605
         * @return string[] The presenters.
606
         */
607
        private function get_all_presenters() {
6✔
608
                $presenters = \array_merge( $this->base_presenters, $this->indexing_directive_presenters );
6✔
609
                if ( $this->options->get( 'opengraph' ) === true ) {
6✔
610
                        $presenters = \array_merge( $presenters, $this->open_graph_presenters );
6✔
611
                }
612
                if ( $this->options->get( 'twitter' ) === true && \apply_filters( 'wpseo_output_twitter_card', true ) !== false ) {
6✔
613
                        $presenters = \array_merge( $presenters, $this->twitter_card_presenters );
6✔
614
                }
615
                if ( $this->options->get( 'enable_enhanced_slack_sharing' ) === true && \apply_filters( 'wpseo_output_enhanced_slack_data', true ) !== false ) {
6✔
616
                        $presenters = \array_merge( $presenters, $this->slack_presenters );
6✔
617
                }
618

619
                return \array_merge( $presenters, $this->closing_presenters );
6✔
620
        }
621

622
        /**
623
         * Whether the title presenter should be removed.
624
         *
625
         * @return bool True when the title presenter should be removed, false otherwise.
626
         */
627
        public function should_title_presenter_be_removed() {
2✔
628
                return ! \get_theme_support( 'title-tag' ) && ! $this->options->get( 'forcerewritetitle', false );
2✔
629
        }
630

631
        /**
632
         * Checks if the Title presenter needs to be removed.
633
         *
634
         * @param string[] $presenters The presenters.
635
         *
636
         * @return string[] The presenters.
637
         */
638
        private function maybe_remove_title_presenter( $presenters ) {
×
639
                // Do not remove the title if we're on a REST request.
640
                if ( \wp_is_serving_rest_request() ) {
×
641
                        return $presenters;
×
642
                }
643

644
                // Remove the title presenter if the theme is hardcoded to output a title tag so we don't have two title tags.
645
                if ( $this->should_title_presenter_be_removed() ) {
×
646
                        $presenters = \array_diff( $presenters, [ 'Title' ] );
×
647
                }
648

649
                return $presenters;
×
650
        }
651
}
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

© 2026 Coveralls, Inc