カスタムの投稿タイプにはsingle-{$ post_type}-{slug} .php


20

Wordpress テンプレート階層の私のお気に入りの部分は、テンプレートを選択するためにWordpressでページを編集しなくても、スラッグごとにページのテンプレートファイルをすばやく作成できることです。

現在これを行うことができます:

page- {slug} .php

しかし、私はこれをできるようにしたいと思います:

single- {post_type}-{slug} .php

たとえば、というタイプreviewの投稿で、「My Great Review」という投稿のテンプレートを作成できます。single-review-my-great-review.php

誰かこれを前に設定しましたか? single-{post_type}-{slug}.php


以前にそのような設定を使用したことはありませんが、複雑すぎる場合は、テンプレートファイルを作成して問題のレビューに関連付けてみませんか。
シェーン

WP 3.4は自動的にフェッチsingle-{post_type}-{slug}.phpするため、WP 3.4へのアップグレードは別のオプションです。
-yitwail

回答:


19

A)コアのベース

Codex Template Hierarchyの説明でわかるように、single-{$post_type}.phpすでにサポートされています。


B)コア階層の拡張

現在、いくつかのフィルターとフックが内部にあり/wp-includes/template-loader.phpます。

  • do_action('template_redirect');
  • apply_filters( 'template_include', $template )
  • AND:内部の特定のフィルターget_query_template( $type, ... )"$type}_template"

B.1)仕組み

  1. テンプレートローダーファイル内で、テンプレートはクエリvar / wp_query条件:によって読み込まれますis_*()
  2. その後、条件がトリガーされます(「単一」テンプレートの場合): is_single() && $template = get_single_template()
  3. これはその後、トリガーget_query_template( $type, $templates )、どこ$typesingle
  4. 次に、"{$type}_template"フィルターがあります

C)ソリューション

私たちがしたようにのみ取得しますつのテンプレートで階層を拡張したいの前にロードされた実際の"single-{$object->post_type}.php"テンプレート、我々は階層を傍受し、テンプレート配列の先頭に新しいテンプレートを追加します。

// Extend the hierarchy
function add_posttype_slug_template( $templates )
{

    $object = get_queried_object();

    // New 
    $templates[] = "single-{$object->post_type}-{$object->post_name}.php";
    // Like in core
    $templates[] = "single-{$object->post_type}.php";
    $templates[] = "single.php";

    return locate_template( $templates );    
}
// Now we add the filter to the appropriate hook
function intercept_template_hierarchy()
{
    add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
}
add_action( 'template_redirect', 'intercept_template_hierarchy', 20 );

注:(デフォルトのオブジェクトスラッグ以外のものを使用する場合)$slugパーマリンク構造に応じて調整する必要があります。グローバルから必要なものを使用してください(object) $post

Tracチケット

上記のアプローチは現在サポートされていないため(この方法で絶対パスをフィルタリングすることしかできません)、ここにtracチケットのリストがあります:


これをテストしたいのですが、最後のadd_filter行に何かが欠けているようです。
スーパートゥルー

@supertrue良いキャッチ。:) )フィルタ内に別の行方不明が見つかりました。一定。たぶん、テンプレート内のスラッグの前にダッシュを下線と交換したいかもしれません。テンプレートを見たときに、接尾辞を目立たせるためです。
カイザー

サイト全体でこのエラーが発生します:警告: array_unshift()[function.array-unshift]:最初の引数は[array_unshiftを含む行]の配列である必要があります
12

わかりましたが、その後、別の何かがコアテンプレートをインターセプトしています。関数は正常に機能し$templates、配列です。このペーストビンのコア機能を参照してください(有効期限なし)。プラグインとデフォルトテーマのないインストールでこれをテストしてください。次に、1つずつアクティブにし、エラーが引き続き発生するかどうかを確認します。
カイザー

ええ、私はこれをデバッグし、最初に見つかったテンプレートの最終的な絶対パスを文字列として取得します。答えを変更する前に、これについてコア開発者と話をする必要があります。また、私slugは何かを混ぜました:用語と分類法でのみ利用可能です。$post->post_nameパーマリンク構造に適合するものに置き換える必要があります。現在、perma structおよびrewriteルールに応じてパスを取得および置換するすべてのケースでこれを自動的に行う方法はありません。別のアップデートを期待してください。
カイザー

