Шаблон страницы как Пользовательский архив типов записей
Моя цель - заполучить слизняка www.domain.com/resources используется шаблоном страницы , а не страницей архива , и имеет отдельные сообщения CPT в качестве дочерних элементов этого слизняка, такие как www.domain.com/resources/post
.
Решение, которое, как я думал, сработает:
Я создал новую страницу в Wordpress и дал ей пользовательский шаблон страницы. Я также регистрирую свой пользовательский тип записи следующим образом. Обратите особое внимание на has_archive и переписать:
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 на отдельных страницах сообщений.
Я в тупике, пожалуйста, посоветуйте!
3 answers
Начиная с версии WordPress 4.4 крюк 'theme_page_templates'
позволяет устанавливать произвольные шаблоны страниц.
Это означает, что можно отображать произвольные значения в меню "Шаблон страницы" на экране редактирования страницы, и при выборе этого параметра значение будет сохранено в мета-файле шаблона страницы для страницы.
Это означает, что вы можете "автоматически" создать шаблон страницы для любого зарегистрированного 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;
}
);
} );
С этим кодом на месте, предполагая, что вы зарегистрировали тип записи resources
с has_archive
, установленным в true
, при создании или редактировании страницы вы увидите в раскрывающемся списке "Шаблон страницы" шаблон страницы с именем Archive: Resources
.
Вы можете выбрать этот шаблон при создании страницы, которую хотите использовать для отображения ваших сообщений resources
.
Перенаправление прямого доступа к странице
Поскольку эта страница является архивом, а не страницей, вы можете использовать некоторый код для перенаправления пользователей на фактическую Архив 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);
}
}
}
Вы можете использовать функцию выше, чтобы написать две дополнительные функции для получения заголовка и содержимого страницы:
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;
?>
Таким образом, ваш URL-адрес архива CPT будет example.com/resources/
, а ваш единственный URL-адрес CPT будет example.com/resources/post-name/
таким, как вы хотите.
В то же время вы сможете писать содержимое и заголовок (и пользовательские поля, если вы хотите), специфичный для типа сообщения.
Кроме того, учтите, что этот метод можно использовать повторно для любого типа сообщений, которые у вас есть или могут быть использованы в будущем.
Ответ Gmazzap отличный! Я просто хотел бы добавить, что начиная с версии 4.1 появились две новые функции, которые идеально подходят для этого варианта использования: 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;
} );
Мой собственный метод для этого кажется явно пещерным человеком после прочтения двух предыдущих ответов, но я все равно поделюсь им, потому что, хотя он и не такой надежный, его невероятно легко настроить. Это также упрощает для авторов контента понимание того, где редактировать "обзорный" контент для данного архива в структуре сайта, в основном основанной на странице/стиле CMS.
Для типа post_type с именем region
я бы зарегистрировал его вместе с фактической страницей WP с именем regions
.
Создайте шаблон под названием page-regions.php
(или любую другую стратегию, которую вы хотите использовать для подключения этой страницы) и выполните пользовательский цикл для извлечения всех типов post_types региона. Если вы используете части шаблонов для своих шаблонов, достаточно просто включить заголовок страницы и основной текст, чтобы ваш код оставался СУХИМ. Это также очень легко настроить, потому что всегда есть этот один тип 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) без обзорного содержимого из страница, но я просто не ссылаюсь на нее. Если пользователи URL-бара попадут туда, ничего страшного.
Небольшой дополнительный бонус: вы можете сделать URL-адрес страницы обзора/архива любым, каким захотите, скажем /regions-of-the-world
.