问题描述

我有一个自定义的帖子类型 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_typetype-{$post_type} CSS 类。例如,定制后期类型 paper 将具有 paper& type-paper CSS 类和一般 post 将具有 posttype-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 中的注释):

  1. 在你的插件目录中创建一个新的目录来保存主题模板文件,例如 theme-onepress 。如果你想用不同的主题来测试设计变化,我将来会帮助你 (我想这是所有这些混乱的主要目的)) 。

  2. 在新的 theme-onepress 目录中,创建一个名为 custom-home.php 的文件。从您的主题 (可能是 index.phphome.php 或主题用于主页模板的任何主题) 复制主页模板的 CODE 。

  3. 现在在 custom-home.phpget_template_part 的所有调用更改为 wpse258844_get_template_part 。无需更改参数,只需要功能名称。上述 CODE 中的 wpse258844_get_template_part()功能与 get_template_part()功能相同,如果在插件的 theme-{$theme_name_slug}(例如 theme-onepress) 目录中找不到自定义模板部分,则可以恢复为默认行为。

  4. 最后,替换插件 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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。