155 lines
3.9 KiB
PHP
155 lines
3.9 KiB
PHP
<?php
|
|
/**
|
|
* JSON-LD Schema.org structured data class.
|
|
*
|
|
* Outputs inline <script type="application/ld+json"> on relevant pages.
|
|
* Skips output when a dedicated SEO plugin is active.
|
|
*
|
|
* @package CyyWordpress
|
|
*/
|
|
|
|
if ( ! class_exists( 'CyyWordpress_Schema' ) ) :
|
|
|
|
/**
|
|
* Handles JSON-LD output.
|
|
*/
|
|
class CyyWordpress_Schema {
|
|
|
|
/**
|
|
* Register hooks.
|
|
*/
|
|
public static function init(): void {
|
|
// Bail early if a popular SEO plugin already handles schema.
|
|
if (
|
|
defined( 'WPSEO_VERSION' )
|
|
|| defined( 'RANKMATH_VERSION' )
|
|
|| class_exists( 'All_in_One_SEO_Pack' )
|
|
) {
|
|
return;
|
|
}
|
|
|
|
add_action( 'wp_head', array( static::class, 'output_schema' ) );
|
|
}
|
|
|
|
/**
|
|
* Determine page type and output the correct schema.
|
|
*/
|
|
public static function output_schema(): void {
|
|
$schema = null;
|
|
|
|
if ( is_front_page() || is_home() ) {
|
|
$schema = self::website_schema();
|
|
} elseif ( is_singular( 'post' ) ) {
|
|
$schema = self::article_schema();
|
|
} elseif ( is_author() ) {
|
|
$schema = self::person_schema();
|
|
}
|
|
|
|
if ( $schema ) {
|
|
// json_encode with JSON_UNESCAPED_UNICODE for readable Chinese output.
|
|
echo '<script type="application/ld+json">'
|
|
. wp_json_encode( $schema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT )
|
|
. '</script>' . PHP_EOL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* WebSite schema with SearchAction for Sitelink Search Box.
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
private static function website_schema(): array {
|
|
return array(
|
|
'@context' => 'https://schema.org',
|
|
'@type' => 'WebSite',
|
|
'name' => get_bloginfo( 'name' ),
|
|
'url' => home_url( '/' ),
|
|
'potentialAction' => array(
|
|
'@type' => 'SearchAction',
|
|
'target' => array(
|
|
'@type' => 'EntryPoint',
|
|
'urlTemplate' => home_url( '/?s={search_term_string}' ),
|
|
),
|
|
'query-input' => 'required name=search_term_string',
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Article schema for single posts.
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
private static function article_schema(): array {
|
|
global $post;
|
|
|
|
$author_id = (int) get_the_author_meta( 'ID' );
|
|
$author_name = get_the_author_meta( 'display_name', $author_id );
|
|
$author_url = get_author_posts_url( $author_id );
|
|
$image_url = '';
|
|
|
|
if ( has_post_thumbnail() ) {
|
|
$src = wp_get_attachment_image_src( (int) get_post_thumbnail_id(), 'large' );
|
|
if ( $src ) {
|
|
$image_url = $src[0];
|
|
}
|
|
}
|
|
|
|
$schema = array(
|
|
'@context' => 'https://schema.org',
|
|
'@type' => 'Article',
|
|
'headline' => get_the_title(),
|
|
'url' => (string) get_permalink(),
|
|
'datePublished' => get_the_date( DATE_W3C ),
|
|
'dateModified' => get_the_modified_date( DATE_W3C ),
|
|
'author' => array(
|
|
'@type' => 'Person',
|
|
'name' => $author_name,
|
|
'url' => $author_url,
|
|
),
|
|
'publisher' => array(
|
|
'@type' => 'Organization',
|
|
'name' => get_bloginfo( 'name' ),
|
|
'url' => home_url( '/' ),
|
|
),
|
|
'description' => has_excerpt()
|
|
? get_the_excerpt()
|
|
: wp_trim_words( wp_strip_all_tags( $post->post_content ), 30 ),
|
|
);
|
|
|
|
if ( $image_url ) {
|
|
$schema['image'] = $image_url;
|
|
}
|
|
|
|
return $schema;
|
|
}
|
|
|
|
/**
|
|
* Person schema for author archive pages.
|
|
*
|
|
* @return array<string, mixed>
|
|
*/
|
|
private static function person_schema(): array {
|
|
$author = get_queried_object();
|
|
$author_id = ( $author instanceof WP_User ) ? $author->ID : 0;
|
|
$author_name = get_the_author_meta( 'display_name', $author_id );
|
|
$author_url = get_author_posts_url( $author_id );
|
|
$bio = get_the_author_meta( 'description', $author_id );
|
|
|
|
$schema = array(
|
|
'@context' => 'https://schema.org',
|
|
'@type' => 'Person',
|
|
'name' => $author_name,
|
|
'url' => $author_url,
|
|
);
|
|
|
|
if ( $bio ) {
|
|
$schema['description'] = $bio;
|
|
}
|
|
|
|
return $schema;
|
|
}
|
|
}
|
|
|
|
endif;
|