Regla de reescritura personalizada para tipos de post personalizados jerárquicos
Trabajando en un sitio de un cliente me he encontrado con mi peor enemigo... la reescritura de URLs en WP :(. Realmente no puedo resolverlo y después de muchos días intentándolo y buscando, no logro que funcione.
Lo que estoy tratando de conseguir es un enlace permanente como este company.com/product/%nombre-del-producto%/
sin importar la profundidad del anidamiento /parent/child/
. Necesito las funcionalidades de las páginas jerárquicas por otros motivos, pero no deberían aparecer en la URL.
Aquí está mi configuración:
- Wordpress 4.4.1
Ajustes de enlaces permanentes establecidos en
Nombre de la entrada
Creé un tipo de post personalizado jerárquico
product
con el parámetro rewrite establecido en false.$args = array( 'label' => __( 'Product', 'domain' ), 'description' => __( 'Productos de la compañía', '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( 'product', $args );
En este punto los productos no tienen un enlace permanente bonito, se ven así y ambos funcionan:
- Primer nivel:
company.com/?product=mi-primer-producto
-> ok - Segundo nivel:
company.com/?product=mi-primer-producto/producto-hijo
-> ok
Después de eso, registré la regla de reescritura y el permastruct luego limpié las reglas de reescritura guardando cambios en la página de ajustes de enlaces permanentes
function bvt_product_rewrite_rule() {
add_rewrite_rule(
'^product/([^/]+)/?$',
'index.php?post_type=product&pagename=$matches[1]',
'top'
);
add_permastruct( 'product', '/product/%product%/' );
}
add_action( 'init', 'bvt_product_rewrite_rule', 10 );
Ahora los enlaces permanentes se mostraban correctamente para la página de primer nivel pero no para la página hija. Además ambos niveles me daban un error 404.
- Primer Nivel:
company.com/product/mi-primer-producto/
-> 404 - Segundo Nivel:
company.com/product/mi-primer-producto/producto-hijo/
-> 404
También probé una solución dada aquí https://wordpress.stackexchange.com/a/101077/86838 donde permitía eliminar el slug del padre del enlace permanente del hijo, pero aún no tuve éxito
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 );
Instalé dos plugins debug-bar y monkeyman-rewrite-analyzer para analizar la reescritura y la consulta, pero sigo sin poder hacer que funcione.
Mi último intento fue con el plugin wp-permastructure que permite establecer enlaces permanentes personalizados para tipos de post personalizados. Lo cual habilita el ajuste personalizado permastruct
en el array de opciones rewrite
de register_post_type
.
[...]
'publicly_queryable' => true,
'rewrite' => array(
'permastruct' => '/%postname%/',
),
'capability_type' => 'page',
[...]
Con este ajuste y deshabilitando tanto la reescritura/permatruct personalizada anterior como flatten_hierarchies, funcionó como se describe en el plugin
- Primer Nivel:
company.com/mi-primer-producto/
-> ok - Segundo Nivel:
company.com/producto-hijo/
-> ok
Pero ahora falta el nivel /product/
, y si intento ponerlo en la configuración 'permastruct' => '/product/%postname%/'
me devuelve un error 404.
Lo que me lleva a mi pregunta principal.
¿Es posible hacer lo que necesito o solo tan cerca como pude llegar con el último plugin?
Gracias de antemano a cualquiera que se tome el tiempo de responderme, y quizás salvarme de mi pobre situación. Gracias
PD: No puedo insertar más de dos enlaces en el cuerpo así que aquí están los enlaces mencionados de los plugins:
https://wordpress.org/plugins/debug-bar/
https://wordpress.org/plugins/monkeyman-rewrite-analyzer/
https://wordpress.org/plugins/wp-permastructure/
Estás muy cerca. Tu regla de reescritura está usando la variable de consulta incorrecta, pagename
debería ser simplemente name
.
Aquí tienes una versión que funciona para mí en una instalación limpia de WordPress 4.4.1 con el tema Twenty Sixteen:
function bvt_product_init() {
$args = array(
'label' => __( 'Producto', 'domain' ),
'description' => __( 'Productos de la empresa', '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' => 'producto' ),
);
register_post_type( 'product', $args );
add_rewrite_rule(
'^producto/([^/]+)/?$',
'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 problema potencial a tener en cuenta: los tipos de post jerárquicos te permiten crear posts con el mismo slug que tienen diferentes padres. Normalmente esto funciona porque se consultan por sus rutas padre/hijo. Sin tener esa relación padre/hijo en la estructura de URLs, puedes crear posts que nunca podrán ser consultados en el front-end si el slug coincide con un post existente. Solo algo para tener presente.
