Jak ustawić relację rodzic-dziecko między różnymi niestandardowymi typami postów

14

Właśnie skonfigurowałem relację między postem a rodzicem między „epizodami” typu posta a „serialem animowanym”.

Użyłem tego fragmentu kodu, aby dodać w polu meta, aby przypisać element nadrzędny z innego typu postu:

add_action('admin_menu', function() {
    remove_meta_box('pageparentdiv', 'episodes', 'normal');
});
add_action('add_meta_boxes', function() {
    add_meta_box('episodes-parent', 'Cartoon Series', 'episodes_attributes_meta_box', 'episodes', 'side', 'default');
});

function episodes_attributes_meta_box($post) {
    $post_type_object = get_post_type_object($post->post_type);
    if ( $post_type_object->hierarchical ) {
        $pages = wp_dropdown_pages(array('post_type' => 'cartoon-series', 'selected' => $post->post_parent, 'name' => 'parent_id', 'show_option_none' => __('(no parent)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // end empty pages check
    } // end hierarchical check.
}

To działało na ekranie administratora, pozwalając mi ustawić serial jako rodzic odcinka, ale kiedy próbuję wyświetlić post, dostaję 404. Struktura adresu URL to:

domain/episodes/series-name/episode-name

Adres URL tej serii to:

domain/cartoon-series/series-name

Chciałbym, aby URL odcinka był:

domain/cartoon-series/series-name/episode-name

czego mi brakuje? Czy można uczynić cały typ postu potomkiem innego typu postu? Więc mógłbym nawet uzyskać adres URL listy odcinków:

domain/cartoon-series/series-name/episodes

Dzięki! Matt


Zgodnie z życzeniem, oto kod dwóch omawianych typów niestandardowych postów:

$labels = array(
    "name" => "Cartoon Series",
    "singular_name" => "Cartoon Series",
    "menu_name" => "Cartoon Series",
    "all_items" => "All Cartoon Series",
    "add_new" => "Add New",
    "add_new_item" => "Add New Cartoon Series",
    "edit" => "Edit",
    "edit_item" => "Edit Cartoon Series",
    "new_item" => "New Cartoon Series",
    "view" => "View",
    "view_item" => "View Cartoon Series",
    "search_items" => "Search Cartoon Series",
    "not_found" => "No Cartoon Series Found",
    "not_found_in_trash" => "No Cartoon Series Found in Trash",
    "parent" => "Parent Cartoon Series",
    );

$args = array(
    "labels" => $labels,
    "description" => "",
    "public" => true,
    "show_ui" => true,
    "has_archive" => true,
    "show_in_menu" => true,
    "exclude_from_search" => false,
    "capability_type" => "post",
    "map_meta_cap" => true,
    "hierarchical" => true,
    "rewrite" => array( "slug" => "cartoon-series", "with_front" => true ),
    "query_var" => true,
    "supports" => array( "title", "revisions", "thumbnail" ),           );
register_post_type( "cartoon-series", $args );

$labels = array(
    "name" => "Episodes",
    "singular_name" => "Episode",
    );

$args = array(
    "labels" => $labels,
    "description" => "",
    "public" => true,
    "show_ui" => true,
    "has_archive" => true,
    "show_in_menu" => true,
    "exclude_from_search" => false,
    "capability_type" => "post",
    "map_meta_cap" => true,
    "hierarchical" => true,
    "rewrite" => array( "slug" => "episodes", "with_front" => true ),
    "query_var" => true,
    "supports" => array( "title", "revisions", "thumbnail" ),           );
register_post_type( "episodes", $args );

Korzystam z wtyczki CPT UI, więc nie mogę bezpośrednio edytować tego kodu. To tylko kod eksportu, który zapewnia interfejs CPT.

Nie mam żadnego innego kodu, który łączy dwa CPT. Może tego mi brakuje. Właśnie znalazłem ten kod online, który umieszcza metaboks na stronie, aby wykonać link. Czy to nie wystarczy do wykonania pracy? Wygląda na to, że ustawia post_parent.

Dzięki! Matt

Mattaton
źródło
Przepraszam, ale się myliłem. Relacja rodzic-dziecko jest poprawnie ustawiona. Meta box nie korzysta z pola meta (to mnie pomyliło za pierwszym razem), używa parent_idzapytania var i nie potrzebuje więcej kodu, aby ustawić relację. Problem polega na tym, że wygenerowany adres URL nie jest rozpoznawany przez WordPress. Próbowałem znaleźć regułę przepisywania, która sprawi, że zadziała, ale nie odniosłem sukcesu. Teraz szukam rozwiązania.
cybmeta
Po pewnym dochodzeniu myślę, że nie możesz sprawić, by działał tak, jak chcesz. Posiadanie typu posta jako elementu nadrzędnego innego typu postu wydaje się niemożliwe. Cóż, jest to możliwe, z twoim kodem, że relacja jest faktycznie ustawiona, ale widok postu dziecka nie działa w interfejsie. Próbowałem przepisać reguły i przyłączyć się pre_get_postsdo zmiany zapytania bez powodzenia, w grę wchodzi coś bardziej skomplikowanego, czego nie byłem w stanie zrozumieć. To tak, jakby kot był rodzicem psa. Sugeruję, aby użyć tylko jednego hierarchicznego typu postu lub ustawić prawdziwość za pomocą pól meta .
cybmeta
Myślę, że jeden hirarchiczny typ słupka idealnie pasuje do twojej sytuacji.
cybmeta
2
Naprawdę staram się NIE być tym skomplikowany. Jeśli dostępne jest bardziej eleganckie rozwiązanie, jestem cała w uszach. Ogólnie jestem nowy w WP i jak dotąd radziłem sobie całkiem nieźle, ale ten mnie zaskoczył. Zazwyczaj po prostu tworzyłem serial animowany i przypisałem go do odcinka. Problem polega na tym, że mam także inne zagnieżdżone dane, inne niż odcinki, które można było zamieścić w serialu animowanym. Wygląda więc na to, że serial animowany również musiałby być CPT. To skomplikowane! :-D Czy możesz mi wyjaśnić, co masz na myśli, używając tylko jednego hierarchicznego typu posta?
Mattaton

Odpowiedzi:

9

Wreszcie znalazłem działające rozwiązanie. Kreskówki z serii mogą być rejestrowane jak ty ale epizody niestandardowe typy post nie może być hirarchical (myślę WordPress spodziewa zawartość rodzic być tego samego typu jak zawartość dziecięcej jeśli związek jest ustawiana za pomocą post_parentw wp_poststabeli bazy danych).

Podczas rejestrowania odcinków reguła przepisywania musi być ustawiona na żądany ślimak, to znaczy cartoon-series/%series_name%. Następnie możemy przefiltrować link odcinka, aby zastąpić %series_name%go faktyczną nazwą rodzicielskiego cartoon-seriestypu postu i zasadą przepisywania, która mówi WordPressowi, gdy żądany jest typ postu z serii kreskówek, a kiedy epizody.

add_action('init', function(){
    $labels = array(
        "name" => "Cartoon Series",
        "singular_name" => "Cartoon Series",
        "menu_name" => "Cartoon Series",
        "all_items" => "All Cartoon Series",
        "add_new" => "Add New",
        "add_new_item" => "Add New Cartoon Series",
        "edit" => "Edit",
        "edit_item" => "Edit Cartoon Series",
        "new_item" => "New Cartoon Series",
        "view" => "View",
        "view_item" => "View Cartoon Series",
        "search_items" => "Search Cartoon Series",
        "not_found" => "No Cartoon Series Found",
        "not_found_in_trash" => "No Cartoon Series Found in Trash",
        "parent" => "Parent Cartoon Series",
    );

    $args = array(
        "labels" => $labels,
         "description" => "",
        "public" => true,
        "show_ui" => true,
        "has_archive" => true,
        "show_in_menu" => true,
        "exclude_from_search" => false,
        "capability_type" => "post",
        "map_meta_cap" => true,
        "hierarchical" => true,
        "rewrite" => array( "slug" => "cartoon-series", "with_front" => true ),
        "query_var" => true,
        "supports" => array( "title", "revisions", "thumbnail" )
    );

    register_post_type( "cartoon-series", $args );

    $labels = array(
        "name" => "Episodes",
        "singular_name" => "Episode",
    );

    $args = array(
        "labels" => $labels,
        "description" => "",
        "public" => true,
        "show_ui" => true,
        "has_archive" => true,
        "show_in_menu" => true,
        "exclude_from_search" => false,
        "capability_type" => "post",
        "map_meta_cap" => true,
        "hierarchical" => false,
        "rewrite" => array( "slug" => "cartoon-series/%series_name%", "with_front" => true ),
        "query_var" => true,
        "supports" => array( "title", "revisions", "thumbnail" )
    );

    register_post_type( "episodes", $args );

});

add_action('add_meta_boxes', function() {
    add_meta_box('episodes-parent', 'Cartoon Series', 'episodes_attributes_meta_box', 'episodes', 'side', 'default');
});

function episodes_attributes_meta_box($post) {
        $pages = wp_dropdown_pages(array('post_type' => 'cartoon-series', 'selected' => $post->post_parent, 'name' => 'parent_id', 'show_option_none' => __('(no parent)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // end empty pages check
}

add_action( 'init', function() {

    add_rewrite_rule( '^cartoon-series/(.*)/([^/]+)/?$','index.php?episodes=$matches[2]','top' );

});

add_filter( 'post_type_link', function( $link, $post ) {
    if ( 'episodes' == get_post_type( $post ) ) {
        //Lets go to get the parent cartoon-series name
        if( $post->post_parent ) {
            $parent = get_post( $post->post_parent );
            if( !empty($parent->post_name) ) {
                return str_replace( '%series_name%', $parent->post_name, $link );
            }
        } else {
            //This seems to not work. It is intented to build pretty permalinks
            //when episodes has not parent, but it seems that it would need
            //additional rewrite rules
            //return str_replace( '/%series_name%', '', $link );
        }

    }
    return $link;
}, 10, 2 );

UWAGA : Pamiętaj, aby opróżnić reguły przepisywania po zapisaniu powyższego kodu i przed wypróbowaniem go. Przejdź do wp-admin/options-permalink.phpi kliknij przycisk Zapisz, aby ponownie wygenerować reguły przepisywania.

UWAGA 2 : Prawdopodobnie należy dodać więcej reguł przepisywania, na przykład w celu pracy z postami stronicowanymi. Może to również wymagać dodatkowej pracy, aby mieć kompletne rozwiązanie, na przykład podczas usuwania cartoon-seriesskasować także wszystkie odcinki podrzędne? Dodać filtr na ekranie edycji administratora, aby filtrować odcinki według nadrzędnego posta? Zmienić tytuł odcinka na ekranie edycji administratora, aby wyświetlał nazwę nadrzędnej serii?

cybmeta
źródło
Dzięki za przyjrzenie się temu! Wygląda na to, że kod, który opublikowałeś, usuwa nazwę serialu z adresu URL. Zamiast zamiany% series_name% na nazwę odcinka,% series_name% powinno być nazwą rodzica odcinka. Nazwa odcinka będzie później. Z jakiegoś powodu pole Cartoon Series nie jest wypełniane, abym wybrał rodzica. Właśnie dlatego myślałem, że odcinki muszą być hierarchiczne. Próbuję dowiedzieć się, dlaczego.
Mattaton
Tak, odcinki muszą być hierarchiczne, aby można było zapełnić meta box z serii Cartoon.
Mattaton
Z odcinkami zhierarchizowanymi, abym mógł ustawić rodzica, adres URL właśnie się pogorszył. Z tym ślimakiem, jak sugerowałeś, dwukrotnie wyświetlam nazwę serii w adresie URL. Więc zamiast domain/episodes/series-name/episode-namejak poprzednio, dostałemdomain/episodes/series-name/series-name/episode-name
Mattaton
Jak powiedziałem, odcinki nie mogą być hierarchiczne. Zmodyfikowałem kod meta-box, aby był zapełniany niehierarchicznymi typami postów. Użyj dokładnego kodu, który opublikowałem, przetestowałem go i działa. Jeśli użyjesz innego kodu, nie będę wiedział, co jest nie tak. Po prostu skopiuj i wklej kod z odpowiedzi i przetestuj go. Może być konieczne wyłączenie wtyczki CPT UI lub przynajmniej usunięcie niestandardowych typów postów z wtyczki, ponieważ są one zarejestrowane w kodzie.
cybmeta
Ach, przepraszam, szybko zeskanowałem i pomyślałem, że ta część jest taka sama. Masz rację, strona ładuje się teraz, a adres URL wygląda poprawnie.
Mattaton
-1

Będziesz musiał napisać własny kod analizujący URL, ponieważ wordpress musi znać typ postu, który próbuje pobrać z bazy danych na podstawie struktury adresu URL, a struktura adresu URL nie daje żadnej wskazówki na ten temat.

Nie jest to coś, co jest bardzo łatwe do zrobienia dzięki interfejsowi API reguł przepisywania w wordpress, ale nic nie stoi na przeszkodzie, aby pominąć mechanizm przepisywania i samodzielnie parsować adresy URL. Coś jak: 1. uruchom reguły przepisywania Wordpress. Jeśli treść została znaleziona, wyświetl ją i wyjdź 2. pobierz pierwszą część adresu URL, sprawdź, czy istnieje post pasujący do tego ślimaka z oczekiwanym typem postu 3. pętla w pozostałych częściach adresu URL sprawdź, czy posty istnieją i są we właściwym typie. 4. jeśli wszystko pasuje, wyświetla ostatni znaleziony post, w przeciwnym razie wyświetla stronę 404

Mark Kaplun
źródło