: title, description, keywords, robots, canonical, social cards, legacy meta, * verification codes, hreflang and the JSON-LD graph. */ if ( ! defined( 'ABSPATH' ) ) { exit; } class SXSEO_Head { public static function hook() { add_action( 'after_setup_theme', function () { add_theme_support( 'title-tag' ); }, 99 ); add_filter( 'pre_get_document_title', array( __CLASS__, 'title' ), 20 ); add_filter( 'wp_robots', array( __CLASS__, 'robots' ), 20 ); add_action( 'wp_head', array( __CLASS__, 'output' ), 1 ); add_action( 'wp', array( __CLASS__, 'late' ) ); add_action( 'template_redirect', array( __CLASS__, 'feed_headers' ), 1 ); remove_action( 'wp_head', 'rel_canonical' ); if ( sxseo_opt( 'cleanup_head' ) ) { remove_action( 'wp_head', 'wp_generator' ); remove_action( 'wp_head', 'rsd_link' ); remove_action( 'wp_head', 'wlwmanifest_link' ); remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 ); add_filter( 'the_generator', '__return_empty_string' ); } // Other SEO plugins' own output would duplicate ours; Sentrixa SEO is the single source. add_filter( 'wpseo_canonical', '__return_false' ); } public static function late() { SXSEO_Context::reset(); } public static function title( $title ) { $c = SXSEO_Context::current(); return '' !== $c['title'] ? wptexturize( $c['title'] ) : $title; } public static function robots( $robots ) { $c = SXSEO_Context::current(); if ( ! get_option( 'blog_public' ) ) { return $robots; } unset( $robots['noindex'], $robots['follow'], $robots['index'], $robots['nofollow'] ); $flags = $c['robots']; $robots[ in_array( 'noindex', $flags, true ) ? 'noindex' : 'index' ] = true; $robots[ in_array( 'nofollow', $flags, true ) ? 'nofollow' : 'follow' ] = true; foreach ( array( 'noarchive', 'nosnippet', 'noimageindex' ) as $adv ) { if ( in_array( $adv, $flags, true ) ) { $robots[ $adv ] = true; } } if ( sxseo_opt( 'robots_max' ) && ! in_array( 'noindex', $flags, true ) ) { unset( $robots['max-image-preview'] ); $robots['max-image-preview'] = 'large'; if ( ! in_array( 'nosnippet', $flags, true ) ) { $robots['max-snippet'] = '-1'; $robots['max-video-preview'] = '-1'; } } return $robots; } public static function feed_headers() { if ( sxseo_opt( 'feeds_noindex' ) && is_feed() ) { header( 'X-Robots-Tag: noindex, follow', true ); } } private static function tag( $name, $content, $attr = 'name' ) { if ( '' === (string) $content ) { return; } echo '' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput } public static function output() { $c = SXSEO_Context::current(); if ( is_admin() || is_feed() ) { return; } echo "\n"; $noindex = in_array( 'noindex', $c['robots'], true ); self::tag( 'description', $c['desc'] ); if ( sxseo_opt( 'meta_keywords' ) && $c['keywords'] && ! $noindex ) { self::tag( 'keywords', implode( ', ', $c['keywords'] ) ); } // Canonical. if ( '' !== $c['url'] && ! is_404() && ! is_search() ) { echo '' . "\n"; } self::legacy( $c ); self::verification(); if ( sxseo_opt( 'og' ) ) { self::social( $c ); } if ( sxseo_opt( 'hreflang' ) && '' !== $c['url'] && ! $noindex ) { $lang = str_replace( '_', '-', get_locale() ); echo '' . "\n"; echo '' . "\n"; } if ( ! $noindex ) { SXSEO_Schema::output( $c ); } echo "\n"; } private static function legacy( array $c ) { $s = SXSEO_Settings::all(); $name = $s['org_name'] ?: get_bloginfo( 'name' ); if ( $s['meta_author'] ) { $author = ''; if ( $c['post'] instanceof WP_Post && 'post' === $c['post']->post_type ) { $author = get_the_author_meta( 'display_name', $c['post']->post_author ); } self::tag( 'author', $author ?: $name ); } if ( $s['meta_copyright'] ) { self::tag( 'copyright', '© ' . gmdate( 'Y' ) . ' ' . $name ); } if ( $s['meta_language'] ) { self::tag( 'language', str_replace( '_', '-', get_locale() ) ); self::tag( 'content-language', str_replace( '_', '-', get_locale() ), 'http-equiv' ); } if ( $s['meta_legacy'] ) { self::tag( 'revisit-after', '7 days' ); self::tag( 'rating', 'general' ); self::tag( 'distribution', 'global' ); self::tag( 'resource-type', 'document' ); self::tag( 'format-detection', 'telephone=yes' ); self::tag( 'application-name', get_bloginfo( 'name' ) ); } if ( $s['geo_meta'] && $s['org_lat'] && $s['org_lng'] ) { if ( $s['org_country'] ) { self::tag( 'geo.region', $s['org_country'] . ( $s['org_region'] ? '-' . $s['org_region'] : '' ) ); } if ( $s['org_city'] ) { self::tag( 'geo.placename', $s['org_city'] ); } self::tag( 'geo.position', $s['org_lat'] . ';' . $s['org_lng'] ); self::tag( 'ICBM', $s['org_lat'] . ', ' . $s['org_lng'] ); } if ( $s['dublin_core'] ) { self::tag( 'DC.title', $c['og_title'] ?: $c['title'] ); self::tag( 'DC.description', $c['desc'] ); self::tag( 'DC.language', str_replace( '_', '-', get_locale() ) ); self::tag( 'DC.publisher', $name ); if ( $c['post'] instanceof WP_Post ) { self::tag( 'DC.date', get_post_modified_time( 'c', true, $c['post'] ) ); self::tag( 'DC.type', 'Text' ); } if ( $c['keywords'] ) { self::tag( 'DC.subject', implode( ', ', $c['keywords'] ) ); } } } private static function verification() { $map = array( 'v_google' => 'google-site-verification', 'v_bing' => 'msvalidate.01', 'v_yandex' => 'yandex-verification', 'v_baidu' => 'baidu-site-verification', 'v_pinterest' => 'p:domain_verify', 'v_facebook' => 'facebook-domain-verification', ); foreach ( $map as $opt => $name ) { self::tag( $name, trim( (string) sxseo_opt( $opt ) ) ); } } private static function social( array $c ) { $s = SXSEO_Settings::all(); $title = $c['og_title'] ?: $c['title']; $desc = $c['og_desc'] ?: $c['desc']; self::tag( 'og:locale', get_locale(), 'property' ); self::tag( 'og:type', 'home' === $c['type'] || 'front' === $c['type'] ? 'website' : $c['og_type'], 'property' ); self::tag( 'og:title', $title, 'property' ); self::tag( 'og:description', $desc, 'property' ); self::tag( 'og:url', $c['url'], 'property' ); self::tag( 'og:site_name', get_bloginfo( 'name' ), 'property' ); if ( $s['fb_app_id'] ) { self::tag( 'fb:app_id', $s['fb_app_id'], 'property' ); } if ( $c['image'] ) { self::tag( 'og:image', $c['image'], 'property' ); if ( 0 === strpos( $c['image'], 'https://' ) ) { self::tag( 'og:image:secure_url', $c['image'], 'property' ); } $att = attachment_url_to_postid( $c['image'] ); if ( $att ) { $meta = wp_get_attachment_metadata( $att ); if ( ! empty( $meta['width'] ) ) { self::tag( 'og:image:width', (string) $meta['width'], 'property' ); self::tag( 'og:image:height', (string) $meta['height'], 'property' ); } $alt = get_post_meta( $att, '_wp_attachment_image_alt', true ); self::tag( 'og:image:alt', $alt ?: $title, 'property' ); $mime = get_post_mime_type( $att ); self::tag( 'og:image:type', (string) $mime, 'property' ); } } if ( 'article' === $c['og_type'] && $c['post'] instanceof WP_Post ) { self::tag( 'article:published_time', get_post_time( 'c', true, $c['post'] ), 'property' ); self::tag( 'article:modified_time', get_post_modified_time( 'c', true, $c['post'] ), 'property' ); self::tag( 'article:author', get_the_author_meta( 'display_name', $c['post']->post_author ), 'property' ); if ( ! empty( $c['ctx']['terms']['primary'] ) ) { self::tag( 'article:section', $c['ctx']['terms']['primary'], 'property' ); } foreach ( (array) get_the_tags( $c['post'] ) as $t ) { if ( $t instanceof WP_Term ) { self::tag( 'article:tag', $t->name, 'property' ); } } } if ( 'none' !== $s['twitter_card'] ) { self::tag( 'twitter:card', $c['image'] ? $s['twitter_card'] : 'summary' ); self::tag( 'twitter:title', $title ); self::tag( 'twitter:description', $desc ); if ( $c['image'] ) { self::tag( 'twitter:image', $c['image'] ); } if ( $s['twitter_site'] ) { $h = '@' . ltrim( $s['twitter_site'], '@' ); self::tag( 'twitter:site', $h ); self::tag( 'twitter:creator', $h ); } } } }