Tipos de posts personalizados, taxonomías y enlaces permanentes
Esto me está volviendo loco y estoy seguro de que es simple, pero nada de lo que busco muestra una estructura simple (todo es muy complejo).
Tengo un tipo de post personalizado product_listing
y una taxonomía personalizada product_cat
(que es jerárquica y debe comportarse como categorías).
Simplemente quiero que mis URLs se vean así:
mysite.com/products/category1/product-name1
mysite.com/products/category2/product-name2
Pero por más que lo intento, sigo obteniendo el temido error 404. Las páginas funcionan bien y los Posts funcionan bien, pero mis posts personalizados no funcionan correctamente. Se están mostrando como:
mysite.com/products/product-name1
mysite.com/products/product-name2
¡Lo cual realmente funciona! Es solo que quiero ver mi taxonomía personalizada allí y además quiero poder acceder a la plantilla taxonomy.php
que tengo configurada yendo a:
mysite.com/products/category1/
mysite.com/products/category2/
Ninguno de mis slugs es igual, ni quiero que lo sean. Aquí está la parte del tipo de post y taxonomía de mi archivo functions.php
:
///// TIPOS DE POST PERSONALIZADOS /////
// registrar el nuevo tipo de post
register_post_type( 'product_listing', array(
'labels' => array(
'name' => __( 'Productos' ),
'singular_name' => __( 'Producto' ),
'add_new' => __( 'Añadir Nuevo' ),
'add_new_item' => __( 'Crear Nuevo Producto' ),
'edit' => __( 'Editar' ),
'edit_item' => __( 'Editar Producto' ),
'new_item' => __( 'Nuevo Producto' ),
'view' => __( 'Ver Productos' ),
'view_item' => __( 'Ver Producto' ),
'search_items' => __( 'Buscar Productos' ),
'not_found' => __( 'No se encontraron productos' ),
'not_found_in_trash' => __( 'No se encontraron productos en la papelera' ),
'parent' => __( 'Producto Padre' ),
),
'description' => __( 'Aquí es donde puedes crear nuevos productos en tu sitio.' ),
'public' => true,
'show_ui' => true,
'capability_type' => 'post',
'publicly_queryable' => true,
'exclude_from_search' => false,
'menu_position' => 2,
'menu_icon' => get_stylesheet_directory_uri() . '/images/tag_orange.png',
'hierarchical' => true,
'_builtin' => false, // ¡Es un tipo de post personalizado, no integrado!
'rewrite' => array( 'slug' => 'products', 'with_front' => true ),
'query_var' => true,
'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions' ),
) );
//conectar a la acción init y llamar a create_book_taxonomies cuando se active
add_action( 'init', 'create_product_taxonomies', 0 );
//add_action('admin_init', 'flush_rewrite_rules');
//crear dos taxonomías, géneros y escritores para el tipo de post "book"
function create_product_taxonomies() {
// Agregar nueva taxonomía, hacerla jerárquica (como categorías)
$labels = array(
'name' => _x( 'Categorías', 'nombre general de taxonomía' ),
'singular_name' => _x( 'Categoría', 'nombre singular de taxonomía' ),
'search_items' => __( 'Buscar Categorías' ),
'all_items' => __( 'Todas las Categorías' ),
'parent_item' => __( 'Categorías Padre' ),
'parent_item_colon' => __( 'Categorías Padre:' ),
'edit_item' => __( 'Editar Categoría' ),
'update_item' => __( 'Actualizar Categoría' ),
'add_new_item' => __( 'Añadir Nueva Categoría' ),
'new_item_name' => __( 'Nuevo Nombre de Categoría' ),
'menu_name' => __( 'Categoría' ),
);
register_taxonomy( 'product_cat', array( 'product_listing' ), array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'query_var' => true,
//'rewrite' => true,
'rewrite' => array( 'slug' => '%category%', 'with_front' => true ),
) );
// Agregar nueva taxonomía, NO jerárquica (como etiquetas)
$labels = array(
'name' => _x( 'Aromas', 'nombre general de taxonomía' ),
'singular_name' => _x( 'Aroma', 'nombre singular de taxonomía' ),
'search_items' => __( 'Buscar Aromas' ),
'popular_items' => __( 'Aromas Populares' ),
'all_items' => __( 'Todos los Aromas' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'Editar Aroma' ),
'update_item' => __( 'Actualizar Aroma' ),
'add_new_item' => __( 'Añadir Nuevo Aroma' ),
'new_item_name' => __( 'Nuevo Nombre de Aroma' ),
'separate_items_with_commas' => __( 'Separar aromas con comas' ),
'add_or_remove_items' => __( 'Añadir o eliminar aromas' ),
'choose_from_most_used' => __( 'Elegir entre los aromas más usados' ),
'menu_name' => __( 'Aromas' ),
);
register_taxonomy( 'scent', 'product_listing', array(
'hierarchical' => false,
'labels' => $labels,
'show_ui' => true,
'query_var' => true,
//'rewrite' => array( 'slug' => 'scents' ),
) );
}
También tengo otra taxonomía personalizada de scents
que idealmente me gustaría que tuviera algún tipo de url amigable, pero soy más flexible en esto. Me gustaría poder acceder a una lista de todos los aromas yendo a mysite.com/products/scents
pero no tienen que ser específicos de la categoría.
¿Alguien puede ayudarme?

