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; } } } }