私の目標は、スラッグwww.domain.com/resourcesをArchive PageではなくPage Templateで使用し、そのスラッグの子として単一のCPT投稿を作成することです。 www.domain.com/resources/post
。
私はうまくいくだろうと思った解決策:
Wordpressで新しいページを作成し、それにカスタムページテンプレートを付けました。以下のように私のカスタム投稿タイプも登録しています。 has_archive および rewrite に特に注意してください。
function bb_resources() {
register_post_type( 'resources', array(
'labels' => array(
'name' => 'Resources',
'singular_name' => 'Resource',
),
'taxonomies' => array('resources_cat'),
'public' => true,
'has_archive' => false,
'show_ui' => true,
'supports' => array( 'title', 'editor' ),
'rewrite' => array('slug'=>'resources', 'with_front'=>false),
) );
}
ただし、これは単一の投稿ページに404を作成します。
私は困惑している、アドバイスしてください!
WordPressバージョン4.4以降、フック 'theme_page_templates'
で任意のページテンプレートを設定することができます。
つまり、ページ編集画面の[Page Template]メニューに任意の値を表示することができ、選択するとその値がそのページのページテンプレートメタに保存されます。
これは、あなたが「自動的に」登録されたCPTのいずれかのためのページテンプレートを作成できることを意味します。
コードは次のようになります。
add_action( 'current_screen', function( \WP_Screen $screen ) {
if( 'page' !== $screen->id || 'post' !== $screen->base ) {
return;
}
// retrieve CPT objects with archive
$types = get_post_types( ['has_archive' => true], 'objects' );
// store CPT slug and labels in an array
$menu = array();
foreach( $types as $cpt ) {
$menu[ $cpt->name ] = 'Archive: ' . $cpt->label;
}
// merge with page templates
$menu and add_filter(
'theme_page_templates',
function( array $templates ) use ( $menu ) {
$templates = array_merge( $templates, $menu );
return $templates;
}
);
} );
このコードを配置した状態で、ページを作成または編集するときにhas_archive
をresources
に設定して投稿タイプtrue
を登録したと仮定すると、[ページテンプレート]ドロップダウンにArchive: Resources
という名前のページテンプレートが表示されます。
あなたはあなたがあなたのresources
投稿を表示するのに使いたい、あなたがページを作成するときそのテンプレートを選ぶことができます。
このページは1ページ以上のアーカイブなので、ページにアクセスしたときにユーザーを実際のCPTのアーカイブにリダイレクトするコードを使用できます。
add_action( 'template_redirect', function() {
if( is_page_template() ) {
// current page templates
$template = get_page_template_slug( get_queried_object_id() );
// array of CPT names, filtering the ones with archives
$types = get_post_types( array( 'has_archive' => true ), 'names' );
// if the current template is one of the CPT, redirect
if( in_array( $template, $types, true ) ) {
wp_safe_redirect( get_post_type_archive_link( $template ) );
exit();
}
}
} );
記事を閲覧するときには、おそらくそのページのコンテンツとタイトルを使用したいでしょう。
それでは、特定の投稿タイプのページを取得できるようにする関数を書きましょう。
function get_archive_page( $post_type = '' ) {
// if no CPT given, let's use the current main query to get it
if( ! $post_type ) {
global $wp_query;
$query_var = ( array ) $wp_query->get( 'post_type' );
$post_type = reset($query_var);
}
// if we have a valid post type
if( post_type_exists( $post_type ) ) {
// let's query the first page that has a page template
// named after the the post type
$posts = get_posts( array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => 1,
'orderby' => 'menu_order',
'order' => 'ASC',
'meta_query' => array( array(
'key' => '_wp_page_template',
'value' => $post_type
) )
) );
// if we have results, return first (and only) post object
if( $posts ) {
return reset($posts);
}
}
}
上記の関数を使って、ページのタイトルと内容を取得するための2つの追加関数を書くことができます。
function get_archive_page_title( $post_type = '' ) {
$page = get_archive_page( $post_type );
return ( $page ) ? get_the_title( $page ) : '';
}
function get_archive_page_content( $post_type = '' ) {
$page = get_archive_page( $post_type );
$content = '';
if( $page ) {
setup_postdata( $page );
ob_start();
the_content();
$content = ob_get_clean();
wp_reset_postdata();
}
return $content;
}
function the_archive_page_title() {
echo get_archive_page_title();
}
function the_archive_page_content() {
echo get_archive_page_content();
}
関数名はそれらが何をするのかを明確にするはずです。
カスタムフィールドが必要な場合は、get_archive_page_meta()
のような関数を書くこともできます。
これで、archive.php
(またはarchive-resources.php
)テンプレートで、上記の関数を使用してアーカイブページのタイトルと内容を表示できます。
それは次のようになります。
<h1><?php the_archive_page_title(); ?></h1>
<div><?php the_archive_page_content(); ?></div>
<?php
while( have_posts() ) : the_post();
// loop stuff here
endwhile;
?>
これにより、CPTアーカイブのURLはexample.com/resources/
になり、単一のCPTのURLはexample.com/resources/post-name/
になります。
同時に、投稿タイプに固有のコンテンツとタイトル(および必要に応じてカスタムフィールド)を書くことができます。
また、このメソッドはどの投稿タイプにも再利用可能であると考えてください。
gmazzap の 答え はすごい!私は4.1以降、そのユースケースにぴったり合う2つの新しい関数、 the_archive_title
と the_archive_description
を追加したいと思います。すでにそれらを使用しているテーマ(二十五十五のような)のためにあなたがテーマテンプレートを編集する代わりにこれをする最後の部分をスキップすることができます:
add_filter( 'get_the_archive_title', function( $title ) {
if( is_post_type_archive() ) {
$page = get_archive_page( $post_type ); // Function Found in @gmazzap's answer
$title = $page ? get_the_title( $page ) : $title;
}
return $title;
} );
add_filter( 'get_the_archive_description', function( $content ) {
if( is_post_type_archive() ) {
$page = get_archive_page( $post_type ); // Function Found in @gmazzap's answer
$content = '';
if( $page ) {
setup_postdata( $page );
ob_start();
the_content();
$content = ob_get_clean();
wp_reset_postdata();
}
$content = ( $content !== '' ) ? get_the_title( $page ) : $content;
}
return $content;
} );
これに対する私自身の方法は、前の2つの答えを読んだ後は明らかに穴が開いているように感じますが、私はとにかくそれを共有します。また、コンテンツ作成者にとって、ページベースの/ CMSスタイルのサイト構造で、特定のアーカイブの「概要」コンテンツをどこで編集するかを知るのは簡単ではありません。
region
と呼ばれるpost_typeについては、regions
と呼ばれる実際のWPページと共にそれを登録します。
page-regions.php
というテンプレート(またはそのページをそのページに接続するために使用する任意の戦略)を作成し、カスタムループを実行してすべての領域post_typeをプルします。テンプレートにテンプレート部分を使用する場合は、ページヘッダーと本文も含めるのが簡単で、コードはDRYのままです。 always という1つのpost_typeがあるため、カスタマイズも非常に簡単です。 :)
これにより、URLは わずかに になりますが、要求したものとは異なります。
http://example.com/regions アーカイブの投稿があるページの
http://example.com/region/africa または
http://example.com/region/asia 単一のCPTビューの場合。
しかし私にとっては、/region/africa
は実際には/regions/africa
よりも理にかなっていますが、それは標準であるRails/cakephpサイトで作業することによって推進されるかもしれません。 /region
だけで、(あなたがpost_typeをどのように設定したかによって)post_type = regionアーカイブになることになりますが、私は単にそれにリンクしません。 URLバーのサーファーがそこに着いても大したことはない。
やや副次的なボーナス:/regions-of-the-world
のように、オーバービュー/アーカイブページのURLを好きなように作ることができます。