Come creare una struttura permalink con tassonomie personalizzate e tipi di post personalizzati come base-name/parent-tax/child-tax/custom-post-type-name
Ho cercato su questo sito e su Google la risposta e non ho trovato nulla. Fondamentalmente voglio fare esattamente ciò che chiede questo post, ma ho bisogno di una tassonomia gerarchica. La risposta fornita in quel post funziona benissimo, ma solo con una tassonomia a livello singolo. È possibile fare quello che voglio? Ho provato mille soluzioni, ma nessuna funziona; nel migliore dei casi riesco a ottenere i permalink giusti ma risultano in errore 404.
Per illustrare visivamente ciò che voglio:
/basename/ - idealmente una pagina, ma penso che questo causerà una collisione di permalink
/basename/top-cat/ - archivio della tassonomia personalizzata genitore
/basename/top-cat/child-cat/ - archivio della tassonomia personalizzata figlio
/basename/top-cat/child-cat/grandchild-cat/ - archivio della tassonomia personalizzata nipote
/basename/top-cat/child-cat/grandchild-cat/post-name/ - il mio post di tipo personalizzato
Si può fare tranquillamente con i post e le categorie predefinite, come si fa con le tassonomie personalizzate e i tipi di post personalizzati? So che bisogna usare 'rewrite' => array( 'slug' => 'tax-name', 'with_front' => true, 'hierarchical' => true ),
per ottenere gli slug gerarchici, che funzionano bene nelle pagine di archivio, ma i post di tipo personalizzato risultano in errore 404. Se rimuovo la parte 'hierarchical' => true
allora i post funzionano, ma perdo gli URL gerarchici (funziona solo /basename/grandchild-cat/post-name/).
Quindi, ci sono soluzioni? Grazie mille, questa cosa mi sta facendo impazzire da circa 3 settimane.
Dopo aver combinato diversi pezzi di altre risposte, sono riuscito a farlo funzionare! Ecco quindi la soluzione per chi di voi sta affrontando lo stesso problema:
Questo post e quest'altro mi hanno aiutato molto, quindi un grazie a questi autori.
Nota: tutto questo codice, insieme al tuo codice iniziale di registrazione del custom post type e della tassonomia, va inserito nel file functions.php
.
Per prima cosa, assicurati di impostare correttamente gli slug quando definisci i tuoi custom post type e tassonomie: per il custom post type dovrebbe essere basename/%taxonomy_name%
e lo slug per la tua tassonomia dovrebbe essere semplicemente basename
. Non dimenticare di aggiungere anche 'hierarchical' => true
all'array rewrite della tassonomia per ottenere termini annidati nell'URL. Assicurati inoltre che query_var
sia impostato su true
in entrambi i casi.
Devi aggiungere una nuova regola di rewrite affinché WordPress sappia come interpretare la struttura del tuo URL. Nel mio caso, la parte del custom post type nell'URI sarà sempre il quinto segmento, quindi ho definito la mia regola di corrispondenza di conseguenza. Nota che potresti dover modificare questo aspetto se utilizzi più o meno segmenti URI. Se avrai livelli variabili di termini annidati, dovrai scrivere una funzione per verificare se l'ultimo segmento URI è un custom post type o un termine della tassonomia per sapere quale regola aggiungere (chiedimi se hai bisogno di aiuto su questo).
add_filter('rewrite_rules_array', 'mmp_rewrite_rules');
function mmp_rewrite_rules($rules) {
$newRules = array();
$newRules['basename/(.+)/(.+)/(.+)/(.+)/?$'] = 'index.php?custom_post_type_name=$matches[4]'; // la mia struttura personalizzata avrà sempre il nome del post come quinto segmento URI
$newRules['basename/(.+)/?$'] = 'index.php?taxonomy_name=$matches[1]';
return array_merge($newRules, $rules);
}
Poi devi aggiungere questo codice per far capire a WordPress come gestire %taxonomy_name%
nella struttura dello slug di rewrite del tuo custom post type:
function filter_post_type_link($link, $post)
{
if ($post->post_type != 'custom_post_type_name')
return $link;
if ($cats = get_the_terms($post->ID, 'taxonomy_name'))
{
$link = str_replace('%taxonomy_name%', get_taxonomy_parents(array_pop($cats)->term_id, 'taxonomy_name', false, '/', true), $link); // vedi la funzione personalizzata definita sotto
}
return $link;
}
add_filter('post_type_link', 'filter_post_type_link', 10, 2);
Ho creato una funzione personalizzata basata sulla funzione get_category_parents
di WordPress:
// mia funzione personalizzata per fare ciò che get_category_parents fa per altre tassonomie
function get_taxonomy_parents($id, $taxonomy, $link = false, $separator = '/', $nicename = false, $visited = array()) {
$chain = '';
$parent = &get_term($id, $taxonomy);
if (is_wp_error($parent)) {
return $parent;
}
if ($nicename)
$name = $parent -> slug;
else
$name = $parent -> name;
if ($parent -> parent && ($parent -> parent != $parent -> term_id) && !in_array($parent -> parent, $visited)) {
$visited[] = $parent -> parent;
$chain .= get_taxonomy_parents($parent -> parent, $taxonomy, $link, $separator, $nicename, $visited);
}
if ($link) {
// nulla, non riesco a farlo funzionare :(
} else
$chain .= $name . $separator;
return $chain;
}
Poi devi svuotare i permalink (basta caricare la pagina delle impostazioni dei permalink).
Ora tutto "dovrebbe" funzionare, si spera! Crea una serie di termini della tassonomia e annidali correttamente, poi crea alcuni post del custom post type e categorizzali correttamente. Puoi anche creare una pagina con lo slug basename
, e tutto dovrebbe funzionare come specificato nella mia domanda. Potresti voler creare alcune pagine di archivio personalizzate per la tassonomia per controllare il loro aspetto e aggiungere un plugin per un widget di tassonomia per mostrare le tue categorie annidate nella sidebar.
Spero che questo ti aiuti!

