Zagnieżdżone niestandardowe typy postów z linkami stałymi

9

Próbuję skonfigurować wielopoziomową niestandardową strukturę typu postu z permalinkami, które wyglądają tak authors/books/chapters, że autorzy, książki i rozdziały są skonfigurowane jako własne niestandardowe typy postów. Na przykład może wyglądać typowy adres URL tej witrynyexample.com/authors/stephen-king/the-shining/chapter-3/

Każdy rozdział może należeć tylko do jednej książki, a każda książka może należeć tylko do jednego autora. Rozważyłem zastosowanie taksonomii zamiast CPT dla autorów i książek, ale muszę powiązać metadane z każdym elementem i wolę do tego interfejs postu.

Jestem w większości przypadków, po prostu konfigurując każdy niestandardowy post jako dziecko wpisu w CPT o jeden poziom wyżej. Na przykład tworzę „Rozdział 3” i przypisuję „Lśnienie” jako element nadrzędny za pomocą niestandardowego meta-boxa. Z kolei „Lśnienie” ma „Stephena Kinga” jako rodzica. Nie miałem żadnych problemów z tworzeniem tych relacji.

Używam tagów przepisywania w ślimakach CPT i permalinki chcą działać, ale nie są w porządku. Za pomocą analizatora ponownego zapisu widzę, że reguły przepisywania są w rzeczywistości generowane, ale wydaje się, że nie są w odpowiedniej kolejności, dlatego najpierw przetwarzane są inne reguły.

Oto zrzut ekranu mojego analizatora przepisywania.

Oto jak zarejestrowałem moje 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' );

Czy jest więc jakiś sposób, aby zmienić priorytet moich reguł przepisywania, aby autorzy, książki i rozdziały były dopasowane najpierw?

Wiem też, że będę musiał dodać post_type_linkfiltr, ale wydaje się to drugorzędne w stosunku do uzyskania permalinków w pierwszej kolejności. Jeśli ktoś wie, gdzie mogę znaleźć kompleksowy przegląd działania tego filtra, byłoby to mile widziane.

Dalton
źródło
Czy zastanawiałeś się nad użyciem Pages? Uzyskasz automatycznie odpowiednią strukturę permalink.
Michael Hampton
Zdecydowanie to rozważyłem. Problem ze stronami polega na tym, że dla jednego autora możemy mieć 100 elementów wnuków, co będzie bardzo trudne w zarządzaniu przez administratora stron. Musimy także mieć możliwość zapytania według typu postu.
Dalton,
Pracuję nad rozwiązaniem, ale mam szybkie pytanie: czy kluczem jest mieć „autora” przed każdym łączem bezpośrednim? Ponieważ wydaje się, że jest to stickler. Myślę, że to trochę mylące WordPress, zwłaszcza, że ​​jest to zwykły link używany również na stronach autorów WP. Jeśli wymagane jest posiadanie „autora”, myślę, że cała sprawa jest nadal możliwa do wykonania… będzie to tylko bardziej skomplikowane.
Rachel Carden,
Ups, nie zdawałem sobie sprawy, że autor będzie miał konflikt z wbudowanym ślimakiem autora WP. Nie, to nie jest wymagane, może być cokolwiek. Zakładałem, że czegoś tam potrzebuję, ponieważ jest to CPT, ale równie dobrze mogą to być „pisarze” lub cokolwiek innego.
Dalton,
Uświadomiłem sobie, że zamieszanie polega na tym, że CPT dzielą się „autorem” jako ślimakiem podstawowym. Po ustawieniu „autora” jako informacji dla autorów CPT, a następnie ustawieniu „autor /% autor%” dla książek CPT i „autor /% autor% /% book%” dla rozdziałów CPT ”, a następnie WordPress uważa, że ​​posty dla„ książek ”i posty dla„ rozdziałów ”są dosłownie hierarchicznymi postami potomnymi dla„ autorów ”. Czy to ma sens? W moich testach możesz zatrzymać „autora” jako podstawę dla „autorów” CPT i działa to dobrze. Zastąp więc moje poprzednie pytanie: potrzebujesz „autora”, czy może ślimak zaczyna się od% autor%?
Rachel Carden,

Odpowiedzi:

11

Jeśli chcesz zachować „autorów” jako podstawowy ślimak w permalinkach, np. Przyklad.com/authors/stephen-king/ dla CPT „autorów”, przyklad.com/authors/stephen-king/the-shining/ dla „książki” CPT i example.com/authors/stephen-king/the-shining/chapter-3/ do „rozdziałów” CPT, WordPress pomyśli, że prawie wszystko jest postem „autorów” lub hierarchicznym dzieckiem „autorów” „post, a ponieważ tak nie jest, WordPress ostatecznie staje się bardzo zdezorientowany.

