Вложенные пользовательские типы записей с постоянными ссылками

9

Я пытаюсь настроить многоуровневую структуру пользовательских типов записей с постоянными ссылками, которые выглядят как authors/books/chaptersавторы, книги и главы, настроенные как их собственные пользовательские типы записей. Например, типичный URL на этом сайте может выглядетьexample.com/authors/stephen-king/the-shining/chapter-3/

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

Я в большинстве случаев просто настраиваю каждый пользовательский пост как дочерний элемент в CPT на один уровень выше. Например, я создаю «Главу 3» и назначаю «Сияющий» в качестве родителя, используя собственный мета-блок. «Сияющий», в свою очередь, имеет «Стивена Кинга» в качестве родителя. У меня не было проблем с созданием этих отношений.

Я использую теги перезаписи в слагах CPT, и постоянные ссылки хотят работать, но они не совсем правы. Используя анализатор перезаписи, я вижу, что правила перезаписи фактически генерируются, но, похоже, они не в правильном порядке, поэтому сначала обрабатываются другие правила.

Вот скриншот моего анализатора перезаписи.

Вот как я зарегистрировал свои CPT:

function cpt_init() {

  $labels = array(
    'name' => 'Authors'
   );

  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'show_in_menu' => true, 
    'query_var' => true,
    'rewrite' => array(
        'slug' => 'author',
        'with_front' => FALSE,
    ),
    'with_front' => false,
    'capability_type' => 'post',
    'has_archive' => false, 
    'hierarchical' => true,
    'menu_position' => null,
    'supports' => array( 'title', 'editor' )
  ); 

  register_post_type('authors',$args);

  $labels = array(
    'name' => 'Books'
  );

  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'show_in_menu' => true, 
    'query_var' => true,
    'rewrite' => array(
        'slug' => 'author/%authors%',
        'with_front' => FALSE,
    ),
    'with_front' => false,
    'capability_type' => 'post',
    'has_archive' => false, 
    'hierarchical' => true,
    'menu_position' => null,
    'supports' => array( 'title', 'editor' )
  ); 

  register_post_type('books',$args);


  $labels = array(
    'name' => 'Chapters'
   );

  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'show_in_menu' => true, 
    'query_var' => true,
    'rewrite' => array(
        'slug' => 'author/%authors%/%books%',
        'with_front' => FALSE,
    ),
    'with_front' => FALSE,
    'capability_type' => 'post',
    'has_archive' => false, 
    'hierarchical' => true,
    'menu_position' => null,
    'supports' => array( 'title', 'editor' )
  ); 

  register_post_type('chapters',$args);

}

add_action( 'init', 'cpt_init' );

Так есть ли способ изменить приоритет моих правил переписывания, чтобы сначала сопоставлялись все авторы, книги и главы?

Я также знаю, что мне придется добавить post_type_linkфильтр, но это кажется второстепенным для получения правильных постоянных ссылок. Если кто-нибудь знает, где я могу найти исчерпывающий обзор того, как работает этот фильтр, это будет оценено.

Dalton
источник
Вы рассматривали только использование страниц? Вы получите правильную структуру постоянных ссылок автоматически.
Майкл Хэмптон
Я определенно обдумал это. Проблема со страницами в том, что у нас может быть 100 элементов внука для одного автора, которыми будет очень трудно управлять в администраторе страниц. Кроме того, мы должны иметь возможность выполнять запрос по типу поста.
Далтон
Я работаю над решением, но у меня есть быстрый вопрос: является ли ключевым иметь «автора» перед каждой постоянной ссылкой? Потому что это похоже на сторонника. Я думаю, что WordPress немного сбивает с толку, тем более что это постоянная ссылка, также используемая для страниц автора WP. Если требуется наличие «автора», я думаю, что все это еще выполнимо ... это будет только сложнее.
Рейчел Карден
К сожалению, я не осознавал, что автор будет конфликтовать со слагом автора встроенного WP. Нет, это не обязательно, это может быть что угодно. Я предположил, что мне нужно что-то там, потому что это CPT, но это могут быть и «писатели», или что-то еще.
Далтон
Я понял, что путаница на самом деле заключается в том, что CPT разделяют «автора» в качестве базового слизняка. После того как вы установили «автора» в качестве пуля для CPT «авторов», а затем вы установите «автор /% author%» для CPT «книги» и «author /% author% /% book%» для глав CPT. », тогда WordPress считает посты для« книг »и посты для« глав »буквально иерархическими дочерними постами для« авторов ». Имеет ли это смысл? В моем тестировании вы могли оставить «автора» в качестве основы для «авторов» CPT, и это работает просто отлично. Так что замените мой предыдущий вопрос на: вам нужен 'author' или слаг может начинаться с% author%?
Рейчел Карден

