Regola di riscrittura personalizzata per tipi di post personalizzati gerarchici

15 gen 2016, 04:43:53
Visualizzazioni: 16.7K
Voti: 1

Sto lavorando al sito di un cliente e mi sono imbattuto nel mio peggior nemico... la riscrittura degli URL in WP :(. Non riesco proprio a capirlo e dopo molti giorni di tentativi e ricerche, non riesco a farlo funzionare.

Quello che sto cercando di ottenere è un permalink come questo company.com/prodotto/%nome-prodotto%/ indipendentemente dall'annidamento /genitore/figlio/. Ho bisogno delle funzionalità delle pagine gerarchiche per altri motivi, ma non dovrebbero apparire nell'URL.

Ecco la mia configurazione:

  • Wordpress 4.4.1
  • Impostazioni dei permalink impostate su Nome articolo

  • Ho creato un tipo di post personalizzato gerarchico prodotto con il parametro rewrite impostato su false.

    $args = array(
        'label'                 => __( 'Prodotto', 'domain' ),
        'description'           => __( 'Prodotti dell\'azienda', 'domain' ),
        'labels'                => $labels,
        'supports'              => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions', 'page-attributes' ),
        'taxonomies'            => array( 'category', 'post_tag' ),
        'hierarchical'          => true,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 5,
        'show_in_admin_bar'     => true,
        'show_in_nav_menus'     => false,
        'can_export'            => true,
        'has_archive'           => true,
        'exclude_from_search'   => false,
        'publicly_queryable'    => true,
        'rewrite'               => false,
        'capability_type'       => 'page',
    );
    register_post_type( 'prodotto', $args );
    

A questo punto i prodotti non hanno un permalink leggibile, appaino così e funzionano entrambi:

  1. Primo livello: company.com/?prodotto=mio-primo-prodotto -> ok
  2. Secondo livello: company.com/?prodotto=mio-primo-prodotto/prodotto-figlio -> ok

Dopodiché, ho registrato la regola di riscrittura e il permastruct poi ho resettato le regole di riscrittura salvando le modifiche nella pagina delle impostazioni dei permalink

    function bvt_product_rewrite_rule() {
        add_rewrite_rule( 
            '^prodotto/([^/]+)/?$',
            'index.php?post_type=prodotto&pagename=$matches[1]',
            'top'
        );
        add_permastruct( 'prodotto', '/prodotto/%prodotto%/' );
    }
    add_action( 'init', 'bvt_product_rewrite_rule', 10 );

Ora i permalink venivano visualizzati correttamente per le pagine di primo livello ma non per le pagine figlie. Inoltre entrambi i livelli mi davano un errore 404.

  1. Primo livello: company.com/prodotto/mio-primo-prodotto/ -> 404
  2. Secondo livello: company.com/prodotto/mio-primo-prodotto/prodotto-figlio/ -> 404

Ho anche provato una soluzione data qui https://wordpress.stackexchange.com/a/101077/86838 che permetteva di rimuovere lo slug del genitore dal permalink del figlio, ma senza successo

function bvt_product_flatten_hierarchies( $post_link, $post ) {
    if ( 'prodotto' != $post->post_type ) {
        return $post_link;
    }

    $uri = '';
    foreach ( $post->ancestors as $parent ) {
        $uri = get_post( $parent )->post_name . "/" . $uri;
    }

    return str_replace( $uri, '', $post_link );
}
add_filter( 'post_type_link', 'bvt_product_flatten_hierarchies', 10, 2 );

Ho installato due plugin debug-bar e monkeyman-rewrite-analyzer per analizzare la riscrittura e la query, ma non riesco ancora a farlo funzionare.

Il mio ultimo tentativo è stato con il plugin wp-permastructure che permette di impostare permalink personalizzati per i tipi di post personalizzati. Questo abilita l'impostazione personalizzata permastruct nell'array rewrite dell'opzione register_post_type.

[...]
'publicly_queryable'    => true,
'rewrite'               => array(
    'permastruct'   => '/%postname%/',
),
'capability_type'       => 'page',
[...]

Con questa impostazione e disabilitando sia la riscrittura personalizzata che il flatten_hierarchies, ha funzionato come descritto dal plugin

  1. Primo livello: company.com/mio-primo-prodotto/ -> ok
  2. Secondo livello: company.com/prodotto-figlio/ -> ok

Ma ora manca il livello /prodotto/, e se provo a inserirlo nella configurazione 'permastruct' => '/prodotto/%postname%/' mi riporta a un errore 404.

Il che mi porta alla mia domanda principale.

È possibile fare quello che ho bisogno o solo avvicinarmi come ho fatto con l'ultimo plugin?

Grazie già a chiunque prenderà il tempo di rispondermi, e magari salvarmi dalla mia povera situazione. Grazie

PS Non posso inserire più di due link nel corpo quindi ecco i link dei plugin menzionati:

https://wordpress.org/plugins/debug-bar/
https://wordpress.org/plugins/monkeyman-rewrite-analyzer/
https://wordpress.org/plugins/wp-permastructure/
2
Commenti

Una cosa che può creare problemi con i rewrite sono i templates. Assicurati che non ci sia nulla che ti ostacoli anche lì. Personalmente, all'inizio eviterei i plugin e proverei a far funzionare il rewrite con l'argomento rewrite del CPT.

Nathan Powell Nathan Powell
15 gen 2016 04:49:10

Ciao Nathan, sono d'accordo con te riguardo ai plugin. Cerco sempre di fare le cose nel modo più semplice possibile, ma questa volta ero piuttosto disperato.

Kuuak Kuuak
15 gen 2016 10:54:12
Tutte le risposte alla domanda 1
1

Sei molto vicino. La tua regola di riscrittura sta usando la variabile di query sbagliata, pagename dovrebbe essere semplicemente name.

Ecco una versione che funziona per me su un'installazione pulita di WordPress 4.4.1 con il tema Twenty Sixteen:

function bvt_product_init() {
    $args = array(
        'label'                 => __( 'Prodotto', 'domain' ),
        'description'           => __( 'Prodotti dell\'azienda', 'domain' ),
        'supports'              => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions', 'page-attributes' ),
        'taxonomies'            => array( 'category', 'post_tag' ),
        'hierarchical'          => true,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 5,
        'show_in_admin_bar'     => true,
        'show_in_nav_menus'     => false,
        'can_export'            => true,
        'has_archive'           => true,
        'rewrite'               => array( 'slug' => 'product' ),
    );
    register_post_type( 'product', $args );

    add_rewrite_rule( 
        '^product/([^/]+)/?$',
        'index.php?post_type=product&name=$matches[1]',
        'top'
    );
}
add_action( 'init', 'bvt_product_init' );

function bvt_product_flatten_hierarchies( $post_link, $post ) {
    if ( 'product' != $post->post_type ) {
        return $post_link;
    }
    $uri = '';
    foreach ( $post->ancestors as $parent ) {
        $uri = get_post( $parent )->post_name . "/" . $uri;
    }
    return str_replace( $uri, '', $post_link );
}
add_filter( 'post_type_link', 'bvt_product_flatten_hierarchies', 10, 2 );

Un potenziale problema da tenere presente: i tipi di post gerarchici ti permettono di creare post con lo stesso slug che hanno genitori diversi. Normalmente questo funziona perché vengono interrogati in base ai loro percorsi genitore/figlio. Senza avere questa relazione genitore/figlio nella struttura degli URL, puoi creare post che non potranno mai essere interrogati sul front-end se lo slug corrisponde a un post esistente. È solo qualcosa da tenere a mente.

15 gen 2016 07:44:05
Commenti

Ciao Milo, grazie mille, era davvero molto vicino. Cambiando solo pagename con name ha funzionato. Per quanto riguarda il problema dello slug identico, ci ho pensato io forzando un numero sku univoco nello slug. Grazie ancora

Kuuak Kuuak
15 gen 2016 10:56:40