三样东西:
这三样都放在 <head> 里,通过 wp_head 钩子输出。
用 WordPress 自带的:
rel_canonical() 默认挂在 wp_head 上,文章页会自动输出;title-tag 后自动输出;所以你其实不用写代码,只要保证 wp_head() 存在,这些就有。
首页、分类页、标签页的 canonical,WordPress 自带的不一定输出。rel_canonical() 只对“单篇内容”生效。
想补齐,可以挂在 wp_head 上自己输出:
add_action( 'wp_head', function () {
if ( is_singular() ) return; // 单篇交给 WordPress 自己
if ( is_front_page() || is_home() ) {
$url = home_url( '/' );
} elseif ( is_category() || is_tag() ) {
$url = get_term_link( get_queried_object() );
} else {
return;
}
echo '<link rel="canonical" href="' . esc_url( $url ) . '">' . "\n";
}, 1 );
注意优先级 1:要比 WordPress 默认的早一点,避免重复输出。
更稳妥的做法是先 remove_action( 'wp_head', 'rel_canonical' ),然后自己统一输出所有页面的 canonical。
add_action( 'wp_head', function () {
$title = wp_get_document_title();
$desc = is_singular() ? wp_strip_all_tags( get_the_excerpt() ) : get_bloginfo( 'description' );
echo '<meta property="og:title" content="' . esc_attr( $title ) . '">' . "\n";
echo '<meta property="og:description" content="' . esc_attr( $desc ) . '">' . "\n";
echo '<meta property="og:url" content="' . esc_url( get_permalink() ) . '">' . "\n";
}, 5 );
只做最基本的三个。要更完整(图片、类型、时间),再加。
结构化数据最简单的形式是“文章”类型:
add_action( 'wp_head', function () {
if ( ! is_singular( 'post' ) ) return;
$data = array(
'@context' => 'https://schema.org',
'@type' => 'BlogPosting',
'headline' => get_the_title(),
'datePublished' => get_the_date( 'c' ),
'dateModified' => get_the_modified_date( 'c' ),
'author' => array( '@type' => 'Person', 'name' => get_the_author() ),
);
echo '<script type="application/ld+json">'
. wp_json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES )
. '</script>' . "\n";
} );
用 wp_json_encode 而不是 json_encode(前者更安全,会处理转义)。
两点提醒:
二选一:要么全交给插件,要么全自己来。
一句话记住:canonical/OG/JSON-LD 挂在 wp_head 输出;能交给 WordPress 的就别自己写;别跟插件重复。
下一篇是卷五最后一篇:收尾上线。