Ответы:

11

Если вы хотите оставить «авторов» в качестве основного слагаемого в постоянных ссылках, например, example.com/authors/stephen-king/ для CPT «авторов», example.com/authors/stephen-king/the-shining/ для CPT «books» и example.com/authors/stephen-king/the-shining/chapter-3/ для CPT «chapters», WordPress будет думать, что почти все - это пост «авторов» или иерархический потомок «авторов» ', и, поскольку это не так, WordPress в конечном итоге становится очень запутанным.

С учетом вышесказанного, есть обходной путь, который является довольно базовым, но при условии, что ваша структура постоянных ссылок всегда следует одному и тому же порядку, то есть за словом «авторы» всегда следует слаг автора, за которым всегда следует слаг книги, за которым всегда следует если у вас есть глава, то вам нужно идти.

В этом решении нет необходимости определять слизень перезаписи в пользовательском определении типа записи для «глав» и «книг», но установите слаг «перезапись авторов» просто как «авторы», поместите следующий код в ваши functions.php файл и "очистить" ваши правила перезаписи.

add_action( 'init', 'my_website_add_rewrite_tag' );
function my_website_add_rewrite_tag() {
    // defines the rewrite structure for 'chapters', needs to go first because the structure is longer
    // says that if the URL matches this rule, then it should display the 'chapters' post whose post name matches the last slug set
    add_rewrite_rule( '^authors/([^/]*)/([^/]*)/([^/]*)/?','index.php?chapters=$matches[3]','top' );
    // defines the rewrite structure for 'books'
    // says that if the URL matches this rule, then it should display the 'books' post whose post name matches the last slug set
    add_rewrite_rule( '^authors/([^/]*)/([^/]*)/?','index.php?books=$matches[2]','top' );   
}

// this filter runs whenever WordPress requests a post permalink, i.e. get_permalink(), etc.
// we will return our custom permalink for 'books' and 'chapters'. 'authors' is already good to go since we defined its rewrite slug in the CPT definition.
add_filter( 'post_type_link', 'my_website_filter_post_type_link', 1, 4 );
function my_website_filter_post_type_link( $post_link, $post, $leavename, $sample ) {
    switch( $post->post_type ) {

        case 'books':

            // I spoke with Dalton and he is using the CPT-onomies plugin to relate his custom post types so for this example, we are retrieving CPT-onomy information. this code can obviously be tweaked with whatever it takes to retrieve the desired information.
            // we need to find the author the book belongs to. using array_shift() makes sure only one author is allowed
            if ( $author = array_shift( wp_get_object_terms( $post->ID, 'authors' ) ) ) {
                if ( isset( $author->slug ) ) {
                    // create the new permalink
                    $post_link = home_url( user_trailingslashit( 'authors/' . $author->slug . '/' . $post->post_name ) );
                }
            }

            break;

        case 'chapters':

            // I spoke with Dalton and he is using the CPT-onomies plugin to relate his custom post types so for this example, we are retrieving CPT-onomy information. this code can obviously be tweaked with whatever it takes to retrieve the desired information.
            // we need to find the book it belongs to. using array_shift() makes sure only one book is allowed
            if ( $book = array_shift( wp_get_object_terms( $post->ID, 'books' ) ) ) {

                // now to find the author the book belongs to. using array_shift() makes sure only one author is allowed
                $author = array_shift( wp_get_object_terms( $book->term_id, 'authors' ) );

                if ( isset( $book->slug ) && $author && isset( $author->slug ) ) {
                    // create the new permalink
                    $post_link = home_url( user_trailingslashit( 'authors/' . $author->slug . '/' . $book->slug . '/' . $post->post_name ) );
                }

            }

            break;

    }
    return $post_link;
}

