Files
CyyWordpress/inc/class-cyywordpress-schema.php
T
2026-04-29 19:04:20 +08:00

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;