Verschachtelte benutzerdefinierte Beitragstypen mit Permalinks

9

Ich versuche, eine mehrstufige benutzerdefinierte Posttypstruktur mit Permalinks einzurichten, die so aussehen authors/books/chapters, dass Autoren, Bücher und Kapitel als eigene benutzerdefinierte Posttypen eingerichtet sind. Beispielsweise könnte eine typische URL auf dieser Site so aussehenexample.com/authors/stephen-king/the-shining/chapter-3/

Jedes Kapitel kann nur zu einem Buch gehören, und jedes Buch kann nur einem Autor gehören. Ich habe überlegt, Taxonomien anstelle von CPTs für Autoren und Bücher zu verwenden, aber ich muss jedem Element Metadaten zuordnen, und ich bevorzuge hierfür die Post-Oberfläche.

Ich bin meistens auf dem Weg dorthin, indem ich einfach jeden benutzerdefinierten Beitrag als untergeordnetes Element eines Eintrags im CPT eine Ebene höher einrichte. Zum Beispiel erstelle ich "Kapitel 3" und weise "The Shining" als übergeordnetes Element mithilfe einer benutzerdefinierten Meta-Box zu. "The Shining" wiederum hat "Stephen King" als Elternteil. Ich hatte keine Probleme, diese Beziehungen aufzubauen.

Ich verwende Rewrite-Tags in den CPT-Slugs und die Permalinks möchten funktionieren, aber sie sind nicht ganz richtig. Mit einem Re-Write-Analysator kann ich sehen, dass die Rewrite-Regeln tatsächlich generiert werden, aber sie scheinen nicht in der richtigen Reihenfolge zu sein, sodass andere Regeln zuerst verarbeitet werden.

Hier ist ein Screenshot meines Rewrite-Analysators.

So habe ich meine CPTs registriert:

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' );

Gibt es also eine Möglichkeit, die Priorität meiner Umschreiberegeln so zu ändern, dass Autoren, Bücher und Kapitel zuerst übereinstimmen?

Ich weiß auch, dass ich einen post_type_linkFilter hinzufügen muss , aber das scheint zweitrangig zu sein, wenn man die Permalinks überhaupt richtig macht. Wenn jemand weiß, wo ich einen umfassenden Überblick über die Funktionsweise dieses Filters finden kann, wäre er dankbar.

Dalton
quelle
Haben Sie darüber nachgedacht, nur Seiten zu verwenden? Sie würden automatisch die richtige Permalink-Struktur erhalten.
Michael Hampton
Ich habe es definitiv in Betracht gezogen. Das Problem mit Seiten ist, dass wir möglicherweise 100 Enkelkinder für einen einzelnen Autor haben, was im Seitenadministrator sehr schwer zu verwalten ist. Außerdem müssen wir in der Lage sein, nach Beitragstyp abzufragen.
Dalton
Ich arbeite an einer Lösung, habe aber eine kurze Frage: Ist es wichtig, vor jedem Permalink einen Autor zu haben? Denn das scheint der Stickler zu sein. Ich denke, es verwirrt WordPress ein wenig zu sehr, zumal dies ein Permalink-Slug ist, der auch für WP-Autorenseiten verwendet wird. Wenn es erforderlich ist, einen 'Autor' zu haben, denke ich, dass das Ganze immer noch machbar ist ... es wird nur komplizierter.
Rachel Carden
Hoppla, ich wusste nicht, dass der Autor mit der integrierten WP-Autoren-Schnecke in Konflikt geraten würde. Nein, das ist nicht erforderlich, es könnte alles sein. Ich nahm an, dass ich dort etwas brauchte , weil es ein CPT ist, aber es könnte genauso gut "Schriftsteller" oder irgendetwas anderes sein.
Dalton
Ich erkannte, dass die Verwirrung tatsächlich darin liegt, dass die CPTs "Autor" als Basisschnecke teilen. Sobald Sie "Autor" als Slug für die CPT-Autoren festgelegt haben, und dann "Autor /% Autor%" für die CPT-Bücher und "Autor /% Autor% /% Buch%" für die CPT-Kapitel festgelegt haben ', dann denkt WordPress, dass die Beiträge für' Bücher 'und die Beiträge für' Kapitel 'buchstäblich hierarchische untergeordnete Beiträge für' Autoren 'sind. Ist das sinnvoll? In meinen Tests konnten Sie "Autor" als Basis für die CPT "Autoren" behalten und es funktioniert einwandfrei. Ersetzen Sie also meine vorherige Frage durch: Benötigen Sie 'Autor' oder kann der Slug mit% author% beginnen?
Rachel Carden

Antworten:

11

Wenn Sie "Autoren" als Basis-Slug in den Permalinks behalten möchten, z. B. example.com/authors/stephen-king/ für das CPT "Autoren", example.com/authors/stephen-king/the-shining/ für das "Bücher" CPT und example.com/authors/stephen-king/the-shining/chapter-3/ für das CPT "Kapitel", WordPress wird denken, dass so ziemlich alles ein "Autoren" -Post oder ein hierarchisches Kind eines "Autors" ist 'post und da dies nicht der Fall ist, wird WordPress letztendlich sehr verwirrt.