Cambia el slug
en los argumentos de tu tipo de entrada a products/%product_cat%
, y el slug
en los argumentos de tu taxonomía a simplemente products
, luego regenera las reglas de reescritura. ¡Ahora WordPress debería manejar /products/mi-categoria-de-producto/nombre-del-post/
!
Finalmente, necesitamos ayudar un poco a WordPress con la generación de enlaces permanentes (por defecto, no reconocerá la etiqueta %product_cat%
en la estructura de enlaces):
/**
* Inyecta el slug del término en la estructura de enlaces permanentes del tipo de entrada personalizado.
*
* @link http://wordpress.stackexchange.com/a/5313/1685
*
* @param string $link
* @param WP_Post $post
* @return array
*/
function wpse_5308_post_type_link( $link, $post ) {
if ( $post->post_type === 'product_listing' ) {
if ( $terms = get_the_terms( $post->ID, 'product_cat' ) )
$link = str_replace( '%product_cat%', current( $terms )->slug, $link );
}
return $link;
}
add_filter( 'post_type_link', 'wpse_5308_post_type_link', 10, 2 );
Algo importante: esto simplemente tomará la primera categoría de producto para el post ordenada por nombre. Si estás asignando múltiples categorías a un solo producto, puedo fácilmente cambiar cómo determina cuál usar en el enlace permanente.
¡Déjame saber cómo te va con esto y podemos abordar los otros problemas!

¡Oh VAYA! ¡Estoy impresionado! ¡Esto FUNCIONÓ! ¡Finalmente! ¡Nunca pensé que algo lo haría!!! Muchísimas gracias!!! ............ Ahora, ¿cómo generaría un enlace (algo como the_permalink) para obtener la URL de la taxonomía por sí sola? /products/my-product-cat/

Creo que resolví eso^^^ ............ pero ahora estoy atascado con la Paginación. Parece romperse al usar cualquier paginación (función personalizada o incorporada) ya que /products/my-product-cat/ se ve bien pero /products/my-product-cat/page/2/ devuelve un error 404 y abandona el archivo taxonomy.php en favor del archivo index.php. He intentado todo lo que pude encontrar y todavía nada.

¿Considerarías cambiar las reglas de reescritura (rewrites) para productos individuales a product/cat-name/product-name
? (nota la singularidad) El problema es que la regla de reescritura para la paginación de taxonomía no se activa, ¡porque queda atrapada por una regla anterior para productos individuales!

