Шаблон страницы как Пользовательский архив типов записей


Моя цель - заполучить слизняка 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 на отдельных страницах сообщений.

Я в тупике, пожалуйста, посоветуйте!

Author: Pieter Goosen, 2015-03-23

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/ таким, как вы хотите.

В то же время вы сможете писать содержимое и заголовок (и пользовательские поля, если вы хотите), специфичный для типа сообщения.

Кроме того, учтите, что этот метод можно использовать повторно для любого типа сообщений, которые у вас есть или могут быть использованы в будущем.

 11
Author: gmazzap, 2016-03-21 14:59:30

Ответ 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;
} );
 2
Author: kraftner, 2017-04-13 12:37:55

Мой собственный метод для этого кажется явно пещерным человеком после прочтения двух предыдущих ответов, но я все равно поделюсь им, потому что, хотя он и не такой надежный, его невероятно легко настроить. Это также упрощает для авторов контента понимание того, где редактировать "обзорный" контент для данного архива в структуре сайта, в основном основанной на странице/стиле 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.

 0
Author: Will, 2016-03-19 00:24:47