Trotzdem gibt es eine Problemumgehung, die recht einfach ist, aber solange Ihre Permalink-Struktur immer der gleichen Reihenfolge folgt, dh auf das Wort "Autoren" folgt immer eine Autoren-Schnecke, auf die immer eine Buch-Schnecke folgt Wenn Sie eine Kapitelschnecke haben, sollten Sie bereit sein, loszulegen.

In dieser Lösung ist es nicht erforderlich, den Umschreibungs-Slug in der benutzerdefinierten Post-Typ-Definition für "Kapitel" und "Bücher" zu definieren. Legen Sie jedoch den "Autoren" -Rewrite-Slug einfach als "Autoren" fest. Fügen Sie den folgenden Code in Ihre functions.php ein Datei und "leeren" Sie Ihre Umschreiberegeln.

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

Erfahren Sie mehr über das CPT-Onomies-Plugin

Rachel Carden
quelle
Das funktioniert perfekt, danke! Ich habe das Gefühl, ich habe gerade so viel gelernt. Das CPT-Onomies-Plugin ist auch wirklich cool. wordpress.org/extend/plugins/cpt-onomies
Dalton
Ich habe das Gefühl, dass Sie beim Wachstum Ihrer "Bibliothek" auf einige Hindernisse stoßen könnten, aber ich habe bereits Code im Sinn. Wenn Sie dies tun, lassen Sie es mich einfach wissen.
Rachel Carden
@RachelCarden Was machst du, wenn zwei Bücher den gleichen Titel haben, aber unterschiedliche Autoren? Es wird eine Kollision in der umgeschriebenen URL geben! Wie lösen Sie das?
Segfault
1
@Segfault Sie müssen alle Autoren-Slugs abrufen, damit Sie sie fest in die Umschreiberegel (e) codieren können: foreach ($ author_slugs als $ author_slug) {add_rewrite_rule ('^ author /'. $ Author_slug. '/ ([) ^ /] *) / ([^ /] *) /? ',' index.php? autoren = '. $ author_slug.' & kapitel = $ entspricht [2] ',' top '); add_rewrite_rule ('^ autoren /'. $ author_slug. '/([^/ weibl.)) /?', 'index.php?authors ='. $ author_slug. '& books = $ match [1]', 'top') ;; }
Rachel Carden
@Segfault Sie können get_terms () verwenden , wenn Sie eine CPT-Onomie verwenden, oder get_posts () , um die Postnamen / Slugs abzurufen.
Rachel Carden
4

Ich habe keine persönlichen Erfahrungen mit einem solchen Szenario, aber Randy Hoyt hat am vergangenen Wochenende im WordCamp San Fran eine Präsentation über "Subordinate Post Types" gehalten, die so klingt, als würden Sie darüber sprechen.

Hier ist seine Seite für den Vortrag, der seine Präsentationsfolien und Links zu einem Plugin enthält, das er für die Arbeit mit untergeordneten Beitragstypen erstellt hat: http://randyhoyt.com/wordpress/subordinate-post-types/

mannieschumpert
quelle
Danke, das sieht nach einer guten Ressource aus. Es ist jedoch nicht klar, ob dies die Beziehung zwischen Enkelkindern unterstützt (dies scheint in meinen Tests nicht der Fall zu sein), und es hilft nicht wirklich bei den Permalinks. Ich habe bereits einen Weg gefunden, um meine Kind / Eltern-Beziehungen aufzubauen (obwohl dies ein ziemlich guter Weg ist), aber die Permalinks sind wirklich das Problem, an dem ich jetzt festhalte.
Dalton
1

Die Regeln werden dem extra_rules_top von WP_Rewrite in der Reihenfolge hinzugefügt, in der die zusätzlichen Permastrukturen hinzugefügt werden. Wenn Sie also die Reihenfolge ändern, in der Sie die Beitragstypen registrieren, wird die Reihenfolge der generierten Umschreiberegeln geändert, sodass das Umschreiben des Kapitels zuerst übereinstimmt. Da Sie jedoch die query_var aus den anderen post_types verwenden, stimmt die wp_query möglicherweise mit einer dieser Abfragen als abgefragter Postname überein, bevor sie dem gewünschten Kapitel entspricht.

Ich würde neue Umschreibetags erstellen, um die Platzhalter für den übergeordneten Autor und das übergeordnete Buch darzustellen, dh:

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

Wenn Sie dies tun, müssen Sie 'query_vars' filtern, um 'parent_book' öffentlich zu machen. Dann müssen Sie pre_get_posts einen Filter hinzufügen, der den als parent_book query_var festgelegten Namen in die post_id konvertiert und als 'post_parent' festlegt.

Prettyboymp
quelle
Könnten Sie bitte Codebeispiele für die von Ihnen genannten Filter angeben? Wie würde das Rewrite-Tag für das CPT des Enkels aussehen?
Dalton