Come impostare la relazione genitore-figlio tra diversi custom post type
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

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?

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é.

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

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

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.

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.

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.

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.

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:
- Esegui le regole di riscrittura di WordPress. Se viene trovato un contenuto, visualizzalo ed esci
- Prendi la prima parte dell'URL, controlla se esiste un post corrispondente a quello slug con il tipo di post atteso
- Cicla sulle parti rimanenti dell'URL verifica che i post esistano e siano del tipo corretto
- Se tutto corrisponde, visualizza l'ultimo post trovato, altrimenti mostra una pagina 404
