Cum să setezi relația părinte-copil între tipuri de postări personalizate diferite

14 mar. 2015, 00:20:15
Vizualizări: 27.4K
Voturi: 23

Tocmai am configurat o relație post/părinte între un tip de postare "episodes" și un tip de postare "cartoon-series".

Am folosit acest cod pentru a adăuga meta box-ul care permite atribuirea părintelui dintr-un alt tip de postare:

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' => __('(fără părinte)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // verificare pentru pagini goale
    } // verificare ierarhică
}

Codul funcționează în panoul de administrare permițându-mi să setez seria ca părinte pentru episod, dar când încerc să vizualizez postarea, primesc o eroare 404. Structura URL-ului este:

domain/episodes/series-name/episode-name

URL-ul pentru serie este:

domain/cartoon-series/series-name

Aș dori ca URL-ul pentru episod să fie:

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

Ce îmi lipsește? Este posibil să fac un întreg tip de postare copilul altui tip de postare? Astfel, aș putea obține chiar și URL-ul pentru lista de episoade să fie:

domain/cartoon-series/series-name/episodes

Mulțumesc! Matt


Conform solicitării, iată codul pentru cele două tipuri de postări personalizate în discuție:

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

Folosesc plugin-ul CPT UI, deci nu pot edita direct acel cod. Acesta este doar codul de export pe care îl oferă CPT UI.

Nu am niciun alt cod care să lege cele două CPT-uri. Poate asta îmi lipsește. Am găsit doar acel cod online care plasează metabox-ul pe pagină pentru a face legătura. Nu este suficient pentru a face treaba? Se pare că setează post_parent.

Mulțumesc! Matt

4
Comentarii

Îmi cer scuze, dar am greșit. Relația părinte-copil este setată corect. Caseta meta nu utilizează un câmp meta (asta m-a încurcat inițial), ci folosește variabila de interogare parent_id și nu necesită cod suplimentar pentru a stabili relația. Problema este că URL-ul generat nu este recunoscut de WordPress. Am încercat să găsesc o regulă de rescriere care să facă asta să funcționeze, dar nu am avut succes. Acum investighez o soluție.

cybmeta cybmeta
14 mar. 2015 20:19:46

După ceva investigații, cred că nu poți face să funcționeze așa cum dorești. A avea un tip de postare ca părinte pentru un alt tip de postare pare să nu fie posibil. Ei bine, este posibil, cu codul tău acea relație este de fapt stabilită, dar vizualizarea postării copil nu funcționează în frontend. Am încercat reguli de rescriere și să modific interogarea prin pre_get_posts fără succes, este implicat ceva mai complicat pe care nu am reușit să înțeleg. Ca și cum ai avea o pisică drept părinte pentru un câine. Sugerez să folosești un singur tip de postare ierarhică sau să stabilești relația folosind câmpuri meta.

cybmeta cybmeta
14 mar. 2015 21:12:59

Cred că un singur tip de postare ierarhică se potrivește perfect situației tale.

cybmeta cybmeta
14 mar. 2015 21:19:12

Încerc cu adevărat să NU complic lucrurile cu asta. Dacă există o soluție mai elegantă, sunt tot urechi. Sunt nou în WordPress în general și m-am descurcat destul de bine până acum, dar asta m-a dat peste cap. În mod normal, aș face seria de desene animate o categorie și aș atribui-o episodului. Problema este că am și alte date imbricate în afară de episoade care trebuie să fie sub seria de desene animate. Deci, se pare că seria de desene animate ar trebui să fie și ea un CPT. E complicat! :-D Poți să-mi explici ce înțelegi prin utilizarea unui singur tip de postare ierarhică?

Mattaton Mattaton
14 mar. 2015 22:40:15
Toate răspunsurile la întrebare 3
7
18

În sfârșit am găsit o soluție funcțională. Seriile de desene animate pot fi înregistrate așa cum ai făcut, dar posturile personalizate pentru episoade nu pot fi ierarhice (cred că WordPress se așteaptă ca conținutul părinte să fie de același tip cu conținutul copil dacă relația este stabilită folosind post_parent în tabelul de baze de date wp_posts).

La înregistrarea episoadelor, regula de rescriere trebuie setată la slug-ul dorit, adică cartoon-series/%series_name%. Apoi putem filtra linkul episoadelor pentru a înlocui %series_name% cu numele real al tipului de postare părinte cartoon-series și o regulă de rescriere pentru a-i spune lui WordPress când este solicitat un tip de postare cartoon-series și când este un episod.

