Come impostare la relazione genitore-figlio tra diversi custom post type

14 mar 2015, 00:20:15
Visualizzazioni: 27.4K
Voti: 23

Ho appena impostato una relazione post/genitore tra un tipo di post "episodes" e un tipo di post "cartoon-series".

Ho utilizzato questo pezzo di codice per aggiungere la meta box per assegnare il genitore da un altro tipo di post:

add_action('admin_menu', function() {
    remove_meta_box('pageparentdiv', 'episodes', 'normal');
});
add_action('add_meta_boxes', function() {
    add_meta_box('episodes-parent', 'Serie Cartoni', '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' => __('(nessun genitore)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // fine controllo pagine vuote
    } // fine controllo gerarchico
}

Questo ha funzionato nella schermata di amministrazione permettendomi di impostare la serie come genitore dell'episodio, ma quando provo a visualizzare il post, ottengo un errore 404. La struttura dell'URL è:

domain/episodes/series-name/episode-name

L'URL per la serie è:

domain/cartoon-series/series-name

Vorrei che l'URL per l'episodio fosse:

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

Cosa mi sfugge? È possibile rendere un intero tipo di post figlio di un altro tipo di post? Così potrei anche ottenere l'URL per l'elenco degli episodi come:

domain/cartoon-series/series-name/episodes

Grazie! Matt


Come richiesto, ecco il codice per i due custom post type in questione:

$labels = array(
    "name" => "Serie Cartoni",
    "singular_name" => "Serie Cartoni",
    "menu_name" => "Serie Cartoni",
    "all_items" => "Tutte le Serie Cartoni",
    "add_new" => "Aggiungi Nuovo",
    "add_new_item" => "Aggiungi Nuova Serie Cartoni",
    "edit" => "Modifica",
    "edit_item" => "Modifica Serie Cartoni",
    "new_item" => "Nuova Serie Cartoni",
    "view" => "Visualizza",
    "view_item" => "Visualizza Serie Cartoni",
    "search_items" => "Cerca Serie Cartoni",
    "not_found" => "Nessuna Serie Cartoni Trovata",
    "not_found_in_trash" => "Nessuna Serie Cartoni Trovata nel Cestino",
    "parent" => "Serie Cartoni Genitore",
    );

$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" => "Episodi",
    "singular_name" => "Episodio",
    );

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

Sto usando il plugin CPT UI, quindi non posso modificare direttamente quel codice. Questo è solo il codice di esportazione che fornisce CPT UI.

Non ho altro codice che collega i due CPT. Forse è questo che mi manca. Ho solo trovato quel codice online che posiziona la metabox sulla pagina per fare il collegamento. Non è sufficiente per fare il lavoro? Sembra che imposti il post_parent.

Grazie! Matt

4
Commenti

Mi dispiace ma mi sbagliavo. La relazione parent-child è impostata correttamente. La meta box non utilizza un meta field (questo è ciò che mi ha confuso inizialmente), utilizza la query var parent_id e non richiede altro codice per impostare la relazione. Il problema è che l'URL generato non viene riconosciuto da WordPress. Ho provato a trovare una regola di rewrite che lo facesse funzionare ma senza successo. Sto ora investigando una soluzione.

cybmeta cybmeta
14 mar 2015 20:19:46

Dopo alcune ricerche, penso che non sia possibile farlo funzionare come desideri. Avere un post type come parent di un altro post type sembra non essere possibile. O meglio, è possibile - con il tuo codice quella relazione è effettivamente impostata - ma visualizzare il child post non funziona nel frontend. Ho provato regole di rewrite e hook in pre_get_posts per modificare la query senza successo, c'è qualcosa di più complicato coinvolto che non sono riuscito a capire. È come avere un gatto come parent di un cane. Suggerisco di usare un solo post type gerarchico o impostare la relazione utilizzando meta fields.

cybmeta cybmeta
14 mar 2015 21:12:59

Penso che un singolo post type gerarchico si adatti perfettamente alla tua situazione.

cybmeta cybmeta
14 mar 2015 21:19:12

Sto davvero cercando di NON complicare questa cosa. Se esiste una soluzione più elegante, sono tutt'orecchi. Sono nuovo a WordPress in generale e finora me la sono cavata abbastanza bene, ma questa mi ha bloccato. Normalmente, farei della serie di cartoni animati una categoria e la assegnerei all'episodio. Il problema è che ho anche altri dati nidificati oltre agli episodi che devono essere sotto la serie di cartoni. Quindi, sembra che la serie di cartoni debba essere anche un CPT. È complicato! :-D Puoi spiegarmi cosa intendi con l'uso di un solo tipo di post gerarchico?

Mattaton Mattaton
14 mar 2015 22:40:15
Tutte le risposte alla domanda 3
7
18

Finalmente ho trovato una soluzione funzionante. Le serie animate possono essere registrate come hai fatto, ma i tipi di post personalizzati per gli episodi non possono essere gerarchici (penso che WordPress si aspetti che il contenuto genitore sia dello stesso tipo del contenuto figlio se la relazione è impostata utilizzando post_parent nella tabella del database wp_posts).

Durante la registrazione degli episodi, la regola di riscrittura deve essere impostata sullo slug desiderato, ovvero cartoon-series/%series_name%. Successivamente possiamo filtrare il link degli episodi per sostituire %series_name% con il nome effettivo del tipo di post genitore cartoon-series e una regola di riscrittura per indicare a WordPress quando viene richiesto un tipo di post cartoon-series e quando è un episodio.

add_action('init', function(){
    $labels = array(
        "name" => "Serie Animate",
        "singular_name" => "Serie Animata",
        "menu_name" => "Serie Animate",
        "all_items" => "Tutte le Serie Animate",
        "add_new" => "Aggiungi Nuova",
        "add_new_item" => "Aggiungi Nuova Serie Animata",
        "edit" => "Modifica",
        "edit_item" => "Modifica Serie Animata",
        "new_item" => "Nuova Serie Animata",
        "view" => "Visualizza",
        "view_item" => "Visualizza Serie Animata",
        "search_items" => "Cerca Serie Animate",
        "not_found" => "Nessuna Serie Animata Trovata",
        "not_found_in_trash" => "Nessuna Serie Animata Trovata nel Cestino",
        "parent" => "Serie Animata Genitore",
    );

    $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" => "Episodi",
        "singular_name" => "Episodio",
    );

    $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', 'Serie Animata', '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' => __('(nessun genitore)'), 'sort_column'=> 'menu_order, post_title', 'echo' => 0));
        if ( ! empty($pages) ) {
            echo $pages;
        } // fine controllo pagine vuote
}

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 ) ) {
        //Recuperiamo il nome della serie animata genitore
        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 {
            //Questo sembra non funzionare. È pensato per costruire permalink puliti
            //quando gli episodi non hanno un genitore, ma sembra che sarebbero necessarie
            //ulteriori regole di riscrittura
            //return str_replace( '/%series_name%', '', $link );
        }

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

NOTA: Ricorda di svuotare le regole di riscrittura dopo aver salvato il codice sopra e prima di provarlo. Vai su wp-admin/options-permalink.php e clicca salva per rigenerare le regole di riscrittura.

NOTA 2: È probabile che debbano essere aggiunte ulteriori regole di riscrittura, ad esempio per funzionare con i post paginati. Inoltre potrebbe essere necessario ulteriore lavoro per avere una soluzione completa, ad esempio, quando si elimina una cartoon-series eliminare anche tutti gli episodi figli? Aggiungere un filtro nella schermata di modifica dell'amministratore per filtrare gli episodi per post genitore? Modificare il titolo degli episodi nella schermata di modifica dell'amministratore per mostrare il nome della serie genitore?

14 mar 2015 22:44:56
Commenti

Grazie per averlo esaminato! Sembra che il codice che hai pubblicato stia rimuovendo il nome della serie di cartoni dall'URL. Invece di sostituire %series_name% con il nome dell'episodio, %series_name% dovrebbe essere il nome del genitore dell'episodio. Il nome dell'episodio dovrebbe seguire dopo. Per qualche motivo, la casella Cartoon Series non viene popolata per me per selezionare un genitore. Ecco perché ho pensato che gli episodi dovessero essere gerarchici. Sto cercando di capire il perché.

Mattaton Mattaton
14 mar 2015 22:58:24

Sì, gli episodi devono essere gerarchici affinché la meta box Cartoon Series venga popolata.

Mattaton Mattaton
14 mar 2015 22:59:40

Con gli episodi gerarchici così da poter impostare il genitore, l'URL è peggiorato. Con lo slug come suggerito, ottengo il nome della serie nell'URL due volte. Quindi, invece di domain/episodes/nome-serie/nome-episodio come prima, ho ottenuto domain/episodes/nome-serie/nome-serie/nome-episodio

Mattaton Mattaton
14 mar 2015 23:03:40

Come ho detto, gli episodi non possono essere gerarchici. Ho modificato il codice della meta box per essere popolato con tipi di post non gerarchici. Usa il codice esatto che ho pubblicato, l'ho testato e funziona. Se usi un altro codice non posso sapere cosa non va. Basta copiare e incollare il codice dalla risposta e testarlo. Potresti aver bisogno di disabilitare il plugin CPT UI o, almeno, eliminare i tipi di post personalizzati dal plugin poiché sono registrati nel codice.

cybmeta cybmeta
14 mar 2015 23:06:57

Ah, mi scuso, avevo dato una rapida occhiata e pensavo che quella parte fosse uguale. Hai ragione, la pagina ora si carica e l'URL sembra corretto.

Mattaton Mattaton
14 mar 2015 23:10:58

Se questa risposta risolve la tua domanda, per favore, contrassegnala come accettata spuntando il segno sotto le frecce di voto in alto a sinistra della risposta.

cybmeta cybmeta
14 mar 2015 23:14:03

Anche dopo 8 anni funziona ancora perfettamente! Grazie!

Gavin Gavin
19 giu 2023 19:20:39
Mostra i restanti 2 commenti
0

Non è necessario ricorrere a hard-coding in questo caso, puoi semplicemente utilizzare questo plugin:

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

Puoi persino prendere spunto dal codice del plugin. Tuttavia, potrebbe non essere una soluzione completa.

7 feb 2017 10:29:43
0
-1

Dovrai scrivere il tuo codice per l'analisi degli URL, poiché WordPress ha bisogno di conoscere il tipo di post che tenta di recuperare dal database in base alla struttura dell'URL, e la tua struttura di URL non fornisce alcun indizio su questo.

Non è qualcosa di molto semplice da fare con l'API delle regole di riscrittura di WordPress, ma nulla ti impedisce di bypassare il meccanismo di riscrittura e analizzare gli URL autonomamente. Qualcosa come:

  1. Esegui le regole di riscrittura di WordPress. Se viene trovato un contenuto, visualizzalo ed esci
  2. Prendi la prima parte dell'URL, controlla se esiste un post corrispondente a quello slug con il tipo di post atteso
  3. Cicla sulle parti rimanenti dell'URL verifica che i post esistano e siano del tipo corretto
  4. Se tutto corrisponde, visualizza l'ultimo post trovato, altrimenti mostra una pagina 404
14 mar 2015 21:28:55