4

テンプレート階層画像に続いて、このようなオプションは表示されません。

だから私はそれについてどうやって行くかをここに示します:

ソリューション1(私の意見では最高)

テンプレートファイルを作成し、レビューに関連付けます

 <?php
 /*
 Template Name: My Great Review
 */
 ?>

テーマディレクトリにテンプレートphpファイルを追加すると、投稿の編集ページにテンプレートオプションとして表示されます。

解決策2

これはおそらくtemplate_redirectフックを使用して実現できます。

functions.phpファイル内:

 function my_redirect()
 {
      global $post;

      if( get_post_type( $post ) == "my_cpt" && is_single() )
      {
           if( file_exists( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' ) )
           {
                include( get_template_directory() . '/single-my_cpt-' . $post->post_name . '.php' );
                exit;
           }
      }
 }
 add_action( 'template_redirect', 'my_redirect' );

編集

file_existsチェックを追加


どうしてexit;そこにいるの?
カイザー

@kaiser当時私が従ったどんなチュートリアルにも参加しているに違いありません。必要でない場合は削除します。
シェーン

1
@kaiser:exit()デフォルトのテンプレートのロードを防ぐために必要です。
スクライブ

ソリューション1は、投稿ではなくページに対してのみ機能します。
IXN

2

(4年前の)一番上の答えはもう機能しませんが、WordPressコーデックには解決策があります

<?php
function add_posttype_slug_template( $single_template )
{
    $object = get_queried_object();
    $single_postType_postName_template = locate_template("single-{$object->post_type}-{$object->post_name}.php");
    if( file_exists( $single_postType_postName_template ) )
    {
        return $single_postType_postName_template;
    } else {
        return $single_template;
    }
}
add_filter( 'single_template', 'add_posttype_slug_template', 10, 1 );
?>

1

ページテンプレートを使用する

スケーラビリティの別のアプローチはpage、カスタム投稿タイプの投稿タイプにページテンプレートドロップダウン機能を複製することです。

再利用可能なコード

コードの複製は良い習慣ではありません。残業は、開発者が管理するのを非常に困難にするときに、コードベースに深刻な膨張を引き起こす可能性があります。スラグごとにテンプレートを作成する代わりに、1対1のポストツーテンプレートの代わりに再利用できる1対多のテンプレートが必要になる可能性が高くなります。

コード

# Define your custom post type string
define('MY_CUSTOM_POST_TYPE', 'my-cpt');

/**
 * Register the meta box
 */
add_action('add_meta_boxes', 'page_templates_dropdown_metabox');
function page_templates_dropdown_metabox(){
    add_meta_box(
        MY_CUSTOM_POST_TYPE.'-page-template',
        __('Template', 'rainbow'),
        'render_page_template_dropdown_metabox',
        MY_CUSTOM_POST_TYPE,
        'side', #I prefer placement under the post actions meta box
        'low'
    );
}

/**
 * Render your metabox - This code is similar to what is rendered on the page post type
 * @return void
 */
function render_page_template_dropdown_metabox(){
    global $post;
    $template = get_post_meta($post->ID, '_wp_page_template', true);
    echo "
        <label class='screen-reader-text' for='page_template'>Page Template</label>
            <select name='_wp_page_template' id='page_template'>
            <option value='default'>Default Template</option>";
            page_template_dropdown($template);
    echo "</select>";
}

/**
 * Save the page template
 * @return void
 */
function save_page_template($post_id){

    # Skip the auto saves
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
        return;
    elseif ( defined( 'DOING_AJAX' ) && DOING_AJAX )
        return;
    elseif ( defined( 'DOING_CRON' ) && DOING_CRON )
        return;

    # Only update the page template meta if we are on our specific post type
    elseif(MY_CUSTOM_POST_TYPE === $_POST['post_type'])
        update_post_meta($post_id, '_wp_page_template', esc_attr($_POST['_wp_page_template']));
}
add_action('save_post', 'save_page_template');


/**
 * Set the page template
 * @param string $template The determined template from the WordPress brain
 * @return string $template Full path to predefined or custom page template
 */
function set_page_template($template){
    global $post;
    if(MY_CUSTOM_POST_TYPE === $post->post_type){
        $custom_template = get_post_meta($post->ID, '_wp_page_template', true);
        if($custom_template)
            #since our dropdown only gives the basename, use the locate_template() function to easily find the full path
            return locate_template($custom_template);
    }
    return $template;
}
add_filter('single_template', 'set_page_template');

これは少し遅い回答ですが、私が知る限り、ウェブ上の誰もこのアプローチを文書化していないので、価値があると思いました。これが誰かを助けることを願っています。


1

私の場合、アルバム分類法によってリンクされたアルバムとトラックのカスタム投稿タイプがあります。アルバムの分類法に応じて、アルバムとトラックの投稿に異なるシングルテンプレートを使用できるようにしたかったのです。

上記のカイザーの答えに基づいて、私はこのコードを書きました。うまくいきます。
注意。add_action()は必要ありませんでした。

// Add an additional template option to the template hierarchy
add_filter( 'single_template', 'add_albumtrack_taxslug_template', 10, 1 );
function add_albumtrack_taxslug_template( $orig_template_path )
{
    // at this point, $orig_template_path is an absolute located path to the preferred single template.

    $object = get_queried_object();

    if ( ! (
        // specify another template option only for Album and Track post types.
        in_array( $object->post_type, array( 'gregory-cpt-album','gregory-cpt-track' )) &&
        // check that the Album taxonomy has been registered.
        taxonomy_exists( 'gregory-tax-album' ) &&
        // get the Album taxonomy term for the current post.
        $album_tax = wp_get_object_terms( $object->ID, 'gregory-tax-album' )
        ))
        return $orig_template_path;

    // assemble template name
    // assumption: only one Album taxonomy term per post. we use the first object in the array.
    $template = "single-{$object->post_type}-{$album_tax[0]->slug}.php";
    $template = locate_template( $template );
    return ( !empty( $template ) ? $template : $orig_template_path );
}

single-gregory-cpt-track-tax-serendipity.phpおよびsingle-gregory-cpt-album-tax-serendipity.phpという名前のテンプレートを作成できるようになり、WPはそれらを自動的に使用します。「tax-serendipity」は、最初のアルバム分類用語のスラッグです。

参照用に、「single_template」フィルターフックは
/wp-includes/theme.phpで宣言されています。get_query_template()

サンプルコードをありがとうございます。

乾杯、グレゴリー


こんにちはGreg-WPSEへようこそ。質問に対する回答として回答のみを投稿してください。フォローアップの質問ではありません。既存の回答では答えられず、コメントするには大きすぎる質問がある場合は、別の質問を開いてください:)
スティーブンハリス

1
文字列/配列の質問は削除されました:
グレゴリー

1
「サンプルコードをありがとうございました。」- どういたしまして。
kaiser

それはあなたのために働きますか?まず、「$ template」はコード内でコメント化しないでください。「$ album_tax [0]-> slug」の代わりに「$ object-> post_name」を使用する必要があると思います。
グレマティス

$ template行を修正しました。ありがとうございました。$ object-> post_name?いや それは投稿のスラッグを返しますが、投稿がリンクされているアルバムのスラッグが必要です。
グレゴリー

0

Briansコードの更新では、ドロップダウンボックスが使用されていないときに、「default」テンプレートオプションがwp_page_templateに保存されていたため、defaultというテンプレートを検索しようとしました。この変更は、投稿メタを保存および削除するときにオプション「デフォルト」をチェックするだけです(テンプレートオプションをデフォルトに戻した場合に便利です)。

elseif(MY_CUSTOM_POST_TYPE === $ _POST ['post_type']){

if(esc_attr($ _ POST ['_ wp_page_template'])=== "default"):
    delete_post_meta($ post_id、 '_wp_page_template');
その他:
    update_post_meta($ post_id、 '_wp_page_template'、esc_attr($ _ POST ['_ wp_page_template']));
endif;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.