問題描述

我有一個自定義的帖子類型 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。