To powiedziawszy, istnieje obejście, które jest dość podstawowe, ale o ile twoja permalinkowa struktura zawsze ma tę samą kolejność, tzn. Po słowie „autorzy” zawsze jest autor ślimak, po którym zawsze następuje ślimak książki, po którym zawsze następuje ślimakiem z rozdziału, powinieneś już iść.

W tym rozwiązaniu nie ma potrzeby definiowania korekty przepisywania w niestandardowej definicji typu postu dla „rozdziałów” i „książek”, ale ustaw korekty przepisywania „Autorzy” jako po prostu „autorów”, umieść następujący kod w swoich funkcjach. Php plik i „opróżnij” swoje reguły przepisywania.

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;
}

Dowiedz się więcej o wtyczce CPT-onomies

Rachel Carden
źródło
Działa to doskonale, dziękuję! Czuję, że właśnie tyle się nauczyłem. Wtyczka CPT-onomies też jest naprawdę fajna. wordpress.org/extend/plugins/cpt-onomies
Dalton
Mam wrażenie, że w miarę powiększania się „biblioteki” możesz napotkać pewne przeszkody, ale mam już na myśli jakiś kod, więc jeśli tak, daj mi znać.
Rachel Carden,
@RachelCarden Co robisz, gdy dwie książki mają ten sam tytuł, ale różnych autorów? W przepisanym adresie URL wystąpi kolizja! Jak to rozwiązujesz?
Segfault
1
@ Segfault Będziesz musiał pobrać wszystkie informacje o autorze, aby móc zapisać je na stałe w regułach przepisywania: foreach ($ autor_slugs jako $ autor_slug) {add_rewrite_rule ('^ autorzy /'. $ Autor_slug. '/ / [ ^ /] *) / ([^ /] *) /? ',' index.php? autorzy = '. $ autor_slug.' & chapters = $ dopasowania [2] ',' top '); add_rewrite_rule ('^ autorzy /'. $ autor_slug. '/([^/]*)/?','index.php?authors='. $ autor_slug. '& books = $ dopasowania [1]', 'top') ; }
Rachel Carden
@Segfault Możesz użyć get_terms () , jeśli używasz CPT-onomy, lub get_posts (), aby pobrać nazwy postów / ślimaków.
Rachel Carden
4

Nie mam osobistego doświadczenia z takim scenariuszem, ale Randy Hoyt przeprowadził prezentację na WordCamp San Fran w ostatni weekend na temat „Podrzędnych typów postów”, co brzmi jak to, o czym mówisz.

Oto jego strona z przemówieniem, która zawiera slajdy prezentacji i linki do wtyczki, którą zbudował do pracy z podrzędnymi typami postów: http://randyhoyt.com/wordpress/subordinate-post-types/

mannieschumpert
źródło
Dzięki, to wygląda na dobry zasób. Nie jest jednak jasne, czy to wspiera relacje z wnukami (wydaje się, że tak nie jest w moich testach) i nie pomaga w przypadku permalinków. Już wymyśliłem sposób na ustanowienie relacji między dzieckiem a rodzicem (chociaż jest to całkiem fajny sposób na zrobienie tego), ale permalinki są naprawdę problemem, który mnie teraz tkwi.
Dalton,
1

Reguły zostaną dodane do extra_rules_top WP_Rewrite w kolejności dodawania dodatkowych permastruktów. Tak więc zmiana kolejności rejestrowania typów postów spowoduje zmianę kolejności generowania reguł przepisywania, dzięki czemu przepisywanie rozdziału zostanie najpierw dopasowane. Ponieważ jednak używasz query_var z innych typów postów, wp_query może skończyć dopasowaniem jednego z nich jako nazwy zapytania, zanim dopasujesz rozdział tak, jak chcesz.

Utworzyłbym nowe znaczniki przepisywania, które będą reprezentować symbole zastępcze dla autora-rodzica i książki-rodzica, tj .:

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

Aby to zrobić, musisz przefiltrować „query_vars”, aby „parent_book” stał się publiczny. Następnie musisz dodać filtr do post_get_posts, który przekształci zestaw nazw jako parent_book query_var w post_id i ustawi go jako „post_parent”.

prettyboymp
źródło
Czy możesz podać przykłady kodu dla wspomnianych filtrów? A jak wyglądałby tag przepisywania dla CPT wnuka?
Dalton,