在开发WordPress主题的时候,我们经常需要为文章设置单独的模版,比如,一篇文章在视频分类中,我们需要为这篇文章设置视频播放模版,一篇文章在图片中,我们需要为这篇文章设置图片相册模版。在 WordPress 中,有很多办法可以给文章设置单独的模版。
第一种办法是使用自定义页面模版,这种方法是在 WordPress 4.7 中开始提供的,示例代码如下,把 post 添加到 Template Post Type: 中,即可在发布文章的时候,和页面一样选择单独的模版了。
<?php
/*
Template Name: Full-width layout
Template Post Type: post, page, event
*/
// 下面是页面模版的代码
这种办法实现起来很简单,但是用户却要在发布文章时选择一下对应的模版,多了一次操作。
另外一个办法是使用文章格式,这种方法需要WordPress主题支持文章格式,用户发布文章的时候选择文章格式,在模版中,我们根据文章格式调用对应的模版,关键代码如下。
<?php get_template_part( 'content', get_post_format() ); ?>
这种办法同样需要在后台多一种选择,并且 WordPress 支持的文章格式有限,虽然可以添加自定是文章格式,却增加了不少复杂度。
为分类文章设置基于分类目录的文章模版
上面两种实现方法都不是很理想,可不可以像分类模版那样,直接在主题中添加一个类似 category-single.php 的分类模版的文件,实现用户选择了分类后,WordPress 自动选择对应的文章模版来显示内容呢?
我们搜索了一番,发现实现方法非常简单,具体代码如下,把下面的代码添加到主题中后,在主题中添加一个 single-category-slug.php 的模版文件,即可实现我们上面的设想,如果没有为子分类设置模版,会自动使用父级分类的文章模版,如果也没有为父级分类设置文章模版,则使用默认的文章模版。
add_filter( 'single_template', function ( $template )
{
foreach ( (array) get_the_category() as $cat ) {
if ( file_exists( TEMPLATEPATH . "/single-category-{$cat->slug}.php" ) ) return TEMPLATEPATH . "/single-category-{$cat->slug}.php";
if ( $cat->parent ) {
$cat = get_the_category_by_ID( $cat->parent );
if ( file_exists( TEMPLATEPATH . "/single-category-{$cat->slug}.php" ) ) return TEMPLATEPATH . "/single-category-{$cat->slug}.php";
}
}
return $template;
} );
结合 Yoast SEO 的主分类功能指定分类文章模版
使用了一段时间之后,我们发现,上面的代码有一些小问题。如果一个文章同时设置了两个分类,WordPress 会选择第一个分类对应的分类文章模版来显示内容,有时候,这不是我们想要的效果,我们需要让文章按照我们指定的分类来选择文章模版,联想到 Yoast SEO 插件有一个设置文章主分类的功能,我们调整了一下上面的代码,最终代码如下。
add_filter( 'single_template', function ( $template )
{
// 获取主分类
$primary_cat_id = get_post_meta( get_the_ID(), '_yoast_wpseo_primary_category', true );
foreach ( (array) get_the_category() as $cat ) {
// 尝试使用主分类文章模版
if ( $primary_cat_id ) {
$primary_cat = get_term( $primary_cat_id );
if ( file_exists( TEMPLATEPATH . "/single-category-{$primary_cat->slug}.php" ) ) {
return TEMPLATEPATH . "/single-category-{$primary_cat->slug}.php";
}
}
// 如果主分类模版不存在,使用分类文章模版
if ( file_exists( TEMPLATEPATH . "/single-category-{$cat->slug}.php" ) ) {
return TEMPLATEPATH . "/single-category-{$cat->slug}.php";
}
if ( $cat->parent ) {
// 如果分类文章模版不存在,尝试初拥主分类父级文章模版
if ( $primary_cat_id ) {
$primary_cat = get_term( $primary_cat_id );
if ( $primary_cat->parent ) {
$primary_cat_parent = get_term( $primary_cat->parent );
}
if ( file_exists( TEMPLATEPATH . "/single-category-{$primary_cat_parent->slug}.php" ) ) {
return TEMPLATEPATH . "/single-category-{$primary_cat_parent->slug}.php";
}
}
// 如果主分类父级文章模版也不存在,尝试使用父级分类文章模版
$cat = get_term( $cat->parent );
if ( file_exists( TEMPLATEPATH . "/single-category-{$cat->slug}.php" ) ) {
return TEMPLATEPATH . "/single-category-{$cat->slug}.php";
}
}
}
return $template;
} );
Yoast SEO 会自动设置第一个分类为主分类,并且大部分情况下,客户都不会为一篇文章设置两个不同的分类,所以发布文章的时候,需要调整主分类的操作其实很少。上面的代码很好的实现了我们的需求,让我们开发的定制主题可以自动根据文章分类选择分类文章模版显示内容,在后台发布文章的时候,也没有多出来一些操作,客户很高兴!
仔细考虑一下,上面的代码还有完善的空间,比如是否可以和文章格式、自定义文章(页面)模版一起工作,一起使用时,选择这些模版的优先级怎么处理?如果你有更好的实现方法,欢迎在评论中提出,我们一起探讨。