Ciao Jeff, grazie per la tua risposta! Ci sono quasi, dopo 4 ore a combattere con questo. Il mio unico problema è che ottengo una doppia barra prima del nome del post (come questo: portfolio/diseno-grafico-2/logo//alquimia-sonora/). Puoi aiutarmi?

@Cmorales, Non sono sicuro senza vedere il tuo codice, ma cerca un punto in cui definisci manualmente una barra prima del nome del post, magari nella registrazione dello slug del CPT o nella funzione filter_post_type? Se non riesci a individuare dove stai aggiungendo la barra extra, potresti semplicemente rimuovere l'ultimo carattere dal valore restituito dalla funzione get_taxonomy_parents chiamata in filter_post_type_link, perché questo ti lascerà con una barra finale, che è la prima delle doppie. Buona fortuna.

Ho creato i permalink come nella tua guida ma il link predefinito in WordPress per il custom post type è: domain.com/my-post-type/custom-post-type-name (domain.com/place/lotus-hotel) Ho appena testato il tuo codice nel file function.php, non riesco a trovare il modo per aggiungere la tassonomia personalizzata al link sopra (domain.com/place/tokyo/lotus-hotel) - tokyo è la mia tassonomia personalizzata

Risolto - vedi domanda. Jeff, grazie per la spiegazione! Ma potresti pubblicare la struttura del custom post type / taxonomy? Così posso capire cosa sto facendo di sbagliato? Sarei davvero grato!

Grazie mille per questo. Un piccolo problema però, sembra che inquini le regole di riscrittura con una serie di voci %taxonomy_name% o nel mio caso: apps/%primary_tag%/([^/]+)/page/?([0-9]{1,})/?$] => index.php?%primary_tag%$matches[1]&apps-post=$matches[2]&paged=$matches[3]
Le regole che aggiungo manualmente hanno la precedenza e sembrano funzionare, ma queste voci implicano che qualcosa non sia del tutto corretto. Hai qualche idea?

