问题描述
我有一个自定义的帖子类型 paper
定义在我的 wordpress 插件,我显示,连同标准的帖子,主要查询通过:
function add_custom_post_types_to_query( $query ) {
if ( is_home() && $query->is_main_query() )
$query->set( 'post_type', array( 'post', 'paper' ) );
// return $query; //As was pointed out by Ihor Vorotnov this is not necessary.
}
add_action( 'pre_get_posts', 'add_custom_post_types_to_query' );
我也可以通过以下方式从插件目录中注册一个自定义的 single-paper.php
模板:
function get_custom_post_type_single_template($single_template) {
global $post;
if ($post->post_type == 'paper') {
$single_template = dirname( __FILE__ ) . '/single-paper.php';
}
return $single_template;
}
add_filter( 'single_template', 'get_custom_post_type_single_template' );
我想为我的主题 (onepress) 使用的 content-____.php
模板做类似的事情来控制我的帖子在主要查询中的显示方式。
主题的 index.php
甚至说
<?php /* Start the Loop */ ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php
/*
* Include the Post-Format-specific template for the content.
* If you want to override this in a child theme, then include a file
* called content-___.php (where ___ is the Post Format name) and that will be used instead.
*/
get_template_part( 'template-parts/content', get_post_format() );
?>
<?php endwhile; ?>
但是我宁可不想为此实现一个子主题,并将所有与自定义帖子类型相关的代码保存在插件中。
有没有办法添加一个过滤器,使 get_template_part( 'template-parts/content', get_post_format() );
使用我的插件为 paper
帖子提供的自定义模板和他们的标准模板的普通帖子?
我已经尝试过上面为'single_template'
使用的各种代码,但是无济于事。
最佳解决方案
Background
不幸的是,get_template_part()
功能没有任何合适的过滤器来实现你想要的。可以使用 get_template_part_{$slug}
动作钩来注入模板部分,但是,对主题或子主题没有任何改变,原始的模板部分将被添加。因此,您将无法替换现有的模板部件。
但是,您可以通过以下选项之一获得所需的结果:
选项 1:使用默认的 CSS 类:
如果只需要更改 paper
自定义帖子类型的样式,那么您可以简单地使用 WordPress 生成的 CSS 类。 WordPress 中的任何标准主题都将为帖子内容生成 $post_type
和 type-{$post_type}
CSS 类。例如,定制后期类型 paper
将具有 paper
& type-paper
CSS 类和一般 post
将具有 post
和 type-post
CSS 类。还有主页将 home
的 CSS 类放在正文中。因此,要在主页中定位 paper
条目,可以使用以下 CSS 规则:
body.home .type-paper {
/* Custom CSS for paper entries in the home page */
}
选项 2:修改 CSS 类:
如果默认的 CSS 类不足够,您还可以使用插件中的 post_class
过滤器钩子来修改 (添加/删除)CSS 类。喜欢这个:
add_filter( 'post_class', 'paper_post_class' );
function paper_post_class( $class ) {
if ( get_post_type() === 'paper' && is_home() ) {
// remove these classes
$remove = array( 'css-class-to-remove', 'another-class-to-remove' );
$class = array_diff( $class, $remove );
// add these classes
$add = array( 'custom-paper', 'my-paper-class' );
$class = array_merge( $add, $class );
}
return $class;
}
这样,您将能够删除不需要 paper
条目的 CSS 类,并为 paper
条目添加新的 CSS 类,而无需修改主题文件。然后使用这些 CSS 类根据需要更改 paper
条目的样式。
选项 3:修改模板& 模板部分
如果您只想定位 CSS 类,您的所需样式更改是不可能的,那么您也可以从插件中更改模板部分。但是,由于通过使用钩子替换由 get_template_part()
添加的模板部件是不可能的,因此您必须以某种方式更改模板,以便您可以从插件中修改 get_template_part()
调用。
为此,您可以定位 pre_get_posts
钩子功能,并使用 template_include
滤镜钩来修改主页模板,如下所示:
function add_custom_post_types_to_query( $query ) {
if ( is_home() && $query->is_main_query() ) {
$query->set( 'post_type', array( 'post', 'paper' ) );
// now also change the home page template, but only when this condition matches
add_filter( 'template_include', 'wpse258844_custom_template', 999 );
}
}
add_action( 'pre_get_posts', 'add_custom_post_types_to_query' );
然后使用以下 CODE(根据需要进行修改):
// for better file management, use a separate "theme-{$theme_name_slug}" directory within your plugin directory
// so if the active theme name is "OnePress", the directory name will be "theme-onepress"
// This will save you a ton of headache if you change the theme,
// as different themes may use different function calls within the templates, which other themes may not have
define( 'wpse258844_TEMPLATE_DIR', plugin_dir_path( __FILE__ ) . sprintf( 'theme-%s/', sanitize_title( wp_get_theme() ) ) );
function wpse258844_custom_template( $template ) {
// this file will replace your homepage template file
$index_paper = wpse258844_TEMPLATE_DIR . 'custom-home.php';
// file_exists() check may need clearing stat cache if you change file name, delete the file etc.
// Once you are done, comment out or remove clearstatcache(); in production
clearstatcache();
if ( file_exists( $index_paper ) ) {
$template = $index_paper;
}
return $template;
}
function wpse258844_get_template_part( $slug, $name = null ) {
if( get_post_type() === 'paper' ) {
// just to be consistant with get_template_part() function
do_action( "get_template_part_{$slug}", $slug, $name );
$located = '';
$name = (string) $name;
// file_exists() check may need clearing stat cache if you change file name, delete the file etc.
// Once you are done, comment out or remove clearstatcache(); in production
clearstatcache();
if ( '' !== $name && file_exists( wpse258844_TEMPLATE_DIR . "{$slug}-{$name}.php" ) ) {
$located = wpse258844_TEMPLATE_DIR . "{$slug}-{$name}.php";
}
else if ( file_exists( wpse258844_TEMPLATE_DIR . "{$slug}.php" ) ) {
$located = wpse258844_TEMPLATE_DIR . "{$slug}.php";
}
if ( '' != $located ) {
load_template( $located, false );
return;
}
}
get_template_part( $slug, $name );
}
一旦您在插件中找到上述 CODE(阅读 CODE 中的注释):
-
在你的插件目录中创建一个新的目录来保存主题模板文件,例如
theme-onepress
。如果你想用不同的主题来测试设计变化,我将来会帮助你 (我想这是所有这些混乱的主要目的)) 。 -
在新的
theme-onepress
目录中,创建一个名为custom-home.php
的文件。从您的主题 (可能是index.php
或home.php
或主题用于主页模板的任何主题) 复制主页模板的 CODE 。 -
现在在
custom-home.php
将get_template_part
的所有调用更改为wpse258844_get_template_part
。无需更改参数,只需要功能名称。上述 CODE 中的wpse258844_get_template_part()
功能与get_template_part()
功能相同,如果在插件的theme-{$theme_name_slug}
(例如theme-onepress
) 目录中找不到自定义模板部分,则可以恢复为默认行为。 -
最后,替换插件
theme-{$theme_name_slug}
目录中要替换的任何模板零件文件。例如,如果原始调用是get_template_part( 'template-parts/content', get_post_format() )
,并且要替换content.php
模板部分,那么只需将一个名为content.php
的文件放在插件的theme-onepress/template-parts
目录中。这意味着,theme-onepress
目录将表现为模板部件的子主题 – 即简单的 drop-in 替换。
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。