bots_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 );
}
}
= '';
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.
*
* @since 1.4.20
*
* @param bool $unsigned Whether or not to follow the links in RSS feed, defaults to true.
*/
if ( \apply_filters( 'nofollow_rss_links', false ) ) {
return '%2$s';
}
return '%2$s';
}
}
( ! 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 = ( $order[ $a ] ?? 4 );
$bi = ( $order[ $b ] ?? 4 );
return ( $ai - $bi );
}
);
return $robots;
}
}
'admin_print_scripts', 'print_emoji_detection_script' );
$this->asset_manager->enqueue_script( 'support' );
$this->asset_manager->enqueue_style( 'support' );
if ( \YoastSEO()->classes->get( Promotion_Manager::class )->is( 'black-friday-promotion' ) ) {
$this->asset_manager->enqueue_style( 'black-friday-banner' );
}
$this->asset_manager->localize_script( 'support', 'wpseoScriptData', $this->get_script_data() );
}
/**
* Removes all current WP notices.
*
* @return void
*/
public function remove_notices() {
\remove_all_actions( 'admin_notices' );
\remove_all_actions( 'user_admin_notices' );
\remove_all_actions( 'network_admin_notices' );
\remove_all_actions( 'all_admin_notices' );
}
/**
* Creates the script data.
*
* @return array>, bool, string>> The script data.
*/
public function get_script_data() {
return [
'preferences' => [
'hasPremiumSubscription' => $this->addon_manager->has_active_addons() && $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG ),
'hasWooSeoSubscription' => $this->addon_manager->has_active_addons() && $this->addon_manager->has_valid_subscription( WPSEO_Addon_Manager::WOOCOMMERCE_SLUG ),
'isRtl' => \is_rtl(),
'pluginUrl' => \plugins_url( '', \WPSEO_FILE ),
'upsellSettings' => [
'actionId' => 'load-nfd-ctb',
'premiumCtbId' => 'f6a84663-465f-4cb5-8ba5-f7a6d72224b2',
],
'isWooCommerceActive' => $this->woocommerce_conditional->is_met(),
],
'linkParams' => $this->shortlink_helper->get_query_params(),
'currentPromotions' => \YoastSEO()->classes->get( Promotion_Manager::class )->get_current_promotions(),
];
}
}
f ( ! empty( $newly_made_public_taxonomies ) ) {
// Force a notification requesting to start the SEO data optimization.
\delete_transient( Indexable_Term_Indexation_Action::UNINDEXED_COUNT_TRANSIENT );
\delete_transient( Indexable_Term_Indexation_Action::UNINDEXED_LIMITED_COUNT_TRANSIENT );
$this->indexing_helper->set_reason( Indexing_Reasons::REASON_TAXONOMY_MADE_PUBLIC );
\do_action( 'new_public_taxonomy_notifications', $newly_made_public_taxonomies );
}
// There are taxonomies that have been made private.
if ( ! empty( $newly_made_non_public_taxonomies ) && $this->indexable_helper->should_index_indexables() ) {
// Schedule a cron job to remove all the terms whose taxonomy has been made private.
$cleanup_not_yet_scheduled = ! \wp_next_scheduled( Cleanup_Integration::START_HOOK );
if ( $cleanup_not_yet_scheduled ) {
\wp_schedule_single_event( ( \time() + ( \MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
}
\do_action( 'clean_new_public_taxonomy_notifications', $newly_made_non_public_taxonomies );
}
}
}
st_Notification::ERROR,
'id' => self::NOTIFICATION_ID,
'capabilities' => 'wpseo_manage_options',
'priority' => 1,
]
);
}
}
ductions ) {
// Bail when there are no introductions to show.
return;
}
// Update user meta to have "seen" these introductions.
$this->update_user_introductions( $user_id, $introductions );
$this->admin_asset_manager->enqueue_script( self::SCRIPT_HANDLE );
$this->admin_asset_manager->localize_script(
self::SCRIPT_HANDLE,
'wpseoIntroductions',
[
'introductions' => $introductions,
'isPremium' => $this->product_helper->is_premium(),
'isRtl' => \is_rtl(),
'linkParams' => $this->short_link_helper->get_query_params(),
'pluginUrl' => \plugins_url( '', \WPSEO_FILE ),
'wistiaEmbedPermission' => $this->wistia_embed_permission_repository->get_value_for_user( $user_id ),
'isWooEnabled' => $this->woocommerce_conditional->is_met(),
]
);
$this->admin_asset_manager->enqueue_style( 'introductions' );
}
/**
* Updates the user metadata to have "seen" the introductions.
*
* @param int $user_id The user ID.
* @param array $introductions The introductions.
*
* @return void
*/
private function update_user_introductions( $user_id, $introductions ) {
$metadata = $this->user_helper->get_meta( $user_id, Introductions_Seen_Repository::USER_META_KEY, true );
if ( ! \is_array( $metadata ) ) {
$metadata = [];
}
if ( empty( $introductions ) || ! \is_array( $introductions ) ) {
return;
}
// Find the introduction with the highest priority, because JS will only show that one.
$highest_priority_intro = \array_reduce(
$introductions,
static function ( $carry, $item ) {
return ( $carry === null || $item['priority'] < $carry['priority'] ) ? $item : $carry;
},
null
);
if ( $highest_priority_intro === null ) {
return;
}
// Mark the introduction with the highest priority as seen.
$metadata[ $highest_priority_intro['id'] ]['is_seen'] = true;
$metadata[ $highest_priority_intro['id'] ]['seen_on'] = \time();
$this->user_helper->update_meta( $user_id, Introductions_Seen_Repository::USER_META_KEY, $metadata );
}
/**
* Updates the introductions metadata format for the user
* This is needed because we're introducing timestamps for introductions that have been seen, thus changing the format.
*
* @param int $user_id The user ID.
*
* @return void
*/
private function update_metadata_for( int $user_id ) {
$metadata = $this->introductions_collector->get_metadata( $user_id );
foreach ( $metadata as $introduction_name => $introduction_data ) {
if ( \is_bool( $introduction_data ) ) {
$metadata[ $introduction_name ] = [
'is_seen' => $introduction_data,
'seen_on' => ( $introduction_data === true ) ? \time() : 0,
];
}
}
$this->user_helper->update_meta( $user_id, Introductions_Seen_Repository::USER_META_KEY, $metadata );
}
}
option_name ] ) {
$this->populate_file_command_handler->handle();
return;
}
}
}
}