Regulă personalizată de rescriere pentru tipuri de postări personalizate ierarhice

15 ian. 2016, 04:43:53
Vizualizări: 16.7K
Voturi: 1

Lucrez la un site pentru un client și m-am lovit de cel mai mare dușman... rescrierea URL-urilor în WP :(. Chiar nu reușesc să îmi dau seama și după multe zile de încercări și căutări, nu reușesc să funcționeze.

Ceea ce încerc să obțin este un permalink de genul company.com/produs/%nume-produs%/ indiferent de adâncimea ierarhiei /părinte/copil/. Am nevoie de funcționalitățile paginilor ierarhice din alte motive, dar acestea nu ar trebui să apară în URL.

Iată configurația mea:

  • Wordpress 4.4.1
  • Setările de permalink setate la Numele postării

  • Am creat un tip de postare ierarhic personalizat produs cu parametrul de rescriere setat pe false.

    $args = array(
        'label'                 => __( 'Produs', 'domeniu' ),
        'description'           => __( 'Produsele companiei', 'domeniu' ),
        '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( 'produs', $args );
    

În acest moment produsele nu au un permalink frumos, arată astfel și funcționează ambele:

  1. Primul nivel: company.com/?produs=primul-meu-produs -> ok
  2. Al doilea nivel: company.com/?produs=primul-meu-produs/produs-copil -> ok

După aceea, am înregistrat regula de rescriere și permastruct-ul, apoi am reîmprospătat regulile de rescriere salvând modificările în pagina de setări de permalink

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

Acum permalink-urile erau afișate corect pentru pagina de prim nivel, dar nu și pentru pagina copil. De asemenea, ambele niveluri mi-au dat eroare 404.

  1. Primul nivel: company.com/produs/primul-meu-produs/ -> 404
  2. Al doilea nivel: company.com/produs/primul-meu-produs/produs-copil/ -> 404

Am încercat și o soluție dată aici https://wordpress.stackexchange.com/a/101077/86838 care permite eliminarea slug-ului părinte din permalink-ul copilului, dar tot nu am reușit

function bvt_produs_flatten_hierarchies( $post_link, $post ) {
    if ( 'produs' != $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_produs_flatten_hierarchies', 10, 2 );

Am instalat două plugin-uri debug-bar și monkeyman-rewrite-analyzer pentru a analiza rescrierea și interogarea, dar tot nu reușesc să le fac să funcționeze.

Ultima mea încercare a fost cu plugin-ul wp-permastructure care permite setarea de permalink-uri personalizate pentru tipurile de postări personalizate. Acesta activează setarea personalizată permastruct în array-ul de opțiuni rewrite al funcției register_post_type.

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

Cu această setare și ambele funcții personalizate de rescriere/permastruct/flatten_hierarchies dezactivate, a funcționat conform descrierii plugin-ului

  1. Primul nivel: company.com/primul-meu-produs/ -> ok
  2. Al doilea nivel: company.com/produs-copil/ -> ok

Dar acum lipsește nivelul /produs/, iar dacă încerc să îl adaug în configurația 'permastruct' => '/produs/%postname%/' revin la eroarea 404 pentru ambele.

Ceea ce mă aduce la întrebarea principală.

Este posibil să fac ceea ce am nevoie sau doar ceea ce am reușit cu ultimul plugin?

Vă mulțumesc deja pentru oricine care își va lua timpul să îmi răspundă și poate mă va salva din situația mea nefericită. Mulțumesc

PS Nu pot insera mai mult de două link-uri în corp, așa că iată link-urile plugin-urilor menționate:

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

Un lucru care poate strica rescrierile sunt templates. Asigură-te că nimic nu stă în calea ta și acolo. Personal, aș evita pluginurile la început și aș încerca să fac rescrierea să funcționeze cu argumentul CPT rewrite.

Nathan Powell Nathan Powell
15 ian. 2016 04:49:10

Hei Nathan, sunt de acord cu tine în legătură cu pluginurile. Întotdeauna încerc să fac lucrurile cât mai simple posibil, dar de data aceasta am fost destul de disperat.

Kuuak Kuuak
15 ian. 2016 10:54:12
Toate răspunsurile la întrebare 1
1

Ești aproape. Regula ta de rescriere folosește variabila de interogare greșită, pagename ar trebui să fie doar name.

Iată o versiune care funcționează pentru mine pe o instalare nouă de WordPress 4.4.1 și tema twentysixteen:

function bvt_product_init() {
    $args = array(
        'label'                 => __( 'Produs', 'domain' ),
        'description'           => __( 'Produsele companiei', '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 );

O problemă potențială de care trebuie să fii atent: tipurile de postări ierarhice îți permit să creezi postări cu același slug dar cu părinți diferiți. În mod normal, acest lucru funcționează pentru că sunt interogate pe baza căilor părinte/copil. Fără a avea această relație părinte/copil în structura URL-ului, poți crea postări care nu pot fi niciodată interogate în partea de frontend dacă slug-ul se potrivește cu o postare existentă. Doar ceva de ținut minte.

15 ian. 2016 07:44:05
Comentarii

Bună Milo, îți mulțumesc foarte mult, a fost într-adevăr foarte aproape. Prin schimbarea doar a pagename cu name a funcționat. În legătură cu problema aceeași slug, m-am ocupat de asta forțând un număr sku unic în slug. Mulțumesc din nou

Kuuak Kuuak
15 ian. 2016 10:56:40