Agregar base de categoría a URL en tipo de entrada/taxonomía personalizada
Estoy construyendo un sistema tipo LMS en WordPress, controlado por Custom Post types
.
El tipo de entrada se llama Lessons
(con un slug de courses
) y tiene una taxonomía personalizada
(categoría) llamada courses
.
La estructura de URL del dominio se muestra actualmente como:
domain.example/courses/lesson-name
.
Quiero que se convierta en:
domain.example/courses/[course-name{category}]/lesson-name
o esencialmente:
/[cpt]/%category%/%postname%/
Aquí está el plugin que escribí que está controlando los CPTs
ahora.
function rflms_post_type() {
$labels = array(
'name' => _x( 'Lessons', 'Post Type General Name', 'text_domain' ),
'singular_name' => _x( 'Lesson', 'Post Type Singular Name', 'text_domain' ),
'menu_name' => __( 'Lessons', 'text_domain' ),
'parent_item_colon' => __( 'Parent Product:', 'text_domain' ),
'all_items' => __( 'All Lessons', 'text_domain' ),
'view_item' => __( 'View Lesson', 'text_domain' ),
'add_new_item' => __( 'Add New Lesson', 'text_domain' ),
'add_new' => __( 'New Lesson', 'text_domain' ),
'edit_item' => __( 'Edit Lesson', 'text_domain' ),
'update_item' => __( 'Update Lesson', 'text_domain' ),
'search_items' => __( 'Search Lessions', 'text_domain' ),
'not_found' => __( 'No Lessons Found', 'text_domain' ),
'not_found_in_trash' => __( 'No Lessons Found in Trash', 'text_domain' ),
);
$args = array(
'label' => __( 'Lessons', 'text_domain' ),
'description' => __( 'Referable Lessons', 'text_domain' ),
'labels' => $labels,
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_in_admin_bar' => true,
'supports' => array('premise-member-access', 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments'),
'menu_position' => 5,
'menu_icon' => null,
'can_export' => true,
'has_archive' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'capability_type' => 'post',
'rewrite' => array('slug' => 'courses'),
);
register_post_type( 'lessons', $args );
// Hook into the 'init' action
}
add_action( 'init', 'rflms_post_type', 0 );
// Register Custom Taxonomy
function custom_taxonomy() {
$labels = array(
'name' => _x( 'Courses', 'Taxonomy General Name', 'text_domain' ),
'singular_name' => _x( 'Course', 'Taxonomy Singular Name', 'text_domain' ),
'menu_name' => __( 'Courses', 'text_domain' ),
'all_items' => __( 'All Courses', 'text_domain' ),
'parent_item' => __( 'Parent Course', 'text_domain' ),
'parent_item_colon' => __( 'Parent Course:', 'text_domain' ),
'new_item_name' => __( 'New Course Name', 'text_domain' ),
'add_new_item' => __( 'Add New Course', 'text_domain' ),
'edit_item' => __( 'Edit Course', 'text_domain' ),
'update_item' => __( 'Update Course', 'text_domain' ),
'separate_items_with_commas' => __( 'Separate Courses with commas', 'text_domain' ),
'search_items' => __( 'Search Courses', 'text_domain' ),
'add_or_remove_items' => __( 'Add or Remove Courses', 'text_domain' ),
'choose_from_most_used' => __( 'Choose from Most Used courses', 'text_domain' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_tagcloud' => false,
'rewrite' => array('slug' => 'courses'),
);
register_taxonomy( 'course', 'lessons', $args );
}
// Hook into the 'init' action
add_action( 'init', 'custom_taxonomy', 0 );

Cambia tu rewrite para añadir la variable de consulta del curso:
'rewrite' => array('slug' => 'cursos/%curso%')
Luego filtra post_type_link
para insertar el curso seleccionado en el enlace permanente:
function wpa_enlace_post_curso( $enlace_post, $id = 0 ){
$post = get_post($id);
if ( is_object( $post ) ){
$terms = wp_get_object_terms( $post->ID, 'curso' );
if( $terms ){
return str_replace( '%curso%' , $terms[0]->slug , $enlace_post );
}
}
return $enlace_post;
}
add_filter( 'post_type_link', 'wpa_enlace_post_curso', 1, 3 );
También hay plugins como Custom Post Type Permalinks que pueden hacer esto por ti.

Gracias, aprecio tu rápida respuesta. Esto tiene mucho sentido. Sin embargo, tengo curiosidad, ¿dónde inserto el filtro post_type_link? ¿Puedo simplemente colocarlo al final de todo el documento?

tienes que limpiar las reescrituras, visita la página de configuración de enlaces permanentes.

también ten en cuenta que probablemente tendrás un conflicto entre una taxonomía y un tipo de publicación que comparten el mismo slug.

Donde estoy ahora es que está generando los permalinks correctamente, pero no se está ejecutando como debería (está generando un soft 404). ¿Alguna recomendación sobre qué puedo hacer para que funcione correctamente? Soy consciente del flush de rewrites de los permalinks. Solo haz clic en 'guardar' y actualiza el archivo (es nginx así que se controla en el archivo nginx.conf)

Esto no funciona para publicaciones traducidas en un sitio multilingüe (por ejemplo, usando WPML).

Esto me muestra la página de inicio en la URL recién creada. Debes usar add_rewrite_rule() como se ve en la respuesta de @Floris para que funcione. También ten en cuenta que las páginas de archivo dejan de funcionar, obtengo 404 para /mi-tipo-de-publicación y para /mi-tipo-de-publicación/mi-categoría

Esto mostrará la publicación sin importar cuál sea el slug del curso. Se muestran en TODOS los slugs de cursos. ¿Cómo limitar esto para que solo se muestre en el slug del curso que está seleccionado y devuelva un 404 en los cursos que no están seleccionados para esa persona?

La solución para mí tuvo tres partes. En mi caso, el tipo de publicación se llama trainings
(formaciones).
- Añadir
'rewrite' => array('slug' => 'trainings/%cat%')
a la funciónregister_post_type
. - Cambiar el slug para que tenga una categoría dinámica.
- "Escuchar" la nueva URL dinámica y cargar la plantilla adecuada.
Así es como cambiar el enlace permanente dinámicamente para un tipo de publicación dado. Añade esto a functions.php
:
function vx_soon_training_post_link( $post_link, $id = 0 ) {
$post = get_post( $id );
if ( is_object( $post ) ) {
$terms = wp_get_object_terms( $post->ID, 'training_cat' );
if ( $terms ) {
return str_replace( '%cat%', $terms[0]->slug, $post_link );
}
}
return $post_link;
}
add_filter( 'post_type_link', 'vx_soon_training_post_link', 1, 3 );
...y así es como cargar la plantilla adecuada en la nueva URL dinámica. Añade esto a functions.php
:
function archive_rewrite_rules() {
add_rewrite_rule(
'^training/(.*)/(.*)/?$',
'index.php?post_type=trainings&name=$matches[2]',
'top'
);
//flush_rewrite_rules(); // usar solo una vez
}
add_action( 'init', 'archive_rewrite_rules' );
¡Eso es todo! Recuerda actualizar los enlaces permanentes guardándolos nuevamente en el backend. O usa la función flush_rewrite_rules()
.

¡Solución encontrada!
Para tener enlaces permanentes jerárquicos para tipos de contenido personalizados, instala el plugin Custom Post Type Permalinks(https://wordpress.org/plugins/custom-post-type-permalinks/).
Actualiza el tipo de contenido registrado. En mi caso el tipo de contenido se llama "Help Center" (Centro de ayuda)
function help_centre_post_type(){
register_post_type('helpcentre', array(
'labels' => array(
'name' => __('Centro de Ayuda'),
'singular_name' => __('Centro de Ayuda'),
'all_items' => __('Ver Artículos'),
'add_new' => __('Nuevo Artículo'),
'add_new_item' => __('Nuevo Centro de Ayuda'),
'edit_item' => __('Editar Centro de Ayuda'),
'view_item' => __('Ver Centro de Ayuda'),
'search_items' => __('Buscar en Centro de Ayuda'),
'no_found' => __('No se encontraron artículos'),
'not_found_in_trash' => __('No hay artículos en la papelera')
),
'public' => true,
'publicly_queryable'=> true,
'show_ui' => true,
'query_var' => true,
'show_in_nav_menus' => false,
'capability_type' => 'page',
'hierarchical' => true,
'rewrite'=> [
'slug' => 'help-center',
"with_front" => false
],
"cptp_permalink_structure" => "/%help_centre_category%/%post_id%-%postname%/",
'menu_position' => 21,
'supports' => array('title','editor', 'thumbnail'),
'has_archive' => true
));
flush_rewrite_rules();
}
add_action('init', 'help_centre_post_type');
Y aquí está la taxonomía registrada
function themes_taxonomy() {
register_taxonomy(
'help_centre_category',
'helpcentre',
array(
'label' => __( 'Categorías' ),
'rewrite'=> [
'slug' => 'help-center',
"with_front" => false
],
"cptp_permalink_structure" => "/%help_centre_category%/",
'hierarchical' => true,
'public' => true,
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'query_var' => true
)
);
}
add_action( 'init', 'themes_taxonomy');
Esta línea hace que tu enlace permanente funcione
"cptp_permalink_structure" => "/%help_centre_category%/%post_id%-%postname%/",
Puedes eliminar %post_id%
y dejar /%help_centre_category%/%postname%/"
No olvides actualizar los enlaces permanentes desde el panel de control.

Necesitas actualizar la línea donde has registrado un tipo de entrada personalizado usando la función register_post_type
.
'rewrite' => array('slug' => 'courses/%cat%')
Para cambiar dinámicamente el enlace permanente del tipo de entrada, debes agregar este código en functions.php
:
function change_link( $post_link, $id = 0 ) {
$post = get_post( $id );
if( $post->post_type == 'courses' )
{
if ( is_object( $post ) ) {
$terms = wp_get_object_terms( $post->ID, array('course') );
if ( $terms ) {
return str_replace( '%cat%', $terms[0]->slug, $post_link );
}
}
}
return $post_link ;
}
add_filter( 'post_type_link', 'change_link', 1, 3 );
//cargar la plantilla en la nueva URL generada, de lo contrario obtendrás errores 404 en la página
function generated_rewrite_rules() {
add_rewrite_rule(
'^courses/(.*)/(.*)/?$',
'index.php?post_type=courses&name=$matches[2]',
'top'
);
}
add_action( 'init', 'generated_rewrite_rules' );
Después de eso, necesitas actualizar las reglas de reescritura de enlaces permanentes. Ve a wp-admin > Ajustes > Enlaces permanentes y actualiza la configuración de enlaces permanentes, luego presiona el botón "Guardar cambios". Esto generará URLs como esta: dominio.ejemplo/courses/[nombre-del-curso{categoría}]/nombre-de-la-lección

Voto negativo - Error 404 tanto en páginas individuales de CPT como en páginas de archivo de CTP

Para cualquiera interesado en la solución, sin tener que manipular código PHP directamente, recomiendo altamente el plugin Permalink Manager Lite de Maciej Bis. Es un salvavidas.
Tiene un mecanismo visual para eliminar o añadir cualquier parte que desees en la URL de los tipos de contenido personalizados basado en 'permastructs':
(Con todo el dolor que implica la simple estructuración de URLs con tipos de contenido personalizados, estábamos a punto de abandonar WP y mudarnos a otro CMS. Pero este plugin junto con ACF y CPTUI o Pods hace que Wordpress sea bastante profesional.)

¡Sí! Después de mucha investigación encontré el plugin 'Custom Permalinks'. Que cumple con mis requisitos en cuanto a URLs personalizadas, por ejemplo:
- para Categorías
- para Entradas
- para Entradas Personalizadas
- para Taxonomías Personalizadas etc.
Como este Post de Tipo Personalizado:

Encontré la respuesta de @chetan-vaghela casi perfecta; en mi caso de uso también quería poder ver una lista de todas las publicaciones de este tipo de contenido como una página de archivo típica (es decir, /cursos/, sin ninguna taxonomía después). Solo tuve que agregar una regla de reescritura adicional de la siguiente manera:
function generated_rewrite_rules() {
add_rewrite_rule(
'^cursos/(.*)/(.*)/?$',
'index.php?post_type=courses&name=$matches[2]',
'top'
);
}
