no wp
This commit is contained in:
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Adds actions that were previously called and are now deprecated.
|
||||
*/
|
||||
class Backwards_Compatibility implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* Represents the options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards_Compatibility constructor
|
||||
*
|
||||
* @param Options_Helper $options The options helper.
|
||||
*/
|
||||
public function __construct( Options_Helper $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
if ( $this->options->get( 'opengraph' ) === true ) {
|
||||
\add_action( 'wpseo_head', [ $this, 'call_wpseo_opengraph' ], 30 );
|
||||
}
|
||||
if ( $this->options->get( 'twitter' ) === true && \apply_filters( 'wpseo_output_twitter_card', true ) !== false ) {
|
||||
\add_action( 'wpseo_head', [ $this, 'call_wpseo_twitter' ], 40 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the old wpseo_opengraph action.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function call_wpseo_opengraph() {
|
||||
\do_action_deprecated( 'wpseo_opengraph', [], '14.0', 'wpseo_frontend_presenters' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the old wpseo_twitter action.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function call_wpseo_twitter() {
|
||||
\do_action_deprecated( 'wpseo_twitter', [], '14.0', 'wpseo_frontend_presenters' );
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Adds support for shortcodes to category and term descriptions.
|
||||
*/
|
||||
class Category_Term_Description implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_filter( 'category_description', [ $this, 'add_shortcode_support' ] );
|
||||
\add_filter( 'term_description', [ $this, 'add_shortcode_support' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds shortcode support to category and term descriptions.
|
||||
*
|
||||
* This methods wrap in output buffering to prevent shortcodes that echo stuff
|
||||
* instead of return from breaking things.
|
||||
*
|
||||
* @param string $description String to add shortcodes in.
|
||||
*
|
||||
* @return string Content with shortcodes filtered out.
|
||||
*/
|
||||
public function add_shortcode_support( $description ) {
|
||||
\ob_start();
|
||||
$description = \do_shortcode( $description );
|
||||
\ob_end_clean();
|
||||
|
||||
return $description;
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Redirect_Helper;
|
||||
use Yoast\WP\SEO\Helpers\Robots_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Class Comment_Link_Fixer.
|
||||
*/
|
||||
class Comment_Link_Fixer implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The redirects helper.
|
||||
*
|
||||
* @var Redirect_Helper
|
||||
*/
|
||||
protected $redirect;
|
||||
|
||||
/**
|
||||
* The robots helper.
|
||||
*
|
||||
* @var Robots_Helper
|
||||
*/
|
||||
protected $robots;
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Comment_Link_Fixer constructor.
|
||||
*
|
||||
* @codeCoverageIgnore It only sets depedencies.
|
||||
*
|
||||
* @param Redirect_Helper $redirect The redirect helper.
|
||||
* @param Robots_Helper $robots The robots helper.
|
||||
*/
|
||||
public function __construct(
|
||||
Redirect_Helper $redirect, Robots_Helper $robots
|
||||
) {
|
||||
$this->redirect = $redirect;
|
||||
$this->robots = $robots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
if ( $this->clean_reply_to_com() ) {
|
||||
\add_filter( 'comment_reply_link', [ $this, 'remove_reply_to_com' ] );
|
||||
\add_action( 'template_redirect', [ $this, 'replytocom_redirect' ], 1 );
|
||||
}
|
||||
|
||||
// When users view a reply to a comment, this URL parameter is set. These should never be indexed separately.
|
||||
if ( $this->get_replytocom_parameter() !== null ) {
|
||||
\add_filter( 'wpseo_robots_array', [ $this->robots, 'set_robots_no_index' ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the url contains the ?replytocom query parameter.
|
||||
*
|
||||
* @codeCoverageIgnore Wraps the filter input.
|
||||
*
|
||||
* @return string|null The value of replytocom or null if it does not exist.
|
||||
*/
|
||||
protected function get_replytocom_parameter() {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
|
||||
if ( isset( $_GET['replytocom'] ) && \is_string( $_GET['replytocom'] ) ) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
|
||||
return \sanitize_text_field( \wp_unslash( $_GET['replytocom'] ) );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the ?replytocom variable from the link, replacing it with a #comment-<number> anchor.
|
||||
*
|
||||
* @todo Should this function also allow for relative urls ?
|
||||
*
|
||||
* @param string $link The comment link as a string.
|
||||
*
|
||||
* @return string The modified link.
|
||||
*/
|
||||
public function remove_reply_to_com( $link ) {
|
||||
return \preg_replace( '`href=(["\'])(?:.*(?:\?|&|&)replytocom=(\d+)#respond)`', 'href=$1#comment-$2', $link );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects out the ?replytocom variables.
|
||||
*
|
||||
* @return bool True when redirect has been done.
|
||||
*/
|
||||
public function replytocom_redirect() {
|
||||
if ( isset( $_GET['replytocom'] ) && \is_singular() ) {
|
||||
$url = \get_permalink( $GLOBALS['post']->ID );
|
||||
$hash = \sanitize_text_field( \wp_unslash( $_GET['replytocom'] ) );
|
||||
$query_string = '';
|
||||
if ( isset( $_SERVER['QUERY_STRING'] ) ) {
|
||||
$query_string = \remove_query_arg( 'replytocom', \sanitize_text_field( \wp_unslash( $_SERVER['QUERY_STRING'] ) ) );
|
||||
}
|
||||
if ( ! empty( $query_string ) ) {
|
||||
$url .= '?' . $query_string;
|
||||
}
|
||||
$url .= '#comment-' . $hash;
|
||||
|
||||
$this->redirect->do_safe_redirect( $url, 301 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we can allow the feature that removes ?replytocom query parameters.
|
||||
*
|
||||
* @codeCoverageIgnore It just wraps a call to a filter.
|
||||
*
|
||||
* @return bool True to remove, false not to remove.
|
||||
*/
|
||||
private function clean_reply_to_com() {
|
||||
/**
|
||||
* Filter: 'wpseo_remove_reply_to_com' - Allow disabling the feature that removes ?replytocom query parameters.
|
||||
*
|
||||
* @param bool $return True to remove, false not to remove.
|
||||
*/
|
||||
return (bool) \apply_filters( 'wpseo_remove_reply_to_com', true );
|
||||
}
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Class Crawl_Cleanup_Basic.
|
||||
*/
|
||||
class Crawl_Cleanup_Basic implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
private $options_helper;
|
||||
|
||||
/**
|
||||
* Crawl Cleanup Basic integration constructor.
|
||||
*
|
||||
* @param Options_Helper $options_helper The option helper.
|
||||
*/
|
||||
public function __construct( Options_Helper $options_helper ) {
|
||||
$this->options_helper = $options_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
// Remove HTTP headers we don't want.
|
||||
\add_action( 'wp', [ $this, 'clean_headers' ], 0 );
|
||||
|
||||
if ( $this->is_true( 'remove_shortlinks' ) ) {
|
||||
// Remove shortlinks.
|
||||
\remove_action( 'wp_head', 'wp_shortlink_wp_head' );
|
||||
\remove_action( 'template_redirect', 'wp_shortlink_header', 11 );
|
||||
}
|
||||
|
||||
if ( $this->is_true( 'remove_rest_api_links' ) ) {
|
||||
// Remove REST API links.
|
||||
\remove_action( 'wp_head', 'rest_output_link_wp_head' );
|
||||
\remove_action( 'template_redirect', 'rest_output_link_header', 11 );
|
||||
}
|
||||
|
||||
if ( $this->is_true( 'remove_rsd_wlw_links' ) ) {
|
||||
// Remove RSD and WLW Manifest links.
|
||||
\remove_action( 'wp_head', 'rsd_link' );
|
||||
\remove_action( 'xmlrpc_rsd_apis', 'rest_output_rsd' );
|
||||
\remove_action( 'wp_head', 'wlwmanifest_link' );
|
||||
}
|
||||
|
||||
if ( $this->is_true( 'remove_oembed_links' ) ) {
|
||||
// Remove JSON+XML oEmbed links.
|
||||
\remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );
|
||||
}
|
||||
|
||||
if ( $this->is_true( 'remove_generator' ) ) {
|
||||
\remove_action( 'wp_head', 'wp_generator' );
|
||||
}
|
||||
|
||||
if ( $this->is_true( 'remove_emoji_scripts' ) ) {
|
||||
// Remove emoji scripts and additional stuff they cause.
|
||||
\remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
|
||||
\remove_action( 'wp_print_styles', 'print_emoji_styles' );
|
||||
\remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
|
||||
\remove_action( 'admin_print_styles', 'print_emoji_styles' );
|
||||
\add_filter( 'wp_resource_hints', [ $this, 'resource_hints_plain_cleanup' ], 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array The array of conditionals.
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes X-Pingback and X-Powered-By headers as they're unneeded.
|
||||
*/
|
||||
public function clean_headers() {
|
||||
if ( \headers_sent() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->is_true( 'remove_powered_by_header' ) ) {
|
||||
\header_remove( 'X-Powered-By' );
|
||||
}
|
||||
if ( $this->is_true( 'remove_pingback_header' ) ) {
|
||||
\header_remove( 'X-Pingback' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the core s.w.org hint as it's only used for emoji stuff we don't use.
|
||||
*
|
||||
* @param array $hints The hints we're adding to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function resource_hints_plain_cleanup( $hints ) {
|
||||
foreach ( $hints as $key => $hint ) {
|
||||
if ( \is_array( $hint ) && isset( $hint['href'] ) ) {
|
||||
if ( \strpos( $hint['href'], '//s.w.org' ) !== false ) {
|
||||
unset( $hints[ $key ] );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( \strpos( $hint, '//s.w.org' ) !== false ) {
|
||||
unset( $hints[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value of an option is set to true.
|
||||
*
|
||||
* @param string $option_name The option name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_true( $option_name ) {
|
||||
return $this->options_helper->get( $option_name ) === true;
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Adds actions that cleanup unwanted rss feed links.
|
||||
*/
|
||||
class Crawl_Cleanup_Rss implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
private $options_helper;
|
||||
|
||||
/**
|
||||
* Crawl Cleanup RSS integration constructor.
|
||||
*
|
||||
* @param Options_Helper $options_helper The option helper.
|
||||
*/
|
||||
public function __construct( Options_Helper $options_helper ) {
|
||||
$this->options_helper = $options_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based on which this loadable should be active.
|
||||
*
|
||||
* @return array The conditionals.
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register our RSS related hooks.
|
||||
*/
|
||||
public function register_hooks() {
|
||||
if ( $this->is_true( 'remove_feed_global' ) ) {
|
||||
\add_action( 'feed_links_show_posts_feed', '__return_false' );
|
||||
}
|
||||
|
||||
if ( $this->is_true( 'remove_feed_global_comments' ) ) {
|
||||
\add_action( 'feed_links_show_comments_feed', '__return_false' );
|
||||
}
|
||||
|
||||
\add_action( 'wp', [ $this, 'maybe_disable_feeds' ] );
|
||||
\add_action( 'wp', [ $this, 'maybe_redirect_feeds' ], -10000 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable feeds on selected cases.
|
||||
*/
|
||||
public function maybe_disable_feeds() {
|
||||
if ( \is_singular() && $this->is_true( 'remove_feed_post_comments' )
|
||||
|| ( \is_author() && $this->is_true( 'remove_feed_authors' ) )
|
||||
|| ( \is_category() && $this->is_true( 'remove_feed_categories' ) )
|
||||
|| ( \is_tag() && $this->is_true( 'remove_feed_tags' ) )
|
||||
|| ( \is_tax() && $this->is_true( 'remove_feed_custom_taxonomies' ) )
|
||||
|| ( \is_post_type_archive() && $this->is_true( 'remove_feed_post_types' ) )
|
||||
|| ( \is_search() && $this->is_true( 'remove_feed_search' ) ) ) {
|
||||
\remove_action( 'wp_head', 'feed_links_extra', 3 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect feeds we don't want away.
|
||||
*/
|
||||
public function maybe_redirect_feeds() {
|
||||
global $wp_query;
|
||||
|
||||
if ( ! \is_feed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( \in_array( \get_query_var( 'feed' ), [ 'atom', 'rdf' ], true ) && $this->is_true( 'remove_atom_rdf_feeds' ) ) {
|
||||
$this->redirect_feed( \home_url(), 'We disable Atom/RDF feeds for performance reasons.' );
|
||||
}
|
||||
|
||||
// Only if we're on the global feed, the query is _just_ `'feed' => 'feed'`, hence this check.
|
||||
if ( ( $wp_query->query === [ 'feed' => 'feed' ]
|
||||
|| $wp_query->query === [ 'feed' => 'atom' ]
|
||||
|| $wp_query->query === [ 'feed' => 'rdf' ] )
|
||||
&& $this->is_true( 'remove_feed_global' ) ) {
|
||||
$this->redirect_feed( \home_url(), 'We disable the RSS feed for performance reasons.' );
|
||||
}
|
||||
|
||||
if ( \is_comment_feed() && ! ( \is_singular() || \is_attachment() ) && $this->is_true( 'remove_feed_global_comments' ) ) {
|
||||
$this->redirect_feed( \home_url(), 'We disable comment feeds for performance reasons.' );
|
||||
}
|
||||
elseif ( \is_comment_feed()
|
||||
&& \is_singular()
|
||||
&& ( $this->is_true( 'remove_feed_post_comments' ) || $this->is_true( 'remove_feed_global_comments' ) ) ) {
|
||||
$url = \get_permalink( \get_queried_object() );
|
||||
$this->redirect_feed( $url, 'We disable post comment feeds for performance reasons.' );
|
||||
}
|
||||
|
||||
if ( \is_author() && $this->is_true( 'remove_feed_authors' ) ) {
|
||||
$author_id = (int) \get_query_var( 'author' );
|
||||
$url = \get_author_posts_url( $author_id );
|
||||
$this->redirect_feed( $url, 'We disable author feeds for performance reasons.' );
|
||||
}
|
||||
|
||||
if ( ( \is_category() && $this->is_true( 'remove_feed_categories' ) )
|
||||
|| ( \is_tag() && $this->is_true( 'remove_feed_tags' ) )
|
||||
|| ( \is_tax() && $this->is_true( 'remove_feed_custom_taxonomies' ) ) ) {
|
||||
$term = \get_queried_object();
|
||||
$url = \get_term_link( $term, $term->taxonomy );
|
||||
if ( \is_wp_error( $url ) ) {
|
||||
$url = \home_url();
|
||||
}
|
||||
$this->redirect_feed( $url, 'We disable taxonomy feeds for performance reasons.' );
|
||||
}
|
||||
|
||||
if ( ( \is_post_type_archive() ) && $this->is_true( 'remove_feed_post_types' ) ) {
|
||||
$url = \get_post_type_archive_link( $this->get_queried_post_type() );
|
||||
$this->redirect_feed( $url, 'We disable post type feeds for performance reasons.' );
|
||||
}
|
||||
|
||||
if ( \is_search() && $this->is_true( 'remove_feed_search' ) ) {
|
||||
$url = \trailingslashit( \home_url() ) . '?s=' . \get_search_query();
|
||||
$this->redirect_feed( $url, 'We disable search RSS feeds for performance reasons.' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a cache control header.
|
||||
*
|
||||
* @param int $expiration The expiration time.
|
||||
*/
|
||||
public function cache_control_header( $expiration ) {
|
||||
\header_remove( 'Expires' );
|
||||
|
||||
// The cacheability of the current request. 'public' allows caching, 'private' would not allow caching by proxies like CloudFlare.
|
||||
$cacheability = 'public';
|
||||
$format = '%1$s, max-age=%2$d, s-maxage=%2$d, stale-while-revalidate=120, stale-if-error=14400';
|
||||
|
||||
if ( \is_user_logged_in() ) {
|
||||
$expiration = 0;
|
||||
$cacheability = 'private';
|
||||
$format = '%1$s, max-age=%2$d';
|
||||
}
|
||||
|
||||
\header( \sprintf( 'Cache-Control: ' . $format, $cacheability, $expiration ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect a feed result to somewhere else.
|
||||
*
|
||||
* @param string $url The location we're redirecting to.
|
||||
* @param string $reason The reason we're redirecting.
|
||||
*/
|
||||
private function redirect_feed( $url, $reason ) {
|
||||
\header_remove( 'Content-Type' );
|
||||
\header_remove( 'Last-Modified' );
|
||||
|
||||
$this->cache_control_header( 7 * \DAY_IN_SECONDS );
|
||||
|
||||
\wp_safe_redirect( $url, 301, 'Yoast SEO: ' . $reason );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the queried post type.
|
||||
*
|
||||
* @return string The queried post type.
|
||||
*/
|
||||
private function get_queried_post_type() {
|
||||
$post_type = \get_query_var( 'post_type' );
|
||||
if ( \is_array( $post_type ) ) {
|
||||
$post_type = \reset( $post_type );
|
||||
}
|
||||
return $post_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the value of an option is set to true.
|
||||
*
|
||||
* @param string $option_name The option name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_true( $option_name ) {
|
||||
return $this->options_helper->get( $option_name ) === true;
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use WP_Query;
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Helpers\Redirect_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Class Crawl_Cleanup_Searches.
|
||||
*/
|
||||
class Crawl_Cleanup_Searches implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* Patterns to match against to find spam.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $patterns = [
|
||||
'/[:()【】[]]+/u',
|
||||
'/(TALK|QQ)\:/iu',
|
||||
];
|
||||
|
||||
/**
|
||||
* The options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
private $options_helper;
|
||||
|
||||
/**
|
||||
* The redirect helper.
|
||||
*
|
||||
* @var Redirect_Helper
|
||||
*/
|
||||
private $redirect_helper;
|
||||
|
||||
/**
|
||||
* Crawl_Cleanup_Searches integration constructor.
|
||||
*
|
||||
* @param Options_Helper $options_helper The option helper.
|
||||
* @param Redirect_Helper $redirect_helper The redirect helper.
|
||||
*/
|
||||
public function __construct( Options_Helper $options_helper, Redirect_Helper $redirect_helper ) {
|
||||
$this->options_helper = $options_helper;
|
||||
$this->redirect_helper = $redirect_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
if ( $this->options_helper->get( 'search_cleanup' ) ) {
|
||||
\add_filter( 'pre_get_posts', [ $this, 'validate_search' ] );
|
||||
}
|
||||
if ( $this->options_helper->get( 'redirect_search_pretty_urls' ) && ! empty( \get_option( 'permalink_structure' ) ) ) {
|
||||
\add_action( 'template_redirect', [ $this, 'maybe_redirect_searches' ], 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array The array of conditionals.
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we want to allow this search to happen.
|
||||
*
|
||||
* @param WP_Query $query The main query.
|
||||
*
|
||||
* @return WP_Query
|
||||
*/
|
||||
public function validate_search( WP_Query $query ) {
|
||||
if ( ! $query->is_search() ) {
|
||||
return $query;
|
||||
}
|
||||
// First check against emoji and patterns we might not want.
|
||||
$this->check_unwanted_patterns( $query );
|
||||
|
||||
// Then limit characters if still needed.
|
||||
$this->limit_characters();
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect pretty search URLs to the "raw" equivalent
|
||||
*/
|
||||
public function maybe_redirect_searches() {
|
||||
if ( ! \is_search() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput
|
||||
if ( isset( $_SERVER['REQUEST_URI'] ) && \stripos( $_SERVER['REQUEST_URI'], '/search/' ) === 0 ) {
|
||||
$args = [];
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput
|
||||
$parsed = \wp_parse_url( $_SERVER['REQUEST_URI'] );
|
||||
|
||||
if ( ! empty( $parsed['query'] ) ) {
|
||||
\wp_parse_str( $parsed['query'], $args );
|
||||
}
|
||||
|
||||
$args['s'] = \get_search_query();
|
||||
|
||||
$proper_url = \home_url( '/' );
|
||||
|
||||
if ( \intval( \get_query_var( 'paged' ) ) > 1 ) {
|
||||
$proper_url .= \sprintf( 'page/%s/', \get_query_var( 'paged' ) );
|
||||
unset( $args['paged'] );
|
||||
}
|
||||
|
||||
$proper_url = \add_query_arg( \array_map( 'rawurlencode_deep', $args ), $proper_url );
|
||||
|
||||
if ( ! empty( $parsed['fragment'] ) ) {
|
||||
$proper_url .= '#' . \rawurlencode( $parsed['fragment'] );
|
||||
}
|
||||
|
||||
$this->redirect_away( 'We redirect pretty URLs to the raw format.', $proper_url );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check query against unwanted search patterns.
|
||||
*
|
||||
* @param WP_Query $query The main WordPress query.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function check_unwanted_patterns( WP_Query $query ) {
|
||||
$s = \rawurldecode( $query->query_vars['s'] );
|
||||
if ( $this->options_helper->get( 'search_cleanup_emoji' ) && $this->has_emoji( $s ) ) {
|
||||
$this->redirect_away( 'We don\'t allow searches with emojis and other special characters.' );
|
||||
}
|
||||
|
||||
if ( ! $this->options_helper->get( 'search_cleanup_patterns' ) ) {
|
||||
return;
|
||||
}
|
||||
foreach ( $this->patterns as $pattern ) {
|
||||
$outcome = \preg_match( $pattern, $s, $matches );
|
||||
if ( $outcome && $matches !== [] ) {
|
||||
$this->redirect_away( 'Your search matched a common spam pattern.' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the homepage for invalid searches.
|
||||
*
|
||||
* @param string $reason The reason for redirecting away.
|
||||
* @param string $to_url The URL to redirect to.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function redirect_away( $reason, $to_url = '' ) {
|
||||
if ( empty( $to_url ) ) {
|
||||
$to_url = \get_home_url();
|
||||
}
|
||||
|
||||
$this->redirect_helper->do_safe_redirect( $to_url, 301, 'Yoast Search Filtering: ' . $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the number of characters in the search query.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function limit_characters() {
|
||||
// We retrieve the search term unescaped because we want to count the characters properly. We make sure to escape it afterwards, if we do something with it.
|
||||
$unescaped_s = \get_search_query( false );
|
||||
|
||||
// We then unslash the search term, again because we want to count the characters properly. We make sure to slash it afterwards, if we do something with it.
|
||||
$raw_s = \wp_unslash( $unescaped_s );
|
||||
if ( \mb_strlen( $raw_s, 'UTF-8' ) > $this->options_helper->get( 'search_character_limit' ) ) {
|
||||
$new_s = \mb_substr( $raw_s, 0, $this->options_helper->get( 'search_character_limit' ), 'UTF-8' );
|
||||
\set_query_var( 's', \wp_slash( \esc_attr( $new_s ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a text string contains an emoji or not.
|
||||
*
|
||||
* @param string $text The text string to detect emoji in.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function has_emoji( $text ) {
|
||||
$emojis_regex = '/([^-\p{L}\x00-\x7F]+)/u';
|
||||
\preg_match( $emojis_regex, $text, $matches );
|
||||
|
||||
return ! empty( $matches );
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
use Yoast\WP\SEO\Surfaces\Meta_Surface;
|
||||
|
||||
/**
|
||||
* Class Feed_Improvements
|
||||
*/
|
||||
class Feed_Improvements implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* Holds the options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Holds the meta helper surface.
|
||||
*
|
||||
* @var Meta_Surface
|
||||
*/
|
||||
private $meta;
|
||||
|
||||
/**
|
||||
* Canonical_Header constructor.
|
||||
*
|
||||
* @codeCoverageIgnore It only sets depedencies.
|
||||
*
|
||||
* @param Options_Helper $options The options helper.
|
||||
* @param Meta_Surface $meta The meta surface.
|
||||
*/
|
||||
public function __construct(
|
||||
Options_Helper $options,
|
||||
Meta_Surface $meta
|
||||
) {
|
||||
$this->options = $options;
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers hooks to WordPress.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_filter( 'get_bloginfo_rss', [ $this, 'filter_bloginfo_rss' ], 10, 2 );
|
||||
\add_filter( 'document_title_separator', [ $this, 'filter_document_title_separator' ] );
|
||||
|
||||
\add_action( 'do_feed_rss', [ $this, 'handle_rss_feed' ], 9 );
|
||||
\add_action( 'do_feed_rss2', [ $this, 'send_canonical_header' ], 9 );
|
||||
\add_action( 'do_feed_rss2', [ $this, 'add_robots_headers' ], 9 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter `bloginfo_rss` output to give the URL for what's being shown instead of just always the homepage.
|
||||
*
|
||||
* @param string $show The output so far.
|
||||
* @param string $what What is being shown.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filter_bloginfo_rss( $show, $what ) {
|
||||
if ( $what === 'url' ) {
|
||||
return $this->get_url_for_queried_object( $show );
|
||||
}
|
||||
|
||||
return $show;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure send canonical header always runs, because this RSS hook does not support the for_comments parameter
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_rss_feed() {
|
||||
$this->send_canonical_header( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a canonical link header to the main canonical URL for the requested feed object. If it is not a comment
|
||||
* feed.
|
||||
*
|
||||
* @param bool $for_comments If the RRS feed is meant for a comment feed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_canonical_header( $for_comments ) {
|
||||
|
||||
if ( $for_comments || \headers_sent() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = $this->get_url_for_queried_object( $this->meta->for_home_page()->canonical );
|
||||
if ( ! empty( $url ) ) {
|
||||
\header( \sprintf( 'Link: <%s>; rel="canonical"', $url ), false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds noindex, follow tag for comment feeds.
|
||||
*
|
||||
* @param bool $for_comments If the RSS feed is meant for a comment feed.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_robots_headers( $for_comments ) {
|
||||
if ( $for_comments && ! \headers_sent() ) {
|
||||
\header( 'X-Robots-Tag: noindex, follow', true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the title separator set in Yoast SEO is used for all feeds.
|
||||
*
|
||||
* @param string $separator The separator from WordPress.
|
||||
*
|
||||
* @return string The separator from Yoast SEO's settings.
|
||||
*/
|
||||
public function filter_document_title_separator( $separator ) {
|
||||
return \html_entity_decode( $this->options->get_title_separator() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the main URL for the queried object.
|
||||
*
|
||||
* @param string $url The URL determined so far.
|
||||
*
|
||||
* @return string The canonical URL for the queried object.
|
||||
*/
|
||||
protected function get_url_for_queried_object( $url = '' ) {
|
||||
$queried_object = \get_queried_object();
|
||||
// Don't call get_class with null. This gives a warning.
|
||||
$class = ( $queried_object !== null ) ? \get_class( $queried_object ) : null;
|
||||
|
||||
switch ( $class ) {
|
||||
// Post type archive feeds.
|
||||
case 'WP_Post_Type':
|
||||
$url = $this->meta->for_post_type_archive( $queried_object->name )->canonical;
|
||||
break;
|
||||
// Post comment feeds.
|
||||
case 'WP_Post':
|
||||
$url = $this->meta->for_post( $queried_object->ID )->canonical;
|
||||
break;
|
||||
// Term feeds.
|
||||
case 'WP_Term':
|
||||
$url = $this->meta->for_term( $queried_object->term_id )->canonical;
|
||||
break;
|
||||
// Author feeds.
|
||||
case 'WP_User':
|
||||
$url = $this->meta->for_author( $queried_object->ID )->canonical;
|
||||
break;
|
||||
// This would be NULL on the home page and on date archive feeds.
|
||||
case null:
|
||||
$url = $this->meta->for_home_page()->canonical;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
use Yoast\WP\SEO\Wrappers\WP_Query_Wrapper;
|
||||
|
||||
/**
|
||||
* Class Force_Rewrite_Title.
|
||||
*/
|
||||
class Force_Rewrite_Title implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Toggle indicating whether output buffering has been started.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $ob_started = false;
|
||||
|
||||
/**
|
||||
* The WP Query wrapper.
|
||||
*
|
||||
* @var WP_Query_Wrapper
|
||||
*/
|
||||
private $wp_query;
|
||||
|
||||
/**
|
||||
* Sets the helpers.
|
||||
*
|
||||
* @codeCoverageIgnore It just handles dependencies.
|
||||
*
|
||||
* @param Options_Helper $options Options helper.
|
||||
* @param WP_Query_Wrapper $wp_query WP query wrapper.
|
||||
*/
|
||||
public function __construct( Options_Helper $options, WP_Query_Wrapper $wp_query ) {
|
||||
$this->options = $options;
|
||||
$this->wp_query = $wp_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
// When the option is disabled.
|
||||
if ( ! $this->options->get( 'forcerewritetitle', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For WordPress versions below 4.4.
|
||||
if ( \current_theme_supports( 'title-tag' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
\add_action( 'template_redirect', [ $this, 'force_rewrite_output_buffer' ], 99999 );
|
||||
\add_action( 'wp_footer', [ $this, 'flush_cache' ], -1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in the force rewrite functionality this retrieves the output, replaces the title with the proper SEO
|
||||
* title and then flushes the output.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function flush_cache() {
|
||||
if ( $this->ob_started !== true ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $this->get_buffered_output();
|
||||
|
||||
$old_wp_query = $this->wp_query->get_query();
|
||||
|
||||
\wp_reset_query();
|
||||
|
||||
// When the file has the debug mark.
|
||||
if ( \preg_match( '/(?\'before\'.*)<!-- This site is optimized with the Yoast SEO.*<!-- \/ Yoast SEO( Premium)? plugin. -->(?\'after\'.*)/is', $content, $matches ) ) {
|
||||
$content = $this->replace_titles_from_content( $content, $matches );
|
||||
|
||||
unset( $matches );
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.WP.GlobalVariablesOverride -- The query gets reset here with the original query.
|
||||
$GLOBALS['wp_query'] = $old_wp_query;
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput -- The output should already have been escaped, we are only filtering it.
|
||||
echo $content;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the output buffer so it can later be fixed by flush_cache().
|
||||
*/
|
||||
public function force_rewrite_output_buffer() {
|
||||
$this->ob_started = true;
|
||||
$this->start_output_buffering();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the titles from the parts that contains a title.
|
||||
*
|
||||
* @param string $content The content to remove the titles from.
|
||||
* @param array $parts_with_title The parts containing a title.
|
||||
*
|
||||
* @return string The modified content.
|
||||
*/
|
||||
protected function replace_titles_from_content( $content, $parts_with_title ) {
|
||||
if ( isset( $parts_with_title['before'] ) && \is_string( $parts_with_title['before'] ) ) {
|
||||
$content = $this->replace_title( $parts_with_title['before'], $content );
|
||||
}
|
||||
|
||||
if ( isset( $parts_with_title['after'] ) ) {
|
||||
$content = $this->replace_title( $parts_with_title['after'], $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the title from the part that contains the title and put this modified part back
|
||||
* into the content.
|
||||
*
|
||||
* @param string $part_with_title The part with the title that needs to be replaced.
|
||||
* @param string $content The entire content.
|
||||
*
|
||||
* @return string The altered content.
|
||||
*/
|
||||
protected function replace_title( $part_with_title, $content ) {
|
||||
$part_without_title = \preg_replace( '/<title.*?\/title>/i', '', $part_with_title );
|
||||
|
||||
return \str_replace( $part_with_title, $part_without_title, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the output buffering.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function start_output_buffering() {
|
||||
\ob_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the buffered output.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return false|string The buffered output.
|
||||
*/
|
||||
protected function get_buffered_output() {
|
||||
return \ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
use Yoast\WP\SEO\Wrappers\WP_Query_Wrapper;
|
||||
|
||||
/**
|
||||
* Handles intercepting requests.
|
||||
*/
|
||||
class Handle_404 implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The WP Query wrapper.
|
||||
*
|
||||
* @var WP_Query_Wrapper
|
||||
*/
|
||||
private $query_wrapper;
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_filter( 'pre_handle_404', [ $this, 'handle_404' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle_404 constructor.
|
||||
*
|
||||
* @codeCoverageIgnore Handles dependencies.
|
||||
*
|
||||
* @param WP_Query_Wrapper $query_wrapper The query wrapper.
|
||||
*/
|
||||
public function __construct( WP_Query_Wrapper $query_wrapper ) {
|
||||
$this->query_wrapper = $query_wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the 404 status code.
|
||||
*
|
||||
* @param bool $handled Whether we've handled the request.
|
||||
*
|
||||
* @return bool True if it's 404.
|
||||
*/
|
||||
public function handle_404( $handled ) {
|
||||
if ( ! $this->is_feed_404() ) {
|
||||
return $handled;
|
||||
}
|
||||
|
||||
$this->set_404();
|
||||
$this->set_headers();
|
||||
|
||||
\add_filter( 'old_slug_redirect_url', '__return_false' );
|
||||
\add_filter( 'redirect_canonical', '__return_false' );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there are no posts in a feed, make it 404 instead of sending an empty RSS feed.
|
||||
*
|
||||
* @return bool True if it's 404.
|
||||
*/
|
||||
protected function is_feed_404() {
|
||||
if ( ! \is_feed() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$wp_query = $this->query_wrapper->get_query();
|
||||
|
||||
// Don't 404 if the query contains post(s) or an object.
|
||||
if ( $wp_query->posts || $wp_query->get_queried_object() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't 404 if it isn't archive or singular.
|
||||
if ( ! $wp_query->is_archive() && ! $wp_query->is_singular() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the 404 status code.
|
||||
*/
|
||||
protected function set_404() {
|
||||
$wp_query = $this->query_wrapper->get_query();
|
||||
$wp_query->is_feed = false;
|
||||
$wp_query->set_404();
|
||||
$this->query_wrapper->set_query( $wp_query );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the headers for http.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function set_headers() {
|
||||
// Overwrite Content-Type header.
|
||||
if ( ! \headers_sent() ) {
|
||||
\header( 'Content-Type: ' . \get_option( 'html_type' ) . '; charset=' . \get_option( 'blog_charset' ) );
|
||||
}
|
||||
|
||||
\status_header( 404 );
|
||||
\nocache_headers();
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Robots_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Class Indexing_Controls.
|
||||
*/
|
||||
class Indexing_Controls implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The robots helper.
|
||||
*
|
||||
* @var Robots_Helper
|
||||
*/
|
||||
protected $robots;
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*
|
||||
* @codeCoverageIgnore Sets the dependencies.
|
||||
*
|
||||
* @param Robots_Helper $robots The robots helper.
|
||||
*/
|
||||
public function __construct( Robots_Helper $robots ) {
|
||||
$this->robots = $robots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
// The option `blog_public` is set in Settings > Reading > Search Engine Visibility.
|
||||
if ( (string) \get_option( 'blog_public' ) === '0' ) {
|
||||
\add_filter( 'wpseo_robots_array', [ $this->robots, 'set_robots_no_index' ] );
|
||||
}
|
||||
|
||||
\add_action( 'template_redirect', [ $this, 'noindex_robots' ] );
|
||||
\add_filter( 'loginout', [ $this, 'nofollow_link' ] );
|
||||
\add_filter( 'register', [ $this, 'nofollow_link' ] );
|
||||
|
||||
// Remove actions that we will handle through our wpseo_head call, and probably change the output of.
|
||||
\remove_action( 'wp_head', 'rel_canonical' );
|
||||
\remove_action( 'wp_head', 'index_rel_link' );
|
||||
\remove_action( 'wp_head', 'start_post_rel_link' );
|
||||
\remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head' );
|
||||
\remove_action( 'wp_head', 'noindex', 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a Robots HTTP header preventing URL from being indexed in the search results while allowing search engines
|
||||
* to follow the links in the object at the URL.
|
||||
*
|
||||
* @return bool Boolean indicating whether the noindex header was sent.
|
||||
*/
|
||||
public function noindex_robots() {
|
||||
if ( ! \is_robots() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->set_robots_header();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds rel="nofollow" to a link, only used for login / registration links.
|
||||
*
|
||||
* @param string $input The link element as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function nofollow_link( $input ) {
|
||||
return \str_replace( '<a ', '<a rel="nofollow" ', $input );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the x-robots-tag to noindex follow.
|
||||
*
|
||||
* @codeCoverageIgnore Too difficult to test.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function set_robots_header() {
|
||||
if ( \headers_sent() === false ) {
|
||||
\header( 'X-Robots-Tag: noindex, follow', true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use WP_Post;
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Conditionals\Open_Graph_Conditional;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
use Yoast\WP\SEO\Surfaces\Meta_Surface;
|
||||
|
||||
/**
|
||||
* Class Open_Graph_OEmbed.
|
||||
*/
|
||||
class Open_Graph_OEmbed implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The meta surface.
|
||||
*
|
||||
* @var Meta_Surface
|
||||
*/
|
||||
private $meta;
|
||||
|
||||
/**
|
||||
* The oEmbed data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* The post ID for the current post.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $post_id;
|
||||
|
||||
/**
|
||||
* The post meta.
|
||||
*
|
||||
* @var Meta|false
|
||||
*/
|
||||
private $post_meta;
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class, Open_Graph_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_filter( 'oembed_response_data', [ $this, 'set_oembed_data' ], 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Open_Graph_OEmbed constructor.
|
||||
*
|
||||
* @param Meta_Surface $meta The meta surface.
|
||||
*/
|
||||
public function __construct( Meta_Surface $meta ) {
|
||||
$this->meta = $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to pass to the oEmbed's response data that will enable
|
||||
* support for using the image and title set by the WordPress SEO plugin's fields. This
|
||||
* address the concern where some social channels/subscribed use oEmebed data over Open Graph data
|
||||
* if both are present.
|
||||
*
|
||||
* @link https://developer.wordpress.org/reference/hooks/oembed_response_data/ for hook info.
|
||||
*
|
||||
* @param array $data The oEmbed data.
|
||||
* @param WP_Post $post The current Post object.
|
||||
*
|
||||
* @return array An array of oEmbed data with modified values where appropriate.
|
||||
*/
|
||||
public function set_oembed_data( $data, $post ) {
|
||||
// Data to be returned.
|
||||
$this->data = $data;
|
||||
$this->post_id = $post->ID;
|
||||
$this->post_meta = $this->meta->for_post( $this->post_id );
|
||||
|
||||
if ( ! empty( $this->post_meta ) ) {
|
||||
$this->set_title();
|
||||
$this->set_description();
|
||||
$this->set_image();
|
||||
}
|
||||
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OpenGraph title if configured.
|
||||
*/
|
||||
protected function set_title() {
|
||||
$opengraph_title = $this->post_meta->open_graph_title;
|
||||
|
||||
if ( ! empty( $opengraph_title ) ) {
|
||||
$this->data['title'] = $opengraph_title;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OpenGraph description if configured.
|
||||
*/
|
||||
protected function set_description() {
|
||||
$opengraph_description = $this->post_meta->open_graph_description;
|
||||
|
||||
if ( ! empty( $opengraph_description ) ) {
|
||||
$this->data['description'] = $opengraph_description;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the image if it has been configured.
|
||||
*/
|
||||
protected function set_image() {
|
||||
$images = $this->post_meta->open_graph_images;
|
||||
|
||||
if ( ! \is_array( $images ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$image = \reset( $images );
|
||||
|
||||
if ( empty( $image ) || ! isset( $image['url'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->data['thumbnail_url'] = $image['url'];
|
||||
|
||||
if ( isset( $image['width'] ) ) {
|
||||
$this->data['thumbnail_width'] = $image['width'];
|
||||
}
|
||||
|
||||
if ( isset( $image['height'] ) ) {
|
||||
$this->data['thumbnail_height'] = $image['height'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
|
||||
use Yoast\WP\SEO\Helpers\Meta_Helper;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Helpers\Redirect_Helper;
|
||||
use Yoast\WP\SEO\Helpers\Url_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Class Redirects.
|
||||
*/
|
||||
class Redirects implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* The meta helper.
|
||||
*
|
||||
* @var Meta_Helper
|
||||
*/
|
||||
protected $meta;
|
||||
|
||||
/**
|
||||
* The current page helper.
|
||||
*
|
||||
* @var Current_Page_Helper
|
||||
*/
|
||||
protected $current_page;
|
||||
|
||||
/**
|
||||
* The redirect helper.
|
||||
*
|
||||
* @var Redirect_Helper
|
||||
*/
|
||||
private $redirect;
|
||||
|
||||
/**
|
||||
* The URL helper.
|
||||
*
|
||||
* @var Url_Helper
|
||||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* Holds the WP_Query variables we should get rid of.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $date_query_variables = [
|
||||
'year',
|
||||
'm',
|
||||
'monthnum',
|
||||
'day',
|
||||
'hour',
|
||||
'minute',
|
||||
'second',
|
||||
];
|
||||
|
||||
/**
|
||||
* Sets the helpers.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Options_Helper $options Options helper.
|
||||
* @param Meta_Helper $meta Meta helper.
|
||||
* @param Current_Page_Helper $current_page The current page helper.
|
||||
* @param Redirect_Helper $redirect The redirect helper.
|
||||
* @param Url_Helper $url The URL helper.
|
||||
*/
|
||||
public function __construct( Options_Helper $options, Meta_Helper $meta, Current_Page_Helper $current_page, Redirect_Helper $redirect, Url_Helper $url ) {
|
||||
$this->options = $options;
|
||||
$this->meta = $meta;
|
||||
$this->current_page = $current_page;
|
||||
$this->redirect = $redirect;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_action( 'wp', [ $this, 'archive_redirect' ] );
|
||||
\add_action( 'wp', [ $this, 'page_redirect' ], 99 );
|
||||
\add_action( 'wp', [ $this, 'category_redirect' ] );
|
||||
\add_action( 'template_redirect', [ $this, 'attachment_redirect' ], 1 );
|
||||
\add_action( 'template_redirect', [ $this, 'disable_date_queries' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable date queries, if they're disabled in Yoast SEO settings, to prevent indexing the wrong things.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disable_date_queries() {
|
||||
if ( $this->options->get( 'disable-date', false ) ) {
|
||||
$exploded_url = \explode( '?', $this->url->recreate_current_url(), 2 );
|
||||
list( $base_url, $query_string ) = \array_pad( $exploded_url, 2, '' );
|
||||
\parse_str( $query_string, $query_vars );
|
||||
foreach ( $this->date_query_variables as $variable ) {
|
||||
if ( \in_array( $variable, \array_keys( $query_vars ), true ) ) {
|
||||
$this->do_date_redirect( $query_vars, $base_url );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When certain archives are disabled, this redirects those to the homepage.
|
||||
*/
|
||||
public function archive_redirect() {
|
||||
if ( $this->need_archive_redirect() ) {
|
||||
$this->redirect->do_safe_redirect( \get_bloginfo( 'url' ), 301 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the redirect meta value, this function determines whether it should redirect the current post / page.
|
||||
*/
|
||||
public function page_redirect() {
|
||||
if ( ! $this->current_page->is_simple_page() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post = \get_post();
|
||||
if ( ! \is_object( $post ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$redirect = $this->meta->get_value( 'redirect', $post->ID );
|
||||
if ( $redirect === '' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->redirect->do_safe_redirect( $redirect, 301 );
|
||||
}
|
||||
|
||||
/**
|
||||
* If the option to disable attachment URLs is checked, this performs the redirect to the attachment.
|
||||
*/
|
||||
public function attachment_redirect() {
|
||||
if ( ! $this->current_page->is_attachment() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->options->get( 'disable-attachment', false ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = $this->get_attachment_url();
|
||||
if ( empty( $url ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->redirect->do_unsafe_redirect( $url, 301 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if certain archive pages are disabled to determine if a archive redirect is needed.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return bool Whether or not to redirect an archive page.
|
||||
*/
|
||||
protected function need_archive_redirect() {
|
||||
if ( $this->options->get( 'disable-date', false ) && $this->current_page->is_date_archive() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $this->options->get( 'disable-author', false ) && $this->current_page->is_author_archive() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $this->options->get( 'disable-post_format', false ) && $this->current_page->is_post_format_archive() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the attachment url for the current page.
|
||||
*
|
||||
* @codeCoverageIgnore It wraps WordPress functions.
|
||||
*
|
||||
* @return string The attachment url.
|
||||
*/
|
||||
protected function get_attachment_url() {
|
||||
/**
|
||||
* Allows the developer to change the target redirection URL for attachments.
|
||||
*
|
||||
* @api string $attachment_url The attachment URL for the queried object.
|
||||
* @api object $queried_object The queried object.
|
||||
*
|
||||
* @since 7.5.3
|
||||
*/
|
||||
return \apply_filters(
|
||||
'wpseo_attachment_redirect_url',
|
||||
\wp_get_attachment_url( \get_queried_object_id() ),
|
||||
\get_queried_object()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects away query variables that shouldn't work.
|
||||
*
|
||||
* @param array $query_vars The query variables in the current URL.
|
||||
* @param string $base_url The base URL without query string.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function do_date_redirect( $query_vars, $base_url ) {
|
||||
foreach ( $this->date_query_variables as $variable ) {
|
||||
unset( $query_vars[ $variable ] );
|
||||
}
|
||||
$url = $base_url;
|
||||
if ( \count( $query_vars ) > 0 ) {
|
||||
$url .= '?' . \http_build_query( $query_vars );
|
||||
}
|
||||
|
||||
$this->redirect->do_safe_redirect( $url, 301 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips `cat=-1` from the URL and redirects to the resulting URL.
|
||||
*/
|
||||
public function category_redirect() {
|
||||
/**
|
||||
* Allows the developer to keep cat=-1 GET parameters
|
||||
*
|
||||
* @since 19.9
|
||||
*
|
||||
* @param bool $remove_cat_parameter Whether to remove the `cat=-1` GET parameter. Default true.
|
||||
*/
|
||||
$should_remove_parameter = \apply_filters( 'wpseo_remove_cat_parameter', true );
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Data is not processed or saved.
|
||||
if ( $should_remove_parameter && isset( $_GET['cat'] ) && $_GET['cat'] === '-1' ) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Data is not processed or saved.
|
||||
unset( $_GET['cat'] );
|
||||
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is just a replace and the data is never saved.
|
||||
$_SERVER['REQUEST_URI'] = \remove_query_arg( 'cat' );
|
||||
}
|
||||
$this->redirect->do_safe_redirect( $this->url->recreate_current_url(), 301, 'Stripping cat=-1 from the URL' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,292 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use WPSEO_Sitemaps_Router;
|
||||
use Yoast\WP\SEO\Conditionals\Robots_Txt_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Helpers\Robots_Txt_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
use Yoast\WP\SEO\Presenters\Robots_Txt_Presenter;
|
||||
|
||||
/**
|
||||
* Handles adding the sitemap to the `robots.txt`.
|
||||
*/
|
||||
class Robots_Txt_Integration implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* Holds the options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
protected $options_helper;
|
||||
|
||||
/**
|
||||
* Holds the robots txt helper.
|
||||
*
|
||||
* @var Robots_Txt_Helper
|
||||
*/
|
||||
protected $robots_txt_helper;
|
||||
|
||||
/**
|
||||
* Holds the robots txt presenter.
|
||||
*
|
||||
* @var Robots_Txt_Presenter
|
||||
*/
|
||||
protected $robots_txt_presenter;
|
||||
|
||||
/**
|
||||
* Sets the helpers.
|
||||
*
|
||||
* @param Options_Helper $options_helper Options helper.
|
||||
* @param Robots_Txt_Helper $robots_txt_helper Robots txt helper.
|
||||
* @param Robots_Txt_Presenter $robots_txt_presenter Robots txt presenter.
|
||||
*/
|
||||
public function __construct( Options_Helper $options_helper, Robots_Txt_Helper $robots_txt_helper, Robots_Txt_Presenter $robots_txt_presenter ) {
|
||||
$this->options_helper = $options_helper;
|
||||
$this->robots_txt_helper = $robots_txt_helper;
|
||||
$this->robots_txt_presenter = $robots_txt_presenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Robots_Txt_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_filter( 'robots_txt', [ $this, 'filter_robots' ], 99999 );
|
||||
|
||||
if ( $this->options_helper->get( 'deny_search_crawling' ) && ! \is_multisite() ) {
|
||||
\add_action( 'Yoast\WP\SEO\register_robots_rules', [ $this, 'add_disallow_search_to_robots' ], 10, 1 );
|
||||
}
|
||||
if ( $this->options_helper->get( 'deny_wp_json_crawling' ) && ! \is_multisite() ) {
|
||||
\add_action( 'Yoast\WP\SEO\register_robots_rules', [ $this, 'add_disallow_wp_json_to_robots' ], 10, 1 );
|
||||
}
|
||||
if ( $this->options_helper->get( 'deny_adsbot_crawling' ) && ! \is_multisite() ) {
|
||||
\add_action( 'Yoast\WP\SEO\register_robots_rules', [ $this, 'add_disallow_adsbot' ], 10, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the robots.txt output.
|
||||
*
|
||||
* @param string $robots_txt The robots.txt output from WordPress.
|
||||
*
|
||||
* @return string Filtered robots.txt output.
|
||||
*/
|
||||
public function filter_robots( $robots_txt ) {
|
||||
$robots_txt = $this->remove_default_robots( $robots_txt );
|
||||
$this->maybe_add_xml_sitemap();
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_should_add_subdirectory_multisite_xml_sitemaps' - Disabling this filter removes subdirectory sites from xml sitemaps.
|
||||
*
|
||||
* @since 19.8
|
||||
*
|
||||
* @param bool $show Whether to display multisites in the xml sitemaps.
|
||||
*/
|
||||
if ( \apply_filters( 'wpseo_should_add_subdirectory_multisite_xml_sitemaps', true ) ) {
|
||||
$this->add_subdirectory_multisite_xml_sitemaps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow registering custom robots rules to be outputted within the Yoast content block in robots.txt.
|
||||
*
|
||||
* @param Robots_Txt_Helper $robots_txt_helper The Robots_Txt_Helper object.
|
||||
*/
|
||||
\do_action( 'Yoast\WP\SEO\register_robots_rules', $this->robots_txt_helper );
|
||||
|
||||
return \trim( $robots_txt . \PHP_EOL . $this->robots_txt_presenter->present() . \PHP_EOL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a disallow rule for search to robots.txt.
|
||||
*
|
||||
* @param Robots_Txt_Helper $robots_txt_helper The robots txt helper.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_disallow_search_to_robots( Robots_Txt_Helper $robots_txt_helper ) {
|
||||
$robots_txt_helper->add_disallow( '*', '/?s=' );
|
||||
$robots_txt_helper->add_disallow( '*', '/page/*/?s=' );
|
||||
$robots_txt_helper->add_disallow( '*', '/search/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a disallow rule for /wp-json/ to robots.txt.
|
||||
*
|
||||
* @param Robots_Txt_Helper $robots_txt_helper The robots txt helper.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_disallow_wp_json_to_robots( Robots_Txt_Helper $robots_txt_helper ) {
|
||||
$robots_txt_helper->add_disallow( '*', '/wp-json/' );
|
||||
$robots_txt_helper->add_disallow( '*', '/?rest_route=' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a disallow rule for AdsBot agents to robots.txt.
|
||||
*
|
||||
* @param Robots_Txt_Helper $robots_txt_helper The robots txt helper.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_disallow_adsbot( Robots_Txt_Helper $robots_txt_helper ) {
|
||||
$robots_txt_helper->add_disallow( 'AdsBot', '/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the default WordPress robots.txt output.
|
||||
*
|
||||
* @param string $robots_txt Input robots.txt.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function remove_default_robots( $robots_txt ) {
|
||||
return \preg_replace(
|
||||
'`User-agent: \*[\r\n]+Disallow: /wp-admin/[\r\n]+Allow: /wp-admin/admin-ajax\.php[\r\n]+`',
|
||||
'',
|
||||
$robots_txt
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds XML sitemap reference to robots.txt.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function maybe_add_xml_sitemap() {
|
||||
// If the XML sitemap is disabled, bail.
|
||||
if ( ! $this->options_helper->get( 'enable_xml_sitemap', false ) ) {
|
||||
return;
|
||||
}
|
||||
$this->robots_txt_helper->add_sitemap( \esc_url( WPSEO_Sitemaps_Router::get_base_url( 'sitemap_index.xml' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds subdomain multisite' XML sitemap references to robots.txt.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function add_subdirectory_multisite_xml_sitemaps() {
|
||||
// If not on a multisite subdirectory, bail.
|
||||
if ( ! \is_multisite() || \is_subdomain_install() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sitemaps_enabled = $this->get_xml_sitemaps_enabled();
|
||||
|
||||
foreach ( $sitemaps_enabled as $blog_id => $is_sitemap_enabled ) {
|
||||
if ( ! $is_sitemap_enabled ) {
|
||||
continue;
|
||||
}
|
||||
$this->robots_txt_helper->add_sitemap( \esc_url( \get_home_url( $blog_id, 'sitemap_index.xml' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves whether the XML sitemaps are enabled, keyed by blog ID.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_xml_sitemaps_enabled() {
|
||||
$is_allowed = $this->is_sitemap_allowed();
|
||||
$blog_ids = $this->get_blog_ids();
|
||||
$is_enabled = [];
|
||||
foreach ( $blog_ids as $blog_id ) {
|
||||
$is_enabled[ $blog_id ] = $is_allowed && $this->is_sitemap_enabled_for( $blog_id );
|
||||
}
|
||||
|
||||
return $is_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves whether the sitemap is allowed on a sub site.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_sitemap_allowed() {
|
||||
$options = \get_network_option( null, 'wpseo_ms' );
|
||||
if ( ! $options || ! isset( $options['allow_enable_xml_sitemap'] ) ) {
|
||||
// Default is enabled.
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $options['allow_enable_xml_sitemap'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves whether the sitemap is enabled on a site.
|
||||
*
|
||||
* @param int $blog_id The blog ID.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_sitemap_enabled_for( $blog_id ) {
|
||||
if ( ! $this->is_yoast_active_on( $blog_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$options = \get_blog_option( $blog_id, 'wpseo' );
|
||||
if ( ! $options || ! isset( $options['enable_xml_sitemap'] ) ) {
|
||||
// Default is enabled.
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $options['enable_xml_sitemap'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether Yoast SEO is active.
|
||||
*
|
||||
* @param int $blog_id The blog ID.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_yoast_active_on( $blog_id ) {
|
||||
return \in_array( 'wordpress-seo/wp-seo.php', (array) \get_blog_option( $blog_id, 'active_plugins', [] ), true ) || $this->is_yoast_active_for_network();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether Yoast SEO is active for the entire network.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_yoast_active_for_network() {
|
||||
$plugins = \get_network_option( null, 'active_sitewide_plugins' );
|
||||
if ( isset( $plugins['wordpress-seo/wp-seo.php'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the blog IDs of public, "active" sites on the network.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_blog_ids() {
|
||||
$criteria = [
|
||||
'archived' => 0,
|
||||
'deleted' => 0,
|
||||
'public' => 1,
|
||||
'spam' => 0,
|
||||
'fields' => 'ids',
|
||||
'network_id' => \get_current_network_id(),
|
||||
];
|
||||
|
||||
return \get_sites( $criteria );
|
||||
}
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Helpers\Options_Helper;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Class RSS_Footer_Embed.
|
||||
*/
|
||||
class RSS_Footer_Embed implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The options helper.
|
||||
*
|
||||
* @var Options_Helper
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the required helpers.
|
||||
*
|
||||
* @codeCoverageIgnore It only handles dependencies.
|
||||
*
|
||||
* @param Options_Helper $options The options helper.
|
||||
*/
|
||||
public function __construct( Options_Helper $options ) {
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_filter( 'the_content_feed', [ $this, 'embed_rssfooter' ] );
|
||||
\add_filter( 'the_excerpt_rss', [ $this, 'embed_rssfooter_excerpt' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the RSS footer (or header) to the full RSS feed item.
|
||||
*
|
||||
* @param string $content Feed item content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function embed_rssfooter( $content ) {
|
||||
if ( ! $this->include_rss_footer( 'full' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return $this->embed_rss( $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the RSS footer (or header) to the excerpt RSS feed item.
|
||||
*
|
||||
* @param string $content Feed item excerpt.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function embed_rssfooter_excerpt( $content ) {
|
||||
if ( ! $this->include_rss_footer( 'excerpt' ) ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
return $this->embed_rss( \wpautop( $content ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the RSS footer should included.
|
||||
*
|
||||
* @param string $context The context of the RSS content.
|
||||
*
|
||||
* @return bool Whether or not the RSS footer should included.
|
||||
*/
|
||||
protected function include_rss_footer( $context ) {
|
||||
if ( ! \is_feed() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter: 'wpseo_include_rss_footer' - Allow the RSS footer to be dynamically shown/hidden.
|
||||
*
|
||||
* @api boolean $show_embed Indicates if the RSS footer should be shown or not.
|
||||
*
|
||||
* @param string $context The context of the RSS content - 'full' or 'excerpt'.
|
||||
*/
|
||||
if ( ! \apply_filters( 'wpseo_include_rss_footer', true, $context ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->is_configured();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the RSS feed fields are configured.
|
||||
*
|
||||
* @return bool True when one of the fields has a value.
|
||||
*/
|
||||
protected function is_configured() {
|
||||
return ( $this->options->get( 'rssbefore', '' ) !== '' || $this->options->get( 'rssafter', '' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the RSS footer and/or header to an RSS feed item.
|
||||
*
|
||||
* @param string $content Feed item content.
|
||||
*
|
||||
* @return string The content to add.
|
||||
*/
|
||||
protected function embed_rss( $content ) {
|
||||
$before = $this->rss_replace_vars( $this->options->get( 'rssbefore', '' ) );
|
||||
$after = $this->rss_replace_vars( $this->options->get( 'rssafter', '' ) );
|
||||
$content = $before . $content . $after;
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the possible RSS variables with their actual values.
|
||||
*
|
||||
* @param string $content The RSS content that should have the variables replaced.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function rss_replace_vars( $content ) {
|
||||
if ( $content === '' ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
$replace_vars = $this->get_replace_vars( $this->get_link_template(), \get_post() );
|
||||
|
||||
$content = \stripslashes( \trim( $content ) );
|
||||
$content = \str_ireplace( \array_keys( $replace_vars ), \array_values( $replace_vars ), $content );
|
||||
|
||||
return \wpautop( $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the replacement variables.
|
||||
*
|
||||
* @codeCoverageIgnore It just contains too much WordPress functions.
|
||||
*
|
||||
* @param string $link_template The link template.
|
||||
* @param mixed $post The post to use.
|
||||
*
|
||||
* @return array The replacement variables.
|
||||
*/
|
||||
protected function get_replace_vars( $link_template, $post ) {
|
||||
$author_link = '';
|
||||
if ( \is_object( $post ) ) {
|
||||
$author_link = \sprintf( $link_template, \esc_url( \get_author_posts_url( $post->post_author ) ), \esc_html( \get_the_author() ) );
|
||||
}
|
||||
|
||||
return [
|
||||
'%%AUTHORLINK%%' => $author_link,
|
||||
'%%POSTLINK%%' => \sprintf( $link_template, \esc_url( \get_permalink() ), \esc_html( \get_the_title() ) ),
|
||||
'%%BLOGLINK%%' => \sprintf( $link_template, \esc_url( \get_bloginfo( 'url' ) ), \esc_html( \get_bloginfo( 'name' ) ) ),
|
||||
'%%BLOGDESCLINK%%' => \sprintf( $link_template, \esc_url( \get_bloginfo( 'url' ) ), \esc_html( \get_bloginfo( 'name' ) ) . ' - ' . \esc_html( \get_bloginfo( 'description' ) ) ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the link template.
|
||||
*
|
||||
* @return string The link template.
|
||||
*/
|
||||
protected function get_link_template() {
|
||||
/**
|
||||
* Filter: 'nofollow_rss_links' - Allow the developer to determine whether or not to follow the links in
|
||||
* the bits Yoast SEO adds to the RSS feed, defaults to false.
|
||||
*
|
||||
* @api bool $unsigned Whether or not to follow the links in RSS feed, defaults to true.
|
||||
*
|
||||
* @since 1.4.20
|
||||
*/
|
||||
if ( \apply_filters( 'nofollow_rss_links', false ) ) {
|
||||
return '<a rel="nofollow" href="%1$s">%2$s</a>';
|
||||
}
|
||||
|
||||
return '<a href="%1$s">%2$s</a>';
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Context\Meta_Tags_Context;
|
||||
use Yoast\WP\SEO\Generators\Schema\Abstract_Schema_Piece;
|
||||
use Yoast\WP\SEO\Generators\Schema\Article;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
|
||||
/**
|
||||
* Adds the table of contents accessibility feature to the article piece with a fallback to the webpage piece.
|
||||
*/
|
||||
class Schema_Accessibility_Feature implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* Returns the conditionals based in which this loadable should be active.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [ Front_End_Conditional::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
\add_filter( 'wpseo_schema_webpage', [ $this, 'maybe_add_accessibility_feature' ], 10, 4 );
|
||||
\add_filter( 'wpseo_schema_article', [ $this, 'add_accessibility_feature' ], 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the accessibility feature to the webpage if there is no article.
|
||||
*
|
||||
* @param array $piece The graph piece.
|
||||
* @param Meta_Tags_Context $context The context.
|
||||
* @param Abstract_Schema_Piece $the_generator The current schema generator.
|
||||
* @param Abstract_Schema_Piece[] $generators The schema generators.
|
||||
*
|
||||
* @return array The graph piece.
|
||||
*/
|
||||
public function maybe_add_accessibility_feature( $piece, $context, $the_generator, $generators ) {
|
||||
foreach ( $generators as $generator ) {
|
||||
if ( \is_a( $generator, Article::class ) && $generator->is_needed() ) {
|
||||
return $piece;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->add_accessibility_feature( $piece, $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the accessibility feature to a schema graph piece.
|
||||
*
|
||||
* @param array $piece The schema piece.
|
||||
* @param Meta_Tags_Context $context The context.
|
||||
*
|
||||
* @return array The graph piece.
|
||||
*/
|
||||
public function add_accessibility_feature( $piece, $context ) {
|
||||
if ( empty( $context->blocks['yoast-seo/table-of-contents'] ) ) {
|
||||
return $piece;
|
||||
}
|
||||
|
||||
if ( isset( $piece['accessibilityFeature'] ) ) {
|
||||
$piece['accessibilityFeature'][] = 'tableOfContents';
|
||||
}
|
||||
else {
|
||||
$piece['accessibilityFeature'] = [
|
||||
'tableOfContents',
|
||||
];
|
||||
}
|
||||
return $piece;
|
||||
}
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Yoast\WP\SEO\Integrations\Front_End;
|
||||
|
||||
use Yoast\WP\SEO\Conditionals\Front_End_Conditional;
|
||||
use Yoast\WP\SEO\Conditionals\WP_Robots_Conditional;
|
||||
use Yoast\WP\SEO\Integrations\Integration_Interface;
|
||||
use Yoast\WP\SEO\Memoizers\Meta_Tags_Context_Memoizer;
|
||||
use Yoast\WP\SEO\Presenters\Robots_Presenter;
|
||||
|
||||
/**
|
||||
* Class WP_Robots_Integration
|
||||
*
|
||||
* @package Yoast\WP\SEO\Integrations\Front_End
|
||||
*/
|
||||
class WP_Robots_Integration implements Integration_Interface {
|
||||
|
||||
/**
|
||||
* The meta tags context memoizer.
|
||||
*
|
||||
* @var Meta_Tags_Context_Memoizer
|
||||
*/
|
||||
protected $context_memoizer;
|
||||
|
||||
/**
|
||||
* Sets the dependencies for this integration.
|
||||
*
|
||||
* @param Meta_Tags_Context_Memoizer $context_memoizer The meta tags context memoizer.
|
||||
*/
|
||||
public function __construct( Meta_Tags_Context_Memoizer $context_memoizer ) {
|
||||
$this->context_memoizer = $context_memoizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the integration.
|
||||
*
|
||||
* This is the place to register hooks and filters.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register_hooks() {
|
||||
/**
|
||||
* Allow control of the `wp_robots` filter by prioritizing our hook 10 less than max.
|
||||
* Use the `wpseo_robots` filter to filter the Yoast robots output, instead of WordPress core.
|
||||
*/
|
||||
\add_filter( 'wp_robots', [ $this, 'add_robots' ], ( \PHP_INT_MAX - 10 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conditionals based on which this loadable should be active.
|
||||
*
|
||||
* @return array The conditionals.
|
||||
*/
|
||||
public static function get_conditionals() {
|
||||
return [
|
||||
Front_End_Conditional::class,
|
||||
WP_Robots_Conditional::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds our robots tag value to the WordPress robots tag output.
|
||||
*
|
||||
* @param array $robots The current robots data.
|
||||
*
|
||||
* @return array The robots data.
|
||||
*/
|
||||
public function add_robots( $robots ) {
|
||||
if ( ! \is_array( $robots ) ) {
|
||||
return $this->get_robots_value();
|
||||
}
|
||||
|
||||
$merged_robots = \array_merge( $robots, $this->get_robots_value() );
|
||||
$filtered_robots = $this->enforce_robots_congruence( $merged_robots );
|
||||
$sorted_robots = $this->sort_robots( $filtered_robots );
|
||||
|
||||
// Filter all falsy-null robot values.
|
||||
return \array_filter( $sorted_robots );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the robots key-value pairs.
|
||||
*
|
||||
* @return array The robots key-value pairs.
|
||||
*/
|
||||
protected function get_robots_value() {
|
||||
$context = $this->context_memoizer->for_current_page();
|
||||
|
||||
$robots_presenter = new Robots_Presenter();
|
||||
$robots_presenter->presentation = $context->presentation;
|
||||
return $this->format_robots( $robots_presenter->get() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats our robots fields, to match the pattern WordPress is using.
|
||||
*
|
||||
* Our format: `[ 'index' => 'noindex', 'max-image-preview' => 'max-image-preview:large', ... ]`
|
||||
* WordPress format: `[ 'noindex' => true, 'max-image-preview' => 'large', ... ]`
|
||||
*
|
||||
* @param array $robots Our robots value.
|
||||
*
|
||||
* @return array The formatted robots.
|
||||
*/
|
||||
protected function format_robots( $robots ) {
|
||||
foreach ( $robots as $key => $value ) {
|
||||
// When the entry represents for example: max-image-preview:large.
|
||||
$colon_position = \strpos( $value, ':' );
|
||||
if ( $colon_position !== false ) {
|
||||
$robots[ $key ] = \substr( $value, ( $colon_position + 1 ) );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// When index => noindex, we want a separate noindex as entry in array.
|
||||
if ( \strpos( $value, 'no' ) === 0 ) {
|
||||
$robots[ $key ] = false;
|
||||
$robots[ $value ] = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// When the key is equal to the value, just make its value a boolean.
|
||||
if ( $key === $value ) {
|
||||
$robots[ $key ] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $robots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures all other possible robots values are congruent with nofollow and or noindex.
|
||||
*
|
||||
* WordPress might add some robot values again.
|
||||
* When the page is set to noindex we want to filter out these values.
|
||||
*
|
||||
* @param array $robots The robots.
|
||||
*
|
||||
* @return array The filtered robots.
|
||||
*/
|
||||
protected function enforce_robots_congruence( $robots ) {
|
||||
if ( ! empty( $robots['nofollow'] ) ) {
|
||||
$robots['follow'] = null;
|
||||
}
|
||||
if ( ! empty( $robots['noarchive'] ) ) {
|
||||
$robots['archive'] = null;
|
||||
}
|
||||
if ( ! empty( $robots['noimageindex'] ) ) {
|
||||
$robots['imageindex'] = null;
|
||||
|
||||
// `max-image-preview` should set be to `none` when `noimageindex` is present.
|
||||
// Using `isset` rather than `! empty` here so that in the rare case of `max-image-preview`
|
||||
// being equal to an empty string due to filtering, its value would still be set to `none`.
|
||||
if ( isset( $robots['max-image-preview'] ) ) {
|
||||
$robots['max-image-preview'] = 'none';
|
||||
}
|
||||
}
|
||||
if ( ! empty( $robots['nosnippet'] ) ) {
|
||||
$robots['snippet'] = null;
|
||||
}
|
||||
if ( ! empty( $robots['noindex'] ) ) {
|
||||
$robots['index'] = null;
|
||||
$robots['imageindex'] = null;
|
||||
$robots['noimageindex'] = null;
|
||||
$robots['archive'] = null;
|
||||
$robots['noarchive'] = null;
|
||||
$robots['snippet'] = null;
|
||||
$robots['nosnippet'] = null;
|
||||
$robots['max-snippet'] = null;
|
||||
$robots['max-image-preview'] = null;
|
||||
$robots['max-video-preview'] = null;
|
||||
}
|
||||
|
||||
return $robots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the robots array.
|
||||
*
|
||||
* @param array $robots The robots array.
|
||||
*
|
||||
* @return array The sorted robots array.
|
||||
*/
|
||||
protected function sort_robots( $robots ) {
|
||||
\uksort(
|
||||
$robots,
|
||||
static function ( $a, $b ) {
|
||||
$order = [
|
||||
'index' => 0,
|
||||
'noindex' => 1,
|
||||
'follow' => 2,
|
||||
'nofollow' => 3,
|
||||
];
|
||||
$ai = isset( $order[ $a ] ) ? $order[ $a ] : 4;
|
||||
$bi = isset( $order[ $b ] ) ? $order[ $b ] : 4;
|
||||
|
||||
return ( $ai - $bi );
|
||||
}
|
||||
);
|
||||
|
||||
return $robots;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user