Estoy abierto a ello. Pero para entenderlo, ¿eso significaría que los productos tendrían una ruta URL diferente si estás viendo una página de producto individual vs. una página de 'categoría'? Entonces, el individual sería producto/nombre-cat/nombre-prod pero las categorías serían productos/nombre-cat/? ¿No sería eso como contradecir el propósito de las URLs "amigables para humanos"? Me cuesta ayudar a mis clientes a aprender el panel de WordPress, y mucho menos esa diferencia... Si lo estoy entendiendo mal, por favor házmelo saber. También podría estar contento SIN un directorio frontal, como categoria-producto/nombre-producto y simplemente categoria-producto/. ¿Podría funcionar eso?

Lo has entendido, aunque diría que SÍ es "amigable para humanos", ya que hay una clara distinción entre archivos (productos/
) y elementos individuales (producto/
). Y no, yo mantendría el 'directorio frontal', ya que ayuda a mantener una clara distinción de las entradas y páginas, además de que de lo contrario podrías terminar con problemas de rendimiento (es decir, reglas de reescritura verbosas).

Vale, ¿qué tal si mantenemos tu sugerencia anterior pero usando términos menos relacionados? Digamos... producto/nombre-cat/nombre-producto/ para páginas de productos individuales... y algo como categorias/nombre-cat/ para las páginas de archivo de categorías? ¿Qué necesitaría modificar en el código anterior para que eso funcione?

Probé ese plugin que sugería la otra respuesta y parece funcionar bien para /products/cat-name/prod-name/ Y /products/cat-name/ ... ¿es una opción viable?

Podría ser que el plugin genera las reglas de reescritura manualmente en un orden que funciona - lo único que haría sería monitorear el rendimiento - usa <?php timer_stop(true); ?>
y <?php echo get_num_queries(); ?>
en algún lugar de tu footer.php
, y observa qué promedios obtienes al solicitar archivos de taxonomía y productos individuales.

¿Encontraron alguna manera de solucionar esto? Probé el código que sugirió @TheDeadMedic y el plugin pero ninguno funciona correctamente. Si es así, por favor revisa mi pregunta. ¡Gracias! - http://wordpress.stackexchange.com/questions/40587/shouldnt-this-be-easy-custom-post-type-custom-taxonomy-permalink

Gracias @TheDeadMechanic, tu respuesta me ayudó, pero solo parcialmente. Quería hacer lo mismo que preguntó @RodeoRamsey, pero con categorías anidadas (ej: misitio.com/productos/categoria1/subcategoria-1/subsubcategoria-1/nombre-del-producto
) y tu solución no funcionó para eso.
Finalmente encontré una solución extendida a mi pregunta que sí funciona, así que si alguien más necesita categorías/subcategorías anidadas puedes ver una solución detallada en mi propia pregunta. Espero que ayude a otros, y gracias por los pasos iniciales.

No estoy seguro de que WordPress admita esa estructura de forma nativa, pero puedes crear fácilmente tus propias reglas de reescritura para lograrlo.
Consulta una respuesta anterior aquí Reescritura de URL de autor.
Puedes cambiar la línea
$newrules['author/([^/]+)/songs/?$'] = 'index.php?post_type=songs&author=$matches[1]';
por algo como
$newrules['products/([^/]+)/([^/]+)/?$'] = 'index.php?post_type=product_listing&product_cat=$matches[1]&name=$matches[2]';
la parte de product_cat aquí puede ser superflua - no estoy seguro si es necesaria.
Puedes añadir cualquier regla que desees y tendrán prioridad sobre las integradas.

Vaya, qué interesante. Oh cielos, creo que las reglas de reescritura personalizadas están más allá de mis capacidades. Probé el código anterior (y el resto del otro post) y no cambió nada. Limpié todo e intenté de nuevo y aún así ningún cambio, así que comenté todas las reglas de reescritura establecidas en los tipos de contenido personalizados y taxonomías, limpié y AÚN nada.

Sí, me estaba volviendo loco antes de configurar el enlace permanente para el tipo de contenido personalizado. Encontré un plugin para manejar el tipo de contenido personalizado. Es muy fácil de usar. http://wordpress.org/extend/plugins/custom-post-permalinks/ ¡WordPress debería añadir esto como función básica! Leo

