Adaugă baza categoriei în URL pentru tipuri de postări și taxonomii personalizate
Construiesc un sistem de tip LMS în WordPress, controlat prin Custom Post Types
.
Tipul de postare se numește Lessons
(cu un slug de courses
) și are o taxonomie personalizată
(categorie) numită courses
.
Structura URL-ului domeniului arată acum așa:
domain.example/courses/lesson-name
.
Vreau să devină:
domain.example/courses/[course-name{category}]/lesson-name
sau mai exact:
/[cpt]/%category%/%postname%/
Iată plugin-ul pe care l-am scris și care controlează acum CPT
-urile.
function rflms_post_type() {
$labels = array(
'name' => _x( 'Lecții', 'Post Type General Name', 'text_domain' ),
'singular_name' => _x( 'Lecție', 'Post Type Singular Name', 'text_domain' ),
'menu_name' => __( 'Lecții', 'text_domain' ),
'parent_item_colon' => __( 'Produs părinte:', 'text_domain' ),
'all_items' => __( 'Toate lecțiile', 'text_domain' ),
'view_item' => __( 'Vezi lecția', 'text_domain' ),
'add_new_item' => __( 'Adaugă lecție nouă', 'text_domain' ),
'add_new' => __( 'Lecție nouă', 'text_domain' ),
'edit_item' => __( 'Editează lecția', 'text_domain' ),
'update_item' => __( 'Actualizează lecția', 'text_domain' ),
'search_items' => __( 'Caută lecții', 'text_domain' ),
'not_found' => __( 'Nu s-au găsit lecții', 'text_domain' ),
'not_found_in_trash' => __( 'Nu s-au găsit lecții în coșul de gunoi', 'text_domain' ),
);
$args = array(
'label' => __( 'Lecții', 'text_domain' ),
'description' => __( 'Lecții referibile', '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 );
// Se conectează la acțiunea 'init'
}
add_action( 'init', 'rflms_post_type', 0 );
// Înregistrează Taxonomie Personalizată
function custom_taxonomy() {
$labels = array(
'name' => _x( 'Cursuri', 'Taxonomy General Name', 'text_domain' ),
'singular_name' => _x( 'Curs', 'Taxonomy Singular Name', 'text_domain' ),
'menu_name' => __( 'Cursuri', 'text_domain' ),
'all_items' => __( 'Toate cursurile', 'text_domain' ),
'parent_item' => __( 'Curs părinte', 'text_domain' ),
'parent_item_colon' => __( 'Curs părinte:', 'text_domain' ),
'new_item_name' => __( 'Nume nou curs', 'text_domain' ),
'add_new_item' => __( 'Adaugă curs nou', 'text_domain' ),
'edit_item' => __( 'Editează cursul', 'text_domain' ),
'update_item' => __( 'Actualizează cursul', 'text_domain' ),
'separate_items_with_commas' => __( 'Separă cursurile cu virgule', 'text_domain' ),
'search_items' => __( 'Caută cursuri', 'text_domain' ),
'add_or_remove_items' => __( 'Adaugă sau șterge cursuri', 'text_domain' ),
'choose_from_most_used' => __( 'Alege dintre cele mai folosite cursuri', '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 );
}
// Se conectează la acțiunea 'init'
add_action( 'init', 'custom_taxonomy', 0 );

Modifică regula de rescriere pentru a adăuga variabila de interogare a cursului:
'rewrite' => array('slug' => 'courses/%course%')
Apoi filtrează post_type_link
pentru a insera cursul selectat în legătura permanentă:
function wpa_course_post_link( $post_link, $id = 0 ){
$post = get_post($id);
if ( is_object( $post ) ){
$terms = wp_get_object_terms( $post->ID, 'course' );
if( $terms ){
return str_replace( '%course%' , $terms[0]->slug , $post_link );
}
}
return $post_link;
}
add_filter( 'post_type_link', 'wpa_course_post_link', 1, 3 );
Există și plugin-uri precum Custom Post Type Permalinks care pot face asta pentru tine.

Mulțumesc, apreciez răspunsul rapid. Are sens complet. Sunt curios totuși, unde inserez filtrul post_type_link? Pot să-l pun pur și simplu la sfârșitul întregului document?

trebuie să resetezi regulile de rescriere, vizitează pagina de setări pentru permalink-uri.

de asemenea, rețineți că este posibil să aveți o conflict între o taxonomie și un tip de postare care folosesc același slug.

Situația actuală este că permalinkurile sunt generate corect, dar nu se execută cum trebuie (se întâmplă un soft 404). Aveți recomandări pentru a rezolva această problemă? Sunt conștient de necesitatea de a reseta rewrite-urile pentru permalinkuri. Doar apăsați 'salvare' și se actualizează fișierul (folosim nginx, deci este controlat în fișierul nginx.conf)

Această soluție nu funcționează pentru postările traduse pe un site multilingv (de exemplu folosind WPML).

Pentru mine afișează pagina principală la URL-ul nou creat. Trebuie să folosești add_rewrite_rule() cum se vede în răspunsul lui @Floris pentru a funcționa. De asemenea, reține că paginile de arhivă nu mai funcționează, primesc eroare 404 pentru /my-post-type și pentru /my-post-type/my-category

Aceasta va afișa postul indiferent de slug-ul cursului. Le afișează pe TOATE slug-urile de cursuri. Cum pot limita acest lucru pentru a afișa doar pe slug-ul cursului care este selectat și să returneze eroare 404 pentru cursurile care nu sunt selectate pentru acea persoană?

Soluția mea a avut trei părți. În cazul meu, tipul de postare se numește trainings
.
- Adaugă
'rewrite' => array('slug' => 'trainings/%cat%')
la funcțiaregister_post_type
. - Modifică slug-ul pentru a avea o categorie dinamică.
- "Ascultă" noul URL dinamic și încarcă template-ul corespunzător.
Iată cum poți schimba permalink-ul dinamic pentru un anumit tip de postare. Adaugă în 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 );
...și iată cum poți încărca template-ul corespunzător pe noul URL dinamic. Adaugă în functions.php
:
function archive_rewrite_rules() {
add_rewrite_rule(
'^training/(.*)/(.*)/?$',
'index.php?post_type=trainings&name=$matches[2]',
'top'
);
//flush_rewrite_rules(); // folosește doar o singură dată
}
add_action( 'init', 'archive_rewrite_rules' );
Gata! Nu uita să reîncarci permalink-urile salvându-le din nou în backend. Sau folosește funcția flush_rewrite_rules()
.

Am găsit soluția!
Pentru a avea permalink-uri ierarhice pentru tipul de postare personalizat, instalați plugin-ul Custom Post Type Permalinks(https://wordpress.org/plugins/custom-post-type-permalinks/).
Actualizați tipul de postare înregistrat. Eu am tipul de postare numit "help center"
function help_centre_post_type(){
register_post_type('helpcentre', array(
'labels' => array(
'name' => __('Centru de Ajutor'),
'singular_name' => __('Centru de Ajutor'),
'all_items' => __('Vezi Postările'),
'add_new' => __('Postare Nouă'),
'add_new_item' => __('Centru de Ajutor Nou'),
'edit_item' => __('Editează Centru de Ajutor'),
'view_item' => __('Vezi Centru de Ajutor'),
'search_items' => __('Caută în Centru de Ajutor'),
'no_found' => __('Nu s-a găsit nicio postare în Centru de Ajutor'),
'not_found_in_trash' => __('Nu există postări în Centru de Ajutor la Gunoi')
),
'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');
Și aici este taxonomia înregistrată
function themes_taxonomy() {
register_taxonomy(
'help_centre_category',
'helpcentre',
array(
'label' => __( 'Categorii' ),
'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');
Această linie face ca permalink-ul tău să funcționeze
"cptp_permalink_structure" => "/%help_centre_category%/%post_id%-%postname%/",
poți elimina %post_id%
și poți păstra /%help_centre_category%/%postname%/"
Nu uita să reîncarci permalink-urile din panoul de administrare.

Trebuie să actualizezi linia unde ai înregistrat un tip de postare personalizat folosind funcția register_post_type
.
'rewrite' => array('slug' => 'courses/%cat%')
Pentru a schimba dinamic permalink-ul tipului de postare, trebuie să adaugi acest cod în 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 );
// încarcă template-ul pe noul URL generat, altfel vei primi eroarea 404
function generated_rewrite_rules() {
add_rewrite_rule(
'^courses/(.*)/(.*)/?$',
'index.php?post_type=courses&name=$matches[2]',
'top'
);
}
add_action( 'init', 'generated_rewrite_rules' );
După aceea, trebuie să resetezi permalink-urile. Mergi în wp-admin > Setări > Permalinkuri, actualizează setările de permalink și apasă butonul "Salvează modificările". Acest lucru va returna URL-uri de genul: domain.example/courses/[nume-curs{categorie}]/nume-lecție

Pentru cei interesați de soluție, fără a fi nevoie să vă jucați cu cod PHP brut, recomand cu mare încredere plugin-ul Permalink Manager Lite de Maciej Bis. Este un adevărat salvator.
Are un mecanism vizual pentru a elimina sau adăuga orice parte doriți în URL-ul tipului de postare personalizat, bazat pe 'permastructs':
(Cu toată durimea implicată în simpla structurare a URL-urilor pentru tipurile de postări personalizate, eram pe punctul de a renunța la WP și de a trece la un alt CMS. Dar acest plugin, împreună cu ACF și CPTUI sau Pods, face WordPress destul de profesionist.)

Da! După multă cercetare am găsit plugin-ul 'Custom Permalinks'. Care îmi îndeplinește cerința în legătură cu URL-uri personalizate, de exemplu:
- pentru Categorii
- pentru Postări
- pentru Postări Personalizate
- pentru Taxonomii Personalizate etc.
Ca acest Post Type Personalizat - Postare:

Am găsit răspunsul lui @chetan-vaghela aproape perfect; în cazul meu de utilizare, am vrut să pot vedea și o listă cu toate articolele de acest tip de postare, ca pe o pagină de arhivă tipică (de exemplu /cursuri/, fără nicio taxonomie după aceasta). A trebuit doar să adaug o regulă suplimentară de rescriere, după cum urmează:
function generated_rewrite_rules() {
add_rewrite_rule(
'^cursuri/(.*)/(.*)/?$',
'index.php?post_type=cursuri&name=$matches[2]',
'top'
);
}
