web-dev-qa-db-ja.com

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

私のお気に入りのWordpress テンプレート階層 は、テンプレートを選択するためにWordpressでページを編集する必要なしに、スラッグによってページのテンプレートファイルを素早く作成する機能です。

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

page- {slug} .php

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

single- {post_type} - {slug} .php

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

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

19
supertrue

A)コアのベース

コーデックスで テンプレート階層の説明を見るとわかるように、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)ソリューション

私たちはonlyだけを前にロードする1つのテンプレートで階層を拡張したいので実際の"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チケット

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

19
kaiser

Template Hierarchy image に続いて、そのような選択肢は見当たりません。

だから私はそれをどうやってやろうと思っているのですか。

解決策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チェックを追加しました

3
Shane

(4年前から)トップの答えはもはや機能しませんが、WordPressのcodex はここで解決策を持っています

<?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 );
?>
2
skladany

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

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

再利用可能なコード

コードの重複は、良い習慣ではありません。時間が経過すると、コードベースが大きく肥大化し、開発者にとって管理が非常に困難になります。スラッグごとにテンプレートを作成する代わりに、一対一のポストツーテンプレートの代わりに再利用できる一対多のテンプレートが必要になるでしょう。

コード

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

これはちょっと遅い答えですが、私が言うことができる限り、Web上の誰もこのアプローチを文書化していないので、私はそれが価値があると思いました。これが誰かに役立つことを願っています。

1
Brian Fegter

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

上記のKaiserの答えに基づいて、私はこのコードを書きました。それはうまくいきます。
注意。 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 );
}

私は今、gregory-cpt-track-tax-serendipity.phpおよびgregory-cpt-album-tax-serendipity.phpという名前のテンプレートを作成でき、WPはそれらを自動的に使用します。 'tax-serendipity'は最初のアルバム分類学用語のナメクジです。

参考までに、 'single_template'フィルタフックは次のように宣言されています。
/wp-includes/theme.php:get_query_template()

サンプルコードをありがとうKaiser。

乾杯、グレゴリー

1
Gregory

Briansコードを更新しました。ドロップダウンボックスが使用されていなかったとき、 "default"テンプレートオプションがwp_page_templateに保存されていたため、defaultという名前のテンプレートが検索されました。この変更では、保存時に "default"オプションのみがチェックされ、代わりにpost metaが削除されます(templateオプションをデフォルトに戻した場合に便利です)。

 elseif(MY_CUSTOM_POST_TYPE === $ _POST ['post_type']){
 if(esc_attr($ _ POST ['_ wp_page_template'])=== "default"): 
 delete_post_meta($ post_id、 '_wp_page_template'); 
 else:
 update_post_meta($ post_id、 '_wp_page_template'、esc_attr($ _ POST ['_ wp_page_template'])); 
 endif; 
} 
0
Mark