Había visto esta opción antes y me abstuve de usarla porque decía "para taxonomías no jerárquicas". Tenía una que estaba configurada como jerárquica, así que no pensé que funcionaría, pero hasta ahora, ¡parece haber hecho el truco! Además, parece estar funcionando para lograr la estructura /productos/nombre-categoria/nombre-producto/ que estaba tratando de conseguir (ver comentario en otra respuesta). @TheDeadMedic, ¿es esta una opción viable? ¿O debería seguir con las reescrituras en el archivo functions.php?

En realidad, es bastante sencillo. Solo necesitas una línea. Aquí está mi código
function create_product_taxonomies()
{
// Añadir nueva taxonomía, hacerla jerárquica (como categorías)
$labels = array(
'name' => _x('Categorías', 'taxonomy general name'),
'singular_name' => _x('Categoría', 'taxonomy singular name'),
'search_items' => __('Buscar Categorías'),
'all_items' => __('Todas las Categorías'),
'parent_item' => __('Categorías Padre'),
'parent_item_colon' => __('Categorías Padre:'),
'edit_item' => __('Editar Categoría'),
'update_item' => __('Actualizar Categoría'),
'add_new_item' => __('Añadir Nueva Categoría'),
'new_item_name' => __('Nombre de la Nueva Categoría'),
'menu_name' => __('Categoría'),
);
register_taxonomy('product_cat', array('product_listing'), array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'query_var' => true,
'rewrite' => array('hierarchical' => true),
));
Y aplicado a la taxonomía generada para mi CPT de Reseñas desde GenerateWP.com. Estoy usando esto en mi propio sitio WordPress, https://www.wpstarters.com
function reviews_category_taxonomy() {
$labels = array(
'name' => _x( 'Categorías de Reseñas', 'Taxonomy General Name', 'reviews_category' ),
'singular_name' => _x( 'Categoría de Reseña', 'Taxonomy Singular Name', 'reviews_category' ),
'menu_name' => __( 'Categoría de Reseña', 'reviews_category' ),
'all_items' => __( 'Todas las Categorías de Reseña', 'reviews_category' ),
'parent_item' => __( 'Categoría de Reseña Padre', 'reviews_category' ),
'parent_item_colon' => __( 'Categoría de Reseña Padre:', 'reviews_category' ),
'new_item_name' => __( 'Nombre de Nueva Categoría de Reseña', 'reviews_category' ),
'add_new_item' => __( 'Añadir Nueva Categoría de Reseña', 'reviews_category' ),
'edit_item' => __( 'Editar Categoría de Reseña', 'reviews_category' ),
'update_item' => __( 'Actualizar Categoría de Reseña', 'reviews_category' ),
'view_item' => __( 'Ver Categoría de Reseña', 'reviews_category' ),
'separate_items_with_commas' => __( 'Separar elementos con comas', 'reviews_category' ),
'add_or_remove_items' => __( 'Añadir o eliminar elementos', 'reviews_category' ),
'choose_from_most_used' => __( 'Elegir de los más usados', 'reviews_category' ),
'popular_items' => __( 'Categorías de Reseña Populares', 'reviews_category' ),
'search_items' => __( 'Buscar Elementos', 'reviews_category' ),
'not_found' => __( 'No Encontrado', 'reviews_category' ),
'no_terms' => __( 'No hay Categorías de Reseña', 'reviews_category' ),
'items_list' => __( 'Lista de Categorías de Reseña', 'reviews_category' ),
'items_list_navigation' => __( 'Navegación de lista de Categorías de Reseña', 'reviews_category' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => false,
'show_in_rest' => true,
'rewrite' => array( 'hierarchical' => true ),
);
register_taxonomy( 'reviews_category', array( 'wps_reviews' ), $args );
}
add_action( 'init', 'reviews_category_taxonomy', 0 );
Todo lo que necesitas es añadir 'rewrite' => array('hierarchical' => true),
