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 entradaCreé un tipo de post personalizado jerárquico
productcon 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.