add_action('init', function(){
    $labels = array(
        "name" => "Serii de Desene Animate",
        "singular_name" => "Serie de Desene Animate",
        "menu_name" => "Serii de Desene Animate",
        "all_items" => "Toate Seriile de Desene Animate",
        "add_new" => "Adaugă Nou",
        "add_new_item" => "Adaugă o Serie Nouă de Desene Animate",
        "edit" => "Editează",
        "edit_item" => "Editează Seria de Desene Animate",
        "new_item" => "Serie Nouă de Desene Animate",
        "view" => "Vizualizează",
        "view_item" => "Vizualizează Seria de Desene Animate",
        "search_items" => "Caută Serii de Desene Animate",
        "not_found" => "Nu s-au găsit Serii de Desene Animate",
        "not_found_in_trash" => "Nu s-au găsit Serii de Desene Animate în Gunoi",
        "parent" => "Seria Părinte de Desene Animate",
    );

    $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" => "Episoade",
        "singular_name" => "Episod",
    );

    $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', 'Serii de Desene Animate', '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' => __('(fără părinte)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // verificare pagini goale
}

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 ) ) {
        //Să obținem numele seriei părinte de desene animate
        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 {
            //Aceasta pare să nu funcționeze. Este intenționat să construiască permalink-uri frumoase
            //când episoadele nu au părinte, dar pare că ar avea nevoie
            //de reguli suplimentare de rescriere
            //return str_replace( '/%series_name%', '', $link );
        }

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

NOTĂ: Nu uitați să reîmprospătați regulile de rescriere după salvarea codului de mai sus și înainte de a încerca. Accesați wp-admin/options-permalink.php și faceți clic pe salvare pentru a regenera regulile de rescriere.

NOTĂ 2: Este posibil să fie necesară adăugarea mai multor reguli de rescriere, de exemplu pentru a funcționa pentru postările paginate. De asemenea, poate fi nevoie de ceva mai multă muncă pentru a avea o soluție completă, de exemplu, la ștergerea unei cartoon-series să se șteargă și toate episoadele copil? Adăugați un filtru în ecranul de editare din administrare pentru a filtra episoadele după postul părinte? Modificați titlul episoadelor în ecranul de editare din administrare pentru a afișa numele seriei părinte?

14 mar. 2015 22:44:56
Comentarii

Mulțumesc că te-ai uitat peste asta! Se pare că codul pe care l-ai postat elimină numele serialului de desene animate din URL. În loc să înlocuiască %series_name% cu numele episodului, %series_name% ar trebui să fie numele părintelui episodului. Numele episodului ar trebui să fie după acesta. Din nu știu ce motiv, căsuța "Serial de Desene Animate" nu se completează pentru mine ca să pot selecta un părinte. De aceea am crezut că episoadele trebuie să fie ierarhice. Încerc să înțeleg de ce.

Mattaton Mattaton
14 mar. 2015 22:58:24

Da, episoadele trebuie să fie ierarhice pentru ca căsuța meta "Serial de Desene Animate" să se poată completa.

Mattaton Mattaton
14 mar. 2015 22:59:40

Cu episoadele ierarhice ca să pot seta părintele, URL-ul a devenit și mai rău. Cu slug-ul cum ai sugerat, primesc numele serialului în URL de două ori. Deci, în loc de domain/episodes/nume-serial/nume-episod ca înainte, am obținut domain/episodes/nume-serial/nume-serial/nume-episod

Mattaton Mattaton
14 mar. 2015 23:03:40

Cum am spus, episoadele nu pot fi ierarhice. Am modificat codul meta box-ului pentru a fi populat cu tipuri de postări ne-ierarhice. Folosește exact codul pe care l-am postat, l-am testat și funcționează. Dacă folosești alt cod, nu pot ști care este problema. Doar copiază și lipește codul din răspuns și testează-l. Poate fi necesar să dezactivezi pluginul CPT UI sau, cel puțin, să ștergi tipurile de postări personalizate din plugin, deoarece acestea sunt înregistrate în cod.

cybmeta cybmeta
14 mar. 2015 23:06:57

Ah, îmi cer scuze, am scanat rapid și am crezut că acea parte era identică. Ai dreptate, pagina se încarcă acum și URL-ul arată corect.

Mattaton Mattaton
14 mar. 2015 23:10:58

Dacă acest răspuns îți rezolvă întrebarea, te rog să marchezi răspunsul ca acceptat bifând marcajul de sub săgețile de vot din stânga-sus a răspunsului.

cybmeta cybmeta
14 mar. 2015 23:14:03

Chiar și după 8 ani, acest lucru încă funcționează perfect! Mulțumesc!

Gavin Gavin
19 iun. 2023 19:20:39
Arată celelalte 2 comentarii
0

Nu este nevoie de hard-coding în acest caz, poți folosi pur și simplu acest plugin:

https://wordpress.org/plugins/add-hierarchy-parent-to-post/

Poți chiar să iei codul din el. Totuși, s-ar putea să nu fie o soluție completă.

7 feb. 2017 10:29:43
0
-1

Va trebui să scrieți propriul cod de parsare a URL-urilor pentru aceasta, deoarece WordPress trebuie să cunoască tipul postării pe care încearcă să o recupereze din baza de date pe baza structurii URL-ului, iar structura URL-ului vostru nu oferă niciun indiciu în acest sens.

Aceasta nu este o sarcină foarte ușoară de realizat cu API-ul de reguli de rescriere din WordPress, dar nu există nimic care să vă împiedice să ocoliți mecanismul de rescriere și să parsați URL-urile manual. Ceva de genul: 1. Rulați regulile de rescriere WordPress. Dacă s-a găsit conținut, afișați-l și ieșiți 2. Luați prima parte a URL-ului, verificați dacă există o postare care să se potrivească cu acel slug și tipul de postare așteptat 3. Parcurgeți restul părților URL-ului și verificați că postările există și sunt de tipul corect 4. Dacă totul se potrivește, afișați ultima postare găsită, altfel afișați o pagină 404

14 mar. 2015 21:28:55