| @@ -1,18 +1,22 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | namespace Yoast\WP\SEO\Integrations; |
| 4 | 4 | |
| 5 | +use WP_HTML_Tag_Processor; | |
| 5 | 6 | use WPSEO_Replace_Vars; |
| 7 | +use Yoast\WP\SEO\Conditionals\Dynamic_Product_Permalinks_Conditional; | |
| 6 | 8 | use Yoast\WP\SEO\Conditionals\Front_End_Conditional; |
| 9 | +use Yoast\WP\SEO\Conditionals\WooCommerce_Version_Conditional; | |
| 7 | 10 | use Yoast\WP\SEO\Context\Meta_Tags_Context; |
| 8 | 11 | use Yoast\WP\SEO\Helpers\Options_Helper; |
| 9 | -use Yoast\WP\SEO\Helpers\Request_Helper; | |
| 12 | +use Yoast\WP\SEO\Helpers\Permalink_Helper; | |
| 10 | 13 | use Yoast\WP\SEO\Memoizers\Meta_Tags_Context_Memoizer; |
| 11 | 14 | use Yoast\WP\SEO\Presenters\Abstract_Indexable_Presenter; |
| 12 | 15 | use Yoast\WP\SEO\Presenters\Debug\Marker_Close_Presenter; |
| 13 | 16 | use Yoast\WP\SEO\Presenters\Debug\Marker_Open_Presenter; |
| 14 | 17 | use Yoast\WP\SEO\Presenters\Title_Presenter; |
| 18 | +use Yoast\WP\SEO\Repositories\Indexable_Repository; | |
| 15 | 19 | use Yoast\WP\SEO\Surfaces\Helpers_Surface; |
| 16 | 20 | use YoastSEO_Vendor\Symfony\Component\DependencyInjection\ContainerInterface; |
| 17 | 21 | |
| 18 | 22 | /** |
| @@ -41,13 +45,13 @@ | ||
| 41 | 45 | */ |
| 42 | 46 | protected $options; |
| 43 | 47 | |
| 44 | 48 | /** |
| 45 | - * Represents the request helper. | |
| 49 | + * Represents the permalink helper. | |
| 46 | 50 | * |
| 47 | - * @var Request_Helper | |
| 51 | + * @var Permalink_Helper | |
| 48 | 52 | */ |
| 49 | - protected $request; | |
| 53 | + protected $permalink_helper; | |
| 50 | 54 | |
| 51 | 55 | /** |
| 52 | 56 | * The helpers surface. |
| 53 | 57 | * |
| @@ -55,8 +59,15 @@ | ||
| 55 | 59 | */ |
| 56 | 60 | protected $helpers; |
| 57 | 61 | |
| 58 | 62 | /** |
| 63 | + * The indexable repository. | |
| 64 | + * | |
| 65 | + * @var Indexable_Repository | |
| 66 | + */ | |
| 67 | + protected $indexable_repository; | |
| 68 | + | |
| 69 | + /** | |
| 59 | 70 | * The replace vars helper. |
| 60 | 71 | * |
| 61 | 72 | * @var WPSEO_Replace_Vars |
| 62 | 73 | */ |
| @@ -100,14 +111,15 @@ | ||
| 100 | 111 | 'Open_Graph\Article_Author', |
| 101 | 112 | 'Open_Graph\Article_Published_Time', |
| 102 | 113 | 'Open_Graph\Article_Modified_Time', |
| 103 | 114 | 'Open_Graph\Image', |
| 115 | + 'Meta_Author', | |
| 104 | 116 | ]; |
| 105 | 117 | |
| 106 | 118 | /** |
| 107 | 119 | * The Open Graph specific presenters that should be output on error pages. |
| 108 | 120 | * |
| 109 | - * @var array | |
| 121 | + * @var array<string> | |
| 110 | 122 | */ |
| 111 | 123 | protected $open_graph_error_presenters = [ |
| 112 | 124 | 'Open_Graph\Locale', |
| 113 | 125 | 'Open_Graph\Title', |
| @@ -116,9 +128,9 @@ | ||
| 116 | 128 | |
| 117 | 129 | /** |
| 118 | 130 | * The Twitter card specific presenters. |
| 119 | 131 | * |
| 120 | - * @var string[] | |
| 132 | + * @var array<string> | |
| 121 | 133 | */ |
| 122 | 134 | protected $twitter_card_presenters = [ |
| 123 | 135 | 'Twitter\Card', |
| 124 | 136 | 'Twitter\Title', |
| @@ -130,9 +142,9 @@ | ||
| 130 | 142 | |
| 131 | 143 | /** |
| 132 | 144 | * The Slack specific presenters. |
| 133 | 145 | * |
| 134 | - * @var string[] | |
| 146 | + * @var array<string> | |
| 135 | 147 | */ |
| 136 | 148 | protected $slack_presenters = [ |
| 137 | 149 | 'Slack\Enhanced_Data', |
| 138 | 150 | ]; |
| @@ -139,11 +151,12 @@ | ||
| 139 | 151 | |
| 140 | 152 | /** |
| 141 | 153 | * The Webmaster verification specific presenters. |
| 142 | 154 | * |
| 143 | - * @var string[] | |
| 155 | + * @var array<string> | |
| 144 | 156 | */ |
| 145 | 157 | protected $webmaster_verification_presenters = [ |
| 158 | + 'Webmaster\Ahrefs', | |
| 146 | 159 | 'Webmaster\Baidu', |
| 147 | 160 | 'Webmaster\Bing', |
| 148 | 161 | 'Webmaster\Google', |
| 149 | 162 | 'Webmaster\Pinterest', |
| @@ -152,11 +165,12 @@ | ||
| 152 | 165 | |
| 153 | 166 | /** |
| 154 | 167 | * Presenters that are only needed on singular pages. |
| 155 | 168 | * |
| 156 | - * @var string[] | |
| 169 | + * @var array<string> | |
| 157 | 170 | */ |
| 158 | 171 | protected $singular_presenters = [ |
| 172 | + 'Meta_Author', | |
| 159 | 173 | 'Open_Graph\Article_Author', |
| 160 | 174 | 'Open_Graph\Article_Publisher', |
| 161 | 175 | 'Open_Graph\Article_Published_Time', |
| 162 | 176 | 'Open_Graph\Article_Modified_Time', |
| @@ -166,9 +180,9 @@ | ||
| 166 | 180 | |
| 167 | 181 | /** |
| 168 | 182 | * The presenters we want to be last in our output. |
| 169 | 183 | * |
| 170 | - * @var string[] | |
| 184 | + * @var array<string> | |
| 171 | 185 | */ |
| 172 | 186 | protected $closing_presenters = [ |
| 173 | 187 | 'Schema', |
| 174 | 188 | ]; |
| @@ -173,11 +187,25 @@ | ||
| 173 | 187 | 'Schema', |
| 174 | 188 | ]; |
| 175 | 189 | |
| 176 | 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 | + /** | |
| 177 | 205 | * Returns the conditionals based on which this loadable should be active. |
| 178 | 206 | * |
| 179 | - * @return array The conditionals. | |
| 207 | + * @return array<string> The conditionals. | |
| 180 | 208 | */ |
| 181 | 209 | public static function get_conditionals() { |
| 182 | 210 | return [ Front_End_Conditional::class ]; |
| 183 | 211 | } |
| @@ -186,29 +214,32 @@ | ||
| 186 | 214 | * Front_End_Integration constructor. |
| 187 | 215 | * |
| 188 | 216 | * @codeCoverageIgnore It sets dependencies. |
| 189 | 217 | * |
| 190 | - * @param Meta_Tags_Context_Memoizer $context_memoizer The meta tags context memoizer. | |
| 191 | - * @param ContainerInterface $service_container The DI container. | |
| 192 | - * @param Options_Helper $options The options helper. | |
| 193 | - * @param Request_Helper $request The request helper. | |
| 194 | - * @param Helpers_Surface $helpers The helpers surface. | |
| 195 | - * @param WPSEO_Replace_Vars $replace_vars The replace vars helper. | |
| 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. | |
| 196 | 225 | */ |
| 197 | 226 | public function __construct( |
| 198 | 227 | Meta_Tags_Context_Memoizer $context_memoizer, |
| 199 | 228 | ContainerInterface $service_container, |
| 200 | 229 | Options_Helper $options, |
| 201 | - Request_Helper $request, | |
| 202 | 230 | Helpers_Surface $helpers, |
| 203 | - WPSEO_Replace_Vars $replace_vars | |
| 231 | + WPSEO_Replace_Vars $replace_vars, | |
| 232 | + Indexable_Repository $indexable_repository, | |
| 233 | + Permalink_Helper $permalink_helper | |
| 204 | 234 | ) { |
| 205 | - $this->container = $service_container; | |
| 206 | - $this->context_memoizer = $context_memoizer; | |
| 207 | - $this->options = $options; | |
| 208 | - $this->request = $request; | |
| 209 | - $this->helpers = $helpers; | |
| 210 | - $this->replace_vars = $replace_vars; | |
| 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; | |
| 211 | 242 | } |
| 212 | 243 | |
| 213 | 244 | /** |
| 214 | 245 | * Registers the appropriate hooks to show the SEO metadata on the frontend. |
| @@ -214,10 +245,14 @@ | ||
| 214 | 245 | * Registers the appropriate hooks to show the SEO metadata on the frontend. |
| 215 | 246 | * |
| 216 | 247 | * Removes some actions to remove metadata that WordPress shows on the frontend, |
| 217 | 248 | * to avoid duplicate and/or mismatched metadata. |
| 249 | + * | |
| 250 | + * @return void | |
| 218 | 251 | */ |
| 219 | 252 | public function register_hooks() { |
| 253 | + \add_filter( 'render_block', [ $this, 'query_loop_next_prev' ], 1, 2 ); | |
| 254 | + | |
| 220 | 255 | \add_action( 'wp_head', [ $this, 'call_wpseo_head' ], 1 ); |
| 221 | 256 | // Filter the title for compatibility with other plugins and themes. |
| 222 | 257 | \add_filter( 'wp_title', [ $this, 'filter_title' ], 15 ); |
| 223 | 258 | // Filter the title for compatibility with block-based themes. |
| @@ -226,8 +261,9 @@ | ||
| 226 | 261 | // Removes our robots presenter from the list when wp_robots is handling this. |
| 227 | 262 | \add_filter( 'wpseo_frontend_presenter_classes', [ $this, 'filter_robots_presenter' ] ); |
| 228 | 263 | |
| 229 | 264 | \add_action( 'wpseo_head', [ $this, 'present_head' ], -9999 ); |
| 265 | + \add_action( 'wpseo_head', [ $this, 'update_outdated_permalink' ], -10_000 ); | |
| 230 | 266 | |
| 231 | 267 | \remove_action( 'wp_head', 'rel_canonical' ); |
| 232 | 268 | \remove_action( 'wp_head', 'index_rel_link' ); |
| 233 | 269 | \remove_action( 'wp_head', 'start_post_rel_link' ); |
| @@ -260,13 +296,134 @@ | ||
| 260 | 296 | return $title; |
| 261 | 297 | } |
| 262 | 298 | |
| 263 | 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() { | |
| 307 | + $dynamic_permalinks_conditional = new Dynamic_Product_Permalinks_Conditional(); | |
| 308 | + if ( ! $dynamic_permalinks_conditional->is_met() ) { | |
| 309 | + return; | |
| 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 ) { | |
| 349 | + if ( $block['blockName'] === 'core/query' ) { | |
| 350 | + // Check that the query does not inherit the main query. | |
| 351 | + if ( isset( $block['attrs']['query']['inherit'] ) && ! $block['attrs']['query']['inherit'] ) { | |
| 352 | + \add_filter( 'wpseo_adjacent_rel_url', [ $this, 'adjacent_rel_url' ], 1, 3 ); | |
| 353 | + } | |
| 354 | + } | |
| 355 | + | |
| 356 | + if ( $block['blockName'] === 'core/query-pagination-next' ) { | |
| 357 | + $this->next = $html; | |
| 358 | + } | |
| 359 | + | |
| 360 | + if ( $block['blockName'] === 'core/query-pagination-previous' ) { | |
| 361 | + $this->prev = $html; | |
| 362 | + } | |
| 363 | + | |
| 364 | + return $html; | |
| 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 ) { | |
| 379 | + // Prioritize existing prev and next links. | |
| 380 | + if ( $link ) { | |
| 381 | + return $link; | |
| 382 | + } | |
| 383 | + | |
| 384 | + // Safety check for rel value. | |
| 385 | + if ( $rel !== 'next' && $rel !== 'prev' ) { | |
| 386 | + return $link; | |
| 387 | + } | |
| 388 | + | |
| 389 | + // Check $this->next or $this->prev for existing links. | |
| 390 | + if ( $this->$rel === null ) { | |
| 391 | + return $link; | |
| 392 | + } | |
| 393 | + | |
| 394 | + $processor = new WP_HTML_Tag_Processor( $this->$rel ); | |
| 395 | + | |
| 396 | + if ( ! $processor->next_tag( [ 'tag_name' => 'a' ] ) ) { | |
| 397 | + return $link; | |
| 398 | + } | |
| 399 | + | |
| 400 | + $href = $processor->get_attribute( 'href' ); | |
| 401 | + | |
| 402 | + if ( ! $href ) { | |
| 403 | + return $link; | |
| 404 | + } | |
| 405 | + | |
| 406 | + // Safety check for full url, not expected. | |
| 407 | + if ( \strpos( $href, 'http' ) === 0 ) { | |
| 408 | + return $href; | |
| 409 | + } | |
| 410 | + | |
| 411 | + // Check if $href is relative and append last part of the url to permalink. | |
| 412 | + if ( \strpos( $href, '/' ) === 0 ) { | |
| 413 | + $href_parts = \explode( '/', $href ); | |
| 414 | + return $presentation->permalink . \end( $href_parts ); | |
| 415 | + } | |
| 416 | + | |
| 417 | + return $link; | |
| 418 | + } | |
| 419 | + | |
| 420 | + /** | |
| 264 | 421 | * Filters our robots presenter, but only when wp_robots is attached to the wp_head action. |
| 265 | 422 | * |
| 266 | - * @param array $presenters The presenters for current page. | |
| 423 | + * @param array<string> $presenters The presenters for current page. | |
| 267 | 424 | * |
| 268 | - * @return array The filtered presenters. | |
| 425 | + * @return array<string> The filtered presenters. | |
| 269 | 426 | */ |
| 270 | 427 | public function filter_robots_presenter( $presenters ) { |
| 271 | 428 | if ( ! \function_exists( 'wp_robots' ) ) { |
| 272 | 429 | return $presenters; |
| @@ -275,9 +432,9 @@ | ||
| 275 | 432 | if ( ! \has_action( 'wp_head', 'wp_robots' ) ) { |
| 276 | 433 | return $presenters; |
| 277 | 434 | } |
| 278 | 435 | |
| 279 | - if ( $this->request->is_rest_request() ) { | |
| 436 | + if ( \wp_is_serving_rest_request() ) { | |
| 280 | 437 | return $presenters; |
| 281 | 438 | } |
| 282 | 439 | |
| 283 | 440 | return \array_diff( $presenters, [ 'Yoast\\WP\\SEO\\Presenters\\Robots_Presenter' ] ); |
| @@ -286,8 +443,10 @@ | ||
| 286 | 443 | /** |
| 287 | 444 | * Presents the head in the front-end. Resets wp_query if it's not the main query. |
| 288 | 445 | * |
| 289 | 446 | * @codeCoverageIgnore It just calls a WordPress function. |
| 447 | + * | |
| 448 | + * @return void | |
| 290 | 449 | */ |
| 291 | 450 | public function call_wpseo_head() { |
| 292 | 451 | global $wp_query; |
| 293 | 452 | |
| @@ -302,8 +461,10 @@ | ||
| 302 | 461 | } |
| 303 | 462 | |
| 304 | 463 | /** |
| 305 | 464 | * Echoes all applicable presenters for a page. |
| 465 | + * | |
| 466 | + * @return void | |
| 306 | 467 | */ |
| 307 | 468 | public function present_head() { |
| 308 | 469 | $context = $this->context_memoizer->for_current_page(); |
| 309 | 470 | $presenters = $this->get_presenters( $context->page_type, $context ); |
| @@ -310,9 +471,10 @@ | ||
| 310 | 471 | |
| 311 | 472 | /** |
| 312 | 473 | * Filter 'wpseo_frontend_presentation' - Allow filtering the presentation used to output our meta values. |
| 313 | 474 | * |
| 314 | - * @api Indexable_Presention The indexable presentation. | |
| 475 | + * @param Indexable_Presentation $presentation The indexable presentation. | |
| 476 | + * @param Meta_Tags_Context $context The meta tags context for the current page. | |
| 315 | 477 | */ |
| 316 | 478 | $presentation = \apply_filters( 'wpseo_frontend_presentation', $context->presentation, $context ); |
| 317 | 479 | |
| 318 | 480 | echo \PHP_EOL; |
| @@ -338,15 +500,13 @@ | ||
| 338 | 500 | * |
| 339 | 501 | * @return Abstract_Indexable_Presenter[] The presenters. |
| 340 | 502 | */ |
| 341 | 503 | public function get_presenters( $page_type, $context = null ) { |
| 342 | - if ( \is_null( $context ) ) { | |
| 343 | - $context = $this->context_memoizer->for_current_page(); | |
| 344 | - } | |
| 504 | + $context ??= $this->context_memoizer->for_current_page(); | |
| 345 | 505 | |
| 346 | 506 | $needed_presenters = $this->get_needed_presenters( $page_type ); |
| 347 | 507 | |
| 348 | - $callback = static function( $presenter ) { | |
| 508 | + $callback = static function ( $presenter ) { | |
| 349 | 509 | if ( ! \class_exists( $presenter ) ) { |
| 350 | 510 | return null; |
| 351 | 511 | } |
| 352 | 512 | return new $presenter(); |
| @@ -355,12 +515,10 @@ | ||
| 355 | 515 | |
| 356 | 516 | /** |
| 357 | 517 | * Filter 'wpseo_frontend_presenters' - Allow filtering the presenter instances in or out of the request. |
| 358 | 518 | * |
| 359 | - * @param array $presenters The presenters. | |
| 360 | - * @param Meta_Tags_Context $context The meta tags context for the current page. | |
| 361 | - * | |
| 362 | - * @api Abstract_Indexable_Presenter[] List of presenter instances. | |
| 519 | + * @param Abstract_Indexable_Presenter[] $presenters List of presenter instances. | |
| 520 | + * @param Meta_Tags_Context $context The meta tags context for the current page. | |
| 363 | 521 | */ |
| 364 | 522 | $presenter_instances = \apply_filters( 'wpseo_frontend_presenters', $presenters, $context ); |
| 365 | 523 | |
| 366 | 524 | if ( ! \is_array( $presenter_instances ) ) { |
| @@ -374,9 +532,9 @@ | ||
| 374 | 532 | |
| 375 | 533 | return \array_merge( |
| 376 | 534 | [ new Marker_Open_Presenter() ], |
| 377 | 535 | $presenter_instances, |
| 378 | - [ new Marker_Close_Presenter() ] | |
| 536 | + [ new Marker_Close_Presenter() ], | |
| 379 | 537 | ); |
| 380 | 538 | } |
| 381 | 539 | |
| 382 | 540 | /** |
| @@ -388,12 +546,9 @@ | ||
| 388 | 546 | */ |
| 389 | 547 | private function get_needed_presenters( $page_type ) { |
| 390 | 548 | $presenters = $this->get_presenters_for_page_type( $page_type ); |
| 391 | 549 | |
| 392 | - if ( ! \get_theme_support( 'title-tag' ) && ! $this->options->get( 'forcerewritetitle', false ) ) { | |
| 393 | - // Remove the title presenter if the theme is hardcoded to output a title tag so we don't have two title tags. | |
| 394 | - $presenters = \array_diff( $presenters, [ 'Title' ] ); | |
| 395 | - } | |
| 550 | + $presenters = $this->maybe_remove_title_presenter( $presenters ); | |
| 396 | 551 | |
| 397 | 552 | $callback = static function ( $presenter ) { |
| 398 | 553 | return "Yoast\WP\SEO\Presenters\\{$presenter}_Presenter"; |
| 399 | 554 | }; |
| @@ -401,11 +556,12 @@ | ||
| 401 | 556 | |
| 402 | 557 | /** |
| 403 | 558 | * Filter 'wpseo_frontend_presenter_classes' - Allow filtering presenters in or out of the request. |
| 404 | 559 | * |
| 405 | - * @api array List of presenters. | |
| 560 | + * @param array $presenters List of presenters. | |
| 561 | + * @param string $page_type The current page type. | |
| 406 | 562 | */ |
| 407 | - $presenters = \apply_filters( 'wpseo_frontend_presenter_classes', $presenters ); | |
| 563 | + $presenters = \apply_filters( 'wpseo_frontend_presenter_classes', $presenters, $page_type ); | |
| 408 | 564 | |
| 409 | 565 | return $presenters; |
| 410 | 566 | } |
| 411 | 567 | |
| @@ -434,8 +590,13 @@ | ||
| 434 | 590 | if ( ! \in_array( $page_type, [ 'Post_Type', 'Static_Home_Page' ], true ) ) { |
| 435 | 591 | $presenters = \array_diff( $presenters, $this->singular_presenters ); |
| 436 | 592 | } |
| 437 | 593 | |
| 594 | + // Filter out `twitter:data` presenters for static home pages. | |
| 595 | + if ( $page_type === 'Static_Home_Page' ) { | |
| 596 | + $presenters = \array_diff( $presenters, $this->slack_presenters ); | |
| 597 | + } | |
| 598 | + | |
| 438 | 599 | return $presenters; |
| 439 | 600 | } |
| 440 | 601 | |
| 441 | 602 | /** |
| @@ -455,6 +616,36 @@ | ||
| 455 | 616 | $presenters = \array_merge( $presenters, $this->slack_presenters ); |
| 456 | 617 | } |
| 457 | 618 | |
| 458 | 619 | return \array_merge( $presenters, $this->closing_presenters ); |
| 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() { | |
| 628 | + return ! \get_theme_support( 'title-tag' ) && ! $this->options->get( 'forcerewritetitle', false ); | |
| 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; | |
| 459 | 650 | } |
| 460 | 651 | } |