tag. * * @since 0.9.0 * @package RankMath * @subpackage RankMath\Frontend * @author Rank Math */ namespace RankMath\Frontend; use RankMath\Post; use RankMath\Helper; use RankMath\Paper\Paper; use RankMath\Traits\Hooker; use RankMath\Sitemap\Router; use RankMath\Helpers\Str; use RankMath\Helpers\Arr; use RankMath\Helpers\Security; defined( 'ABSPATH' ) || exit; /** * Head class. * * @copyright Copyright (C) 2008-2019, Yoast BV * The following code is a derivative work of the code from the Yoast(https://github.com/Yoast/wordpress-seo/), which is licensed under GPL v3. */ class Head { use Hooker; /** * The Constructor. */ public function __construct() { $this->action( 'wp_head', 'head', 1 ); if ( Helper::is_amp_active() ) { $this->action( 'amphtml_template_head', 'head', 1 ); $this->action( 'weeblramp_print_meta_data', 'head', 1 ); $this->action( 'better-amp/template/head', 'head', 99 ); $this->action( 'amp_post_template_head', 'head', 9 ); remove_action( 'better-amp/template/head', 'better_amp_print_rel_canonical' ); } $this->action( 'wp_head', 'front_page_init', 0 ); $this->filter( 'language_attributes', 'search_results_schema' ); $this->action( 'rank_math/head', 'metadesc', 6 ); $this->action( 'rank_math/head', 'robots', 10 ); $this->action( 'rank_math/head', 'canonical', 20 ); $this->action( 'rank_math/head', 'adjacent_rel_links', 21 ); $this->action( 'rank_math/head', 'metakeywords', 22 ); $this->filter( 'wp_title', 'title', 15 ); $this->filter( 'thematic_doctitle', 'title', 15 ); $this->filter( 'pre_get_document_title', 'title', 15 ); // Code to move title inside the Rank Math's meta. remove_action( 'wp_head', '_wp_render_title_tag', 1 ); add_action( 'rank_math/head', '_wp_render_title_tag', 1 ); // Force Rewrite title. if ( Helper::get_settings( 'titles.rewrite_title' ) && ! current_theme_supports( 'title-tag' ) ) { $this->action( 'get_header', 'start_ob', 0 ); $this->action( 'wp_head', 'rewrite_title', 9999 ); } // Remove core robots data. if ( ! is_embed() ) { remove_all_filters( 'wp_robots' ); } } /** * Initialize front page related stuff. */ public function front_page_init() { if ( ! is_front_page() ) { return; } $this->action( 'rank_math/head', 'webmaster_tools_authentication', 90 ); } /** * Output authentication codes for all the Webmaster Tools. */ public function webmaster_tools_authentication() { $tools = [ 'google_verify' => 'google-site-verification', 'bing_verify' => 'msvalidate.01', 'baidu_verify' => 'baidu-site-verification', 'yandex_verify' => 'yandex-verification', 'pinterest_verify' => 'p:domain_verify', 'norton_verify' => 'norton-safeweb-site-verification', ]; foreach ( $tools as $id => $name ) { $content = trim( Helper::get_settings( "general.{$id}" ) ); $content = $this->do_filter( 'webmaster/' . $id, $content ); if ( empty( $content ) ) { continue; } printf( '' . "\n", esc_attr( $name ), esc_attr( $content ) ); } $custom_webmaster_tags = Helper::get_settings( 'general.custom_webmaster_tags' ); if ( empty( $custom_webmaster_tags ) ) { return; } $custom_webmaster_tags = Arr::from_string( $custom_webmaster_tags ); foreach ( $custom_webmaster_tags as $custom_webmaster_tag ) { $custom_webmaster_tag = trim( $custom_webmaster_tag ); if ( empty( $custom_webmaster_tag ) ) { continue; } echo $custom_webmaster_tag . "\n"; } } /** * Add Search Result Page schema as language attributes for the tag. * * @param string $output A space-separated list of language attributes. * @return string */ public function search_results_schema( $output ) { if ( ! is_search() ) { return $output; } return preg_replace( '/itemtype="([^"]+)"/', 'itemtype="https://schema.org/SearchResultsPage', $output ); } /** * Main function attached to the wp_head hook. */ public function head() { global $wp_query; $old_wp_query = null; if ( ! $wp_query->is_main_query() ) { $old_wp_query = $wp_query; wp_reset_query(); } $this->credits(); // Remove core actions, now handled by Rank Math. 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 ); if ( Helper::is_amp_active() ) { remove_action( 'amp_post_template_head', 'amp_post_template_add_title' ); remove_action( 'amp_post_template_head', 'amp_post_template_add_canonical' ); remove_action( 'amp_post_template_head', 'amp_print_schemaorg_metadata' ); } /** * Add extra output in the head tag. */ $this->do_action( 'head' ); $this->credits( true ); if ( ! empty( $old_wp_query ) ) { $GLOBALS['wp_query'] = $old_wp_query; unset( $old_wp_query ); } } /** * Main title function. * * @param string $title Already set title or empty string. * @return string */ public function title( $title ) { if ( is_feed() ) { return $title; } $generated = Paper::get()->get_title(); return Str::is_non_empty( $generated ) ? $generated : $title; } /** * Output the meta description tag with the generated description. */ public function metadesc() { $generated = Paper::get()->get_description(); if ( Str::is_non_empty( $generated ) ) { echo '', "\n"; } } /** * Output the meta robots tag. */ public function robots() { $robots = Paper::get()->get_robots(); $robotsstr = join( ', ', $robots ); if ( Str::is_non_empty( $robotsstr ) ) { echo '', "\n"; } // If a page is noindex, let's remove the canonical URL. // https://www.seroundtable.com/google-noindex-rel-canonical-confusion-26079.html . if ( isset( $robots['index'] ) && 'noindex' === $robots['index'] ) { $this->remove_action( 'rank_math/head', 'canonical', 20 ); $this->remove_action( 'rank_math/head', 'adjacent_rel_links', 21 ); } } /** * Output the canonical URL tag. */ public function canonical() { $canonical = Paper::get()->get_canonical(); if ( Str::is_non_empty( $canonical ) ) { echo '' . "\n"; } } /** * Add the rel 'prev' and 'next' links to archives or single posts. * * @link http://googlewebmastercentral.blogspot.com/2011/09/pagination-with-relnext-and-relprev.html */ public function adjacent_rel_links() { /** * Enable rel "next" & "prev" tags on sites running Genesis. * * @param bool $unsigned Whether or not to show rel next / prev . */ if ( is_home() && function_exists( 'genesis' ) && false === $this->do_filter( 'frontend/genesis/force_adjacent_rel_home', false ) ) { return; } /** * Disable rel 'prev' and 'next' links. * * @param bool $disable Rel 'prev' and 'next' links should be disabled or not. */ if ( true === $this->do_filter( 'frontend/disable_adjacent_rel_links', false ) ) { return; } if ( is_singular() ) { $this->adjacent_rel_links_single(); return; } $this->adjacent_rel_links_archive(); } /** * Output the meta keywords value. */ public function metakeywords() { /** * Passing a truthy value to the filter will effectively short-circuit the * set keywords process. * * @param bool $return Short-circuit return value. Either false or true. */ if ( ! $this->do_filter( 'frontend/show_keywords', false ) ) { return; } $keywords = Paper::get()->get_keywords(); if ( Str::is_non_empty( $keywords ) ) { echo '', "\n"; } } /** * Output the rel next/prev tags on a paginated single post. * * @return void */ private function adjacent_rel_links_single() { $num_pages = 1; $queried_object = get_queried_object(); if ( ! empty( $queried_object ) ) { $num_pages = substr_count( $queried_object->post_content, '' ) + 1; } if ( 1 === $num_pages ) { return; } $page = max( 1, (int) get_query_var( 'page' ) ); $url = get_permalink( get_queried_object_id() ); if ( $page > 1 ) { $this->adjacent_rel_link( 'prev', $url, $page - 1, 'page' ); } if ( $page < $num_pages ) { $this->adjacent_rel_link( 'next', $url, $page + 1, 'page' ); } } /** * Output the rel next/prev tags on archives. */ private function adjacent_rel_links_archive() { $url = Paper::get()->get_canonical( true, true ); if ( ! is_string( $url ) || '' === $url ) { return; } $paged = max( 1, (int) get_query_var( 'paged' ) ); if ( 2 === $paged ) { $this->adjacent_rel_link( 'prev', $url, $paged - 1 ); } if ( is_front_page() ) { $url = Router::get_base_url( '' ); } if ( $paged > 2 ) { $this->adjacent_rel_link( 'prev', $url, $paged - 1 ); } if ( $paged < $GLOBALS['wp_query']->max_num_pages ) { $this->adjacent_rel_link( 'next', $url, $paged + 1 ); } } /** * Build adjacent page link for archives. * * @param string $rel Prev or next. * @param string $url The current archive URL without page parameter. * @param string $page The page number added to the $url in the link tag. * @param string $query_arg The pagination query argument to use for the $url. */ private function adjacent_rel_link( $rel, $url, $page, $query_arg = 'paged' ) { global $wp_rewrite; if ( $page > 1 ) { $url = ! $wp_rewrite->using_permalinks() ? Security::add_query_arg_raw( $query_arg, $page, $url ) : user_trailingslashit( trailingslashit( $url ) . $this->get_pagination_base() . $page ); } /** * Change the link rel HTML output. * * @param string $link The `do_filter( "frontend/{$rel}_rel_link", '\n" ); if ( Str::is_non_empty( $link ) ) { echo $link; } } /** * Get pagination base. * * @return string The pagination base. */ private function get_pagination_base() { global $wp_rewrite; return ( ! is_singular() || Post::is_home_static_page() ) ? trailingslashit( $wp_rewrite->pagination_base ) : ''; } /** * Credits. * * @param boolean $closing Is closing credits needed. */ private function credits( $closing = false ) { /** * Disable credit in the HTML source. * * @param bool $remove */ if ( $this->do_filter( 'frontend/remove_credit_notice', false ) ) { return; } if ( false === $closing ) { if ( ! Helper::is_whitelabel() && ! defined( 'RANK_MATH_PRO_FILE' ) ) { echo "\n\n"; } elseif ( defined( 'RANK_MATH_PRO_FILE' ) ) { echo "\n\n"; } return; } if ( ! Helper::is_whitelabel() ) { echo '\n\n"; } } /** * Start the Output Buffer. * * @since 1.0.29 */ public function start_ob() { ob_start(); } /** * Use output buffering to force rewrite the title tag. */ public function rewrite_title() { global $wp_query; // Check if we're in the main query. $old_wp_query = null; if ( ! $wp_query->is_main_query() ) { $old_wp_query = $wp_query; wp_reset_query(); } $content = ob_get_clean(); $title = Paper::get()->get_title(); if ( empty( $title ) ) { echo $content; } // Find all title tags, remove them, and add the new one. $content = preg_replace( '//i', '', $content ); $content = str_replace( '', '' . "\n" . '' . esc_html( $title ) . '', $content ); if ( ! empty( $old_wp_query ) ) { $GLOBALS['wp_query'] = $old_wp_query; } echo $content; } }