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