web-dev-qa-db-ja.com

プラグインを使用してメインのクエリにカスタム投稿タイプのカスタムコンテンツテンプレートパーツを追加する方法

私はWordPressプラグインでカスタム投稿タイプpaperを定義しています。これはメインのクエリで標準の投稿と一緒に表示されます。

function add_custom_post_types_to_query( $query ) {
    if ( is_home() && $query->is_main_query() )
        $query->set( 'post_type', array( 'post', 'paper' ) );
    // As was pointed out by Ihor Vorotnov this return is not necessary. 
    // return $query;
}
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'に対して上記で使用したコードのさまざまなバリエーションを試しましたが、役に立ちません。

6
cgogolin

バックグラウンド

残念ながら get_template_part() functionはあなたが望むものを達成するのに適したフィルタを持っていません。 get_template_part_{$slug}アクションフックを使ってテンプレート部分を挿入することは可能ですが、あなたのテーマや子テーマを変更することなく、とにかく元のテンプレート部分が追加されます。そのため、この方法で既存のテンプレートパーツを置き換えることはできません。

ただし、以下のいずれかの方法で目的の結果を得ることができます。


オプション1:デフォルトのCSSクラスを使用します。

paperカスタム投稿タイプのスタイルを変更したいだけの場合は、WordPressによって生成されたCSSクラスを使用することができます。 WordPressのどの標準テーマでも、投稿コンテンツ用の$post_typeおよびtype-{$post_type} CSSクラスが生成されます。たとえば、カスタム投稿タイプpaperにはpapertype-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 filterフックを使用して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 filterフックを使用して、以下のようにホームページテンプレートを変更します。

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' ); 

その後、次のコードを使用します(必要に応じて変更します)。

// 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、またはあなたのテーマがホームページテンプレートに使っているものはなんでも)。

  3. custom-home.phpで、get_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ディレクトリはテンプレートパーツの子テーマのように動作します。つまり、単純なドロップイン置換です。

7
Fayaz

それのためにあなた自身の関数を作成してください:

function get_template_part_custom($content_name) {
     global $post;
     //its paper type?
     if ($post->post_type == 'paper') {
         //get template-parts/content-paper.php
         get_template_part( 'template-parts/content', $content_name );
     }else{
         //fallback to the default
         get_template_part( 'template-parts/content', get_post_format($post) );
     }
}

このように使用してください。

get_template_part_custom('paper');

投稿がpaper型の場合、ルートテーマフォルダのcontent-paper.phpというフォルダ内にtemplate-partsというファイルをロードしようとします。ファイルが存在しない場合は、content.phpをロードしようとします、 template-hierarchy を確認します。私はあなたがあなたのテンプレートを登録する必要があるとは思わないsingle-paper.php、WordPressはあなたのためにそれを拾います。

編集:

プラグインからテンプレートを読み込むには:

//load a custom file from the plugin
add_filter( 'template_include', 'return_our_template');

//Returns template file
function return_our_template( $template ) {

    // Post ID
    $post_id = get_the_ID();

    // For all other Types that arent ours
    if ( get_post_type( $post_id ) != 'paper' ) {
        return $template;
    }

    // Else use our custom template
    if ( is_single() ) {
        return get_custom_template( 'single' );
    }

}

//Get the custom template if is set
function get_custom_template( $template ) {

    // Get the slug
    $template_slug = rtrim( $template, '.php' );
    $template = $template_slug . '.php';

    // Check if a custom template exists in the theme folder, if not, load the plugin template file
    if ( $theme_file = locate_template( array( 'plugin_template/' . $template ) ) ) {
        $file = $theme_file;
    }
    else {
        //here path to '/single-paper.php'
        $file = PATH_TO_YOUR_BASE_DIR . $template;
    }
    //create a new filter so the devs can filter this
    return apply_filters( 'filter_template_' . $template, $file );
}
0
David Lee

私がソースコードから見ることができる限り、あなたが通常するようにあなたはget_template_part()をフィルターにかけることができません。 このスレッド を見てください。

0
Ihor Vorotnov

これは、求められたことを達成するためのもう1つの「ハック」です。

カスタム投稿タイプ用のカスタムテンプレートを使用するためにpost formatpost type!と混同しないでください)を使用することができます。行を覚えて

get_template_part( 'template-parts/content', get_post_format() );

質問に記載されているindex.phpに。この構造を通して、ほとんどの標準テーマはpost formatに応じて異なるテンプレートをロードします。

papername__などの特定のカスタム投稿タイプの投稿はすべて、特定の投稿形式、たとえばasidename__を持つことができます。

set_post_format( $post_id, 'aside' )

関数が'save_post'フックにフックされていて、以下のようなものを追加することによって

function paper_format_terms( $terms, $post_id, $tax ) {
    if ( 'post_format' === $tax && empty( $terms ) && 'paper' === get_post_type( $post_id ) ) {
        $aside = get_term_by( 'slug', 'post-format-aside', $tax );
        $terms = array( $aside );
    }
    return $terms;
}
add_filter( 'get_the_terms', 'paper_format_terms', 10, 3 );

'get_the_terms'フックに。

カスタム投稿フォーマットを定義することはできませんが、通常、他には使用されない投稿フォーマットが少なくとも1つあります。 'aside'形式は良い選択です。

標準のテーマは、papername__の投稿に遭遇したときはいつでもテンプレート.../template-parts/content-aside.phpを探します。やらなければいけないことは、テーマが更新されたときにそれが上書きされたり削除されたりしないような方法で適切なテンプレートをテーマディレクトリにインストールすることです。これは、私が適切なテンプレートをpluginsディレクトリのfiel content-aside.phpに入れて、以下のように `` upgrader_process_complete 'にフックすることでできます

function install_aside_template_on_upgrade( $upgrader_object, $options ) {
    if ($options['type'] == 'theme' ) {
        $content_aside = plugin_dir_path( __FILE__ ) . 'content-aside.php';
        $template_parts_content_aside = get_stylesheet_directory() . '/template-parts/content-aside.php';

        copy($content_aside, $template_parts_content_aside);
    }
}
add_action( 'upgrader_process_complete', 'install_aside_template_on_upgrade',10, 2);

このようにして、テーマが更新されるたびにcontent-aside.phpがテーマディレクトリにコピーされます。

これはかなりひどいハックであり、望ましくない副作用をもたらす可能性があることに注意してください。それでも、私はこれがいくつかのために役立つことができると思いました...

0
cgogolin

投稿された質問に対する正確な回答ではありませんが、このページに掲載される多くの人にとって実際に最適な解決策になると思われる、同様の何かを達成するためのさらにクリーンで簡単な方法があります。私には、この質問をしてから要件が少し変わったので、最終的にこの解決策に進むことができました。

カスタムテーマを使用する代わりに、多くの場合、テーマのテンプレートがthe_excerpt()を呼び出したときにカスタム投稿タイプが返すものを変更するだけで十分です。これは、次のように'the_excerpt'フィルタにフックすることで実現できます。

function paper_get_the_excerpt ($content) {
    global $post;
    $post_id = $post->ID;
    if ( get_post_type($post_id) === 'paper' ) {
        [do whatever you want with $content]
    }
    return $content;
}
add_filter( 'the_excerpt', 'paper_get_the_excerpt' );

きれいでシンプルで、テンプレートを変更するのと同じくらい柔軟性があります。

0
cgogolin