Узнайте больше о плагине CPT-onomies

Рейчел Карден
источник
Это работает отлично, спасибо! Я чувствую, что только что многому научился. Плагин CPT-onomies тоже действительно классный. wordpress.org/extend/plugins/cpt-onomies
Далтон
У меня есть ощущение, что вы можете столкнуться с некоторыми препятствиями по мере роста вашей «библиотеки», но у меня уже есть некоторый код, поэтому, если вы это сделаете, просто дайте мне знать.
Рэйчел Карден
@RachelCarden Что вы делаете, когда две книги имеют одинаковое название, но разных авторов? Там будет столкновение в переписанном URL! Как вы решаете это?
Segfault
1
@Segfault Вам нужно будет получить все авторские слагы, чтобы вы могли жестко запрограммировать их в правило (ы) перезаписи: foreach ($ author_slugs as $ author_slug) {add_rewrite_rule ('^ авторы /'. $ Author_slug. '/ ([ ^ /] *) / ([^ /] *) /? ',' index.php? авторы = '. $ author_slug.' & chapters = $ match [2] ',' top '); add_rewrite_rule ('^ авторы /'. $ author_slug. '/([^/]*)/?','index.php?authors='. $ author_slug. '& books = $ match [1]', 'top') ; }
Рэйчел Карден
@Segfault Вы можете использовать get_terms () , если вы используете CPT-ономию, или get_posts (), чтобы получить названия постов / слагов.
Рэйчел Карден
4

У меня нет личного опыта с таким сценарием, но Рэнди Хойт на прошлых выходных сделал презентацию на WordCamp San Fran о «типах подчиненных постов», которая звучит так, как вы говорите.

Вот его страница для выступления, которая включает слайды презентации и ссылки на плагин, который он создал для работы с подчиненными типами записей : http://randyhoyt.com/wordpress/subordinate-post-types/

mannieschumpert
источник
Спасибо, это похоже на хороший ресурс. Не ясно, поддерживает ли это отношения с внуками, хотя (в моем тестировании это не так) и не помогает с постоянными ссылками. Я уже нашел способ установить отношения между ребенком и родителем (хотя это довольно хороший способ сделать это), но постоянные ссылки - это действительно проблема, с которой я застрял сейчас.
Далтон
1

Правила будут добавлены к extra_rules_top в WP_Rewrite в порядке добавления дополнительных пермаструктур. Таким образом, переключение порядка, в котором вы регистрируете типы записей, изменит порядок генерации правил перезаписи, в результате чего сначала переписывается глава. Однако, так как вы используете query_var из других post_types, wp_query может в конечном итоге соответствовать одному из них в качестве имени запрашиваемого поста, прежде чем соответствовать главе, как вы хотите.

Я хотел бы создать новые теги перезаписи, чтобы представить заполнители для родительского автора и родительской книги, то есть:

add_rewrite_tag('%parent-book%', '([^/]+)', 'parent_book=');

При этом вам нужно будет отфильтровать 'query_vars', чтобы сделать 'parent_book' общедоступным. Затем вам нужно добавить фильтр в pre_get_posts, который преобразует имя, установленное в качестве parent_book query_var, в post_id и устанавливает его как «post_parent».

prettyboymp
источник
Не могли бы вы предоставить примеры кода для фильтров, которые вы упомянули? Кроме того, как будет выглядеть тег перезаписи для CPT внука?
Дальтон