"Se avrai livelli variabili di termini annidati, dovrai scrivere una funzione per verificare se l'ultimo segmento dell'URI è un custom post type o un termine della tassonomia per sapere quale regola aggiungere (chiedimi se hai bisogno di aiuto su questo)..." Beh, puoi aiutarmi, per favore? :)

^ è esattamente ciò di cui avevo bisogno. Qualcuno sa come farlo? Vedi la mia domanda qui: http://wordpress.stackexchange.com/questions/102246/wordpress-returns-404-on-custom-rewrite-rules

Questo ha funzionato bene, ma per qualche motivo sta recuperando solo la categoria genitore e nessuna delle sottocategorie. Ho copiato esattamente come hai postato e ho cambiato solo i nomi del mio post type e delle taxonomy dove indicato. Hai qualche idea?

So che è un po' vecchio, ma hai qualche idea su come mantenere '/basename' puntato verso gli elementi più recenti in quel post type indipendentemente dalla tassonomia?

Dopo 3 ore di ricerche su Google, questa è la risposta. Per quelli di voi che stanno usando un formato /tipo_post/termine/slug/ (senza gerarchia), potete rimuovere la funzione get_taxonomy_parents() e sostituirla con $cats[0]->slug visto che c'è già un controllo per verificare se ha termini. Quella funzione è anche la cosa che aggiunge un altro slash.

Dai un'occhiata a questo plugin (ora su github). Fornisce URL gerarchici per le categorie, ma puoi facilmente adattarlo a qualsiasi tassonomia.
La creazione delle regole segue una funzione ricorsiva.

Per gestire diversi livelli di annidamento,
/basename/top-cat/ -> Archivio Top Cat
/basename/top-cat/nome-post/ -> Post in Top Cat
/basename/top-cat/child-cat/ -> Archivio Child Cat
/basename/top-cat/child-cat/nome-post/ -> Post in Child Cat
Alla fine ho utilizzato la soluzione di Jeff senza il filtro rewrite_rules_array
. Invece ho usato il filtro request
per verificare se l'ultima parte dell'URL è un nome di post valido e aggiungerlo alle query_vars.
Ad esempio:
function vk_query_vars($qvars){
if(is_admin()) return $qvars;
$custom_taxonomy = 'product_category';
if(array_key_exists($custom_taxonomy, $qvars)){
$custom_post_type = 'product';
$pathParts = explode('/', $qvars[$custom_taxonomy]);
$numParts = sizeof($pathParts);
$lastPart = array_pop($pathParts);
$post = get_page_by_path($lastPart, OBJECT, $custom_post_type);
if( $post && !is_wp_error($post) ){
$qvars['p'] = $post->ID;
$qvars['post_type'] = $custom_post_type;
}
}
return $qvars;
}
add_filter('request', 'vk_query_vars');

Ecco la mia versione della soluzione di Jeff. Il rewrite_rules_array
potrebbe non essere necessario a seconda dell'applicazione. Questo semplifica il filter_post_type_link
e non richiede funzioni aggiuntive. Utilizza la funzione integrata get_term_parents_list()
function PLUGIN_filter_post_type_link($post_link, $post)
{
$postTypes = ['CUSTOM-POST-TYPE'];
$taxonomy = 'TAXONOMY';
/* se il post_type corrisponde */
if (in_array($post->post_type, $postTypes, $strict=true)) {
/* se è assegnata una tassonomia */
if ($terms = get_the_terms($post->ID, $taxonomy)
) {
$args = [
'format' => 'slug',
'separator' => '/',
'link' => false,
'inclusive' => true,
];
return str_replace(
"%{$taxonomy}%",
rtrim(
get_term_parents_list($terms[0]->term_id, $taxonomy, $args),
"/"
),
$post_link);
}
/* rimuovi la tassonomia e lo slash finale dal post_link */
return str_replace("%{$taxonomy}%/", '', $post_link);
}
return $post_link;
}
