Eliminarea slug-ului din URL-urile postărilor pentru tipuri de postări personalizate
Se pare că toate resursele web bazate pe subiectul eliminării unui slug pentru tipuri de postări personalizate, adică
yourdomain.com/CPT-SLUG/post-name
sunt acum soluții foarte învechite care fac adesea referire la instalări WordPress pre-versiunea 3.5. O soluție comună este să folosești:
'rewrite' => array( 'slug' => false, 'with_front' => false ),
în interiorul funcției tale register_post_type
. Această metodă nu mai funcționează și poate induce în eroare. Așa că întreb comunitatea în Q4 2020...
Care sunt modalitățile moderne și eficiente de a elimina Slug-ul Tipului de Postare din URL-ul unei postări de tip Custom Post Type din argumentul rewrite sau din oricare altă parte?
ACTUALIZARE: Se pare că există mai multe modalități de a forța acest lucru să funcționeze cu regex. În mod specific, răspunsul de la Jan Beck, în cazul în care ești dispus să monitorizezi constant crearea de conținut pentru a te asigura că nu sunt create nume de pagini/postări conflictuale.... Cu toate acestea, sunt convins că aceasta este o slăbiciune majoră în nucleul WordPress care ar trebui gestionată pentru noi. Atât ca opțiune/hook la crearea unui CPT, cât și ca set avansat de opțiuni pentru permalink-uri. Vă rog să susțineți ticket-ul de tracking.
Notă de subsol: Vă rugăm să susțineți acest ticket trac prin urmărire/promovare: https://core.trac.wordpress.org/ticket/34136#ticket

Următorul cod va funcționa, dar trebuie să țineți cont că pot apărea conflicte ușor dacă slug-ul pentru tipul personalizat de postare este același cu un slug de pagină sau postare...
Mai întâi, vom elimina slug-ul din permalink:
function na_remove_slug( $post_link, $post, $leavename ) {
if ( 'events' != $post->post_type || 'publish' != $post->post_status ) {
return $post_link;
}
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
add_filter( 'post_type_link', 'na_remove_slug', 10, 3 );
Doar eliminarea slug-ului nu este suficientă. În acest moment, veți primi o eroare 404 pentru că WordPress se așteaptă ca doar postările și paginile să se comporte astfel. Va trebui să adăugați și următorul cod:
function na_parse_request( $query ) {
if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
if ( ! empty( $query->query['name'] ) ) {
$query->set( 'post_type', array( 'post', 'events', 'page' ) );
}
}
add_action( 'pre_get_posts', 'na_parse_request' );
Doar schimbați "events" cu tipul vostru personalizat de postare și sunteți gata. Poate fi necesar să reîmprospătați permalink-urile.

mersi. Crezi că această soluție este mai bună decât crearea manuală a rescrierilor? Am văzut această soluție și s-ar putea să evite conflictele pe care le-ai menționat?

Cred că aceasta este o soluție automatizată bună dacă ești sigur că nu vei crea conflicte. Nu este o soluție bună dacă o oferi... să zicem unui client care nu este expert în tehnologie.

poți să actualizezi, te rog, cum să folosești acest cod pentru mai multe tipuri de postări

Eșuează cu nginx din cauza condiției 2 != count( $query->query )
. Cu nginx, poți avea $query->query ca array('page' => '', 'name' => '...', 'q' => '...')
. Deci @NateAllen, care este sensul acelei condiții?

Avem nevoie de ceva mai bun decât asta. Suport pentru eliminarea slug-ului integrat, astfel încât să nu putem crea URL-uri conflictuale mai târziu. La fel cum postările și paginile obișnuite își creează URL-urile.

Este doar impresia mea sau acest lucru întrerupe unele tag-uri condiționale WordPress precum is_single() și is_singular()?

Din păcate, această soluție a provocat unele link-uri stricate și blogul meu a încetat să mai afișeze postări, rămânând doar o pagină normală. Vezi mai jos o soluție mai bună de la Matt Keys.

Acest cod presupune că numele post_type
este același cu slug
-ul tipului de postare personalizat, ceea ce nu este neapărat valabil în toate cazurile. Dar în rest, o soluție bună, deși sunt de acord că o soluție nativă din WP ar fi mai bună.

single-{cpt}.php încetează să funcționeze folosind această abordare

Pentru cei care au o problemă cu codul de mai sus, funcționează perfect dacă înlocuiți a doua funcție (function na_parse_request()) cu cea găsită în acest răspuns. Nu uitați să modificați codul cu numele propriu al tipului de postare personalizat.

Am folosit acest cod frumos până când a apărut WP 5.2. După actualizare, acest cod a început să nu mai funcționeze în plugin-ul meu pentru tipuri de postări personalizate și în plugin-ul Advanced Custom Fields, deoarece, cred eu, folosesc aceeași funcție pre_get_posts, așa că în loc de Grupuri Advanced Custom Field, văd postările mele personalizate în acest plugin... De asemenea, nu mai funcționează cu plugin-ul CPT UI - nu se mai pot crea postări noi și nu apar în listă după crearea lor. Vă rog ajutați!!

A funcționat pentru un singur tip de postare. Cum pot folosi codul pentru mai multe tipuri de postări?

Ahh, în sfârșit o soluție - mulțumesc! Mă întrebam de ce primesc brusc erori 404 timp de o oră înainte să realizez că era din cauza acestui 'rewrite' => array( 'slug' => false) :)

Analizând răspunsurile de aici, cred că există loc pentru o soluție mai bună care combină câteva lucruri învățate mai sus și adaugă detectarea automată și prevenirea slug-urilor duplicate pentru articole.
NOTĂ: Asigurați-vă că înlocuiți 'custom_post_type' cu numele propriului CPT în tot exemplul meu de mai jos. Există multe apariții, iar un 'find/replace' este o modalitate ușoară de a le prinde pe toate. Tot acest cod poate fi introdus în functions.php sau într-un plugin.
Pasul 1: Dezactivați rescrierile pentru tipul de postare personalizat setând rewrites la 'false' la înregistrarea postării:
register_post_type( 'custom_post_type',
array(
'rewrite' => false
)
);
Pasul 2: Adăugați manual rescrierile personalizate în partea de jos a rescrierilor WordPress pentru custom_post_type
function custom_post_type_rewrites() {
add_rewrite_rule( '[^/]+/attachment/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'bottom');
add_rewrite_rule( '[^/]+/attachment/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'bottom');
add_rewrite_rule( '[^/]+/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
add_rewrite_rule( '[^/]+/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
add_rewrite_rule( '[^/]+/attachment/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'bottom');
add_rewrite_rule( '[^/]+/attachment/([^/]+)/embed/?$', 'index.php?attachment=$matches[1]&embed=true', 'bottom');
add_rewrite_rule( '([^/]+)/embed/?$', 'index.php?custom_post_type=$matches[1]&embed=true', 'bottom');
add_rewrite_rule( '([^/]+)/trackback/?$', 'index.php?custom_post_type=$matches[1]&tb=1', 'bottom');
add_rewrite_rule( '([^/]+)/page/?([0-9]{1,})/?$', 'index.php?custom_post_type=$matches[1]&paged=$matches[2]', 'bottom');
add_rewrite_rule( '([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?custom_post_type=$matches[1]&cpage=$matches[2]', 'bottom');
add_rewrite_rule( '([^/]+)(?:/([0-9]+))?/?$', 'index.php?custom_post_type=$matches[1]', 'bottom');
add_rewrite_rule( '[^/]+/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'bottom');
add_rewrite_rule( '[^/]+/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'bottom');
add_rewrite_rule( '[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
add_rewrite_rule( '[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
add_rewrite_rule( '[^/]+/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'bottom');
add_rewrite_rule( '[^/]+/([^/]+)/embed/?$', 'index.php?attachment=$matches[1]&embed=true', 'bottom');
}
add_action( 'init', 'custom_post_type_rewrites' );
NOTĂ: În funcție de nevoile dvs., este posibil să doriți să modificați rescrierile de mai sus (dezactivați trackback-uri? feed-uri?, etc.). Acestea reprezintă tipurile 'implicite' de rescrieri care ar fi fost generate dacă nu ați fi dezactivat rescrierile în pasul 1
Pasul 3: Faceți din nou permalink-urile către tipul de postare personalizat 'prietenoase'
function custom_post_type_permalinks( $post_link, $post, $leavename ) {
if ( isset( $post->post_type ) && 'custom_post_type' == $post->post_type ) {
$post_link = home_url( $post->post_name );
}
return $post_link;
}
add_filter( 'post_type_link', 'custom_post_type_permalinks', 10, 3 );
NOTĂ: Puteți opri aici dacă nu vă faceți griji cu privire la faptul că utilizatorii pot crea o postare conflictuală (duplicat) într-un alt tip de postare care va crea o situație în care doar una dintre ele se va încărca atunci când este solicitată pagina.
Pasul 4: Prevenirea slug-urilor duplicate pentru postări
function prevent_slug_duplicates( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
$check_post_types = array(
'post',
'page',
'custom_post_type'
);
if ( ! in_array( $post_type, $check_post_types ) ) {
return $slug;
}
if ( 'custom_post_type' == $post_type ) {
// Salvarea unei postări custom_post_type, verifică duplicate în POST sau PAGE
$post_match = get_page_by_path( $slug, 'OBJECT', 'post' );
$page_match = get_page_by_path( $slug, 'OBJECT', 'page' );
if ( $post_match || $page_match ) {
$slug .= '-duplicate';
}
} else {
// Salvarea unui POST sau PAGE, verifică duplicate în custom_post_type
$custom_post_type_match = get_page_by_path( $slug, 'OBJECT', 'custom_post_type' );
if ( $custom_post_type_match ) {
$slug .= '-duplicate';
}
}
return $slug;
}
add_filter( 'wp_unique_post_slug', 'prevent_slug_duplicates', 10, 6 );
NOTĂ: Acest cod va adăuga șirul '-duplicate' la sfârșitul oricărui slug duplicat. Acest cod nu poate preveni slug-uri duplicate dacă acestea există deja înainte de implementarea acestei soluții. Asigurați-vă că verificați mai întâi dacă există duplicate.
Aș fi bucuros să aud de la alții care încerce această soluție pentru a vedea dacă a funcționat bine și pentru ei.

Am fost optimist în legătură cu această abordare, dar primesc eroare 404 pe postările mele CPT, chiar și după ce am resetat Permalink-urile.

Îmi pare rău că nu a funcționat pentru tine, Garconis. Am discutat cu altcineva despre asta acum ceva timp și și ei aveau probleme pe site-ul lor. Îmi aduc aminte că conta dacă permalink-urile postărilor de blog au un prefix. Pe site-ul pentru care am dezvoltat asta, postările de blog folosesc structura de permalink: /blog/%postname%/. Dacă nu ai un prefix pe postările tale de blog și este acceptabil să ai unul, încearcă și spune-mi cum merge!

Această soluție a funcționat pentru mine. Spre deosebire de alte soluții de pe pagină, nu a stricat paginile normale sau layout-ul blogului și nu a cauzat redirecționări infinite. De asemenea, afișează URL-ul corect în zona "Legătură permanentă" când editez acele pagini CPT. O soluție destul de bună aici, singura problemă este că pagina de arhivă nu funcționează. NU UITAȚI să înlocuiți "custom_post_type" și să reîmprospătați legăturile permanente după aceea.

@MattKeys, setările implicite pentru Legături Permanente au o Structură Personalizată de /%category%/%postname%/
. Când adaug codul tău, slug-urile CPT arată OK (deși le lipsește slash-ul final) ... și verificatorul de conflicte funcționează și el. Dar postările reale rezultă într-o eroare 404.

Funcționează excelent! Totuși, a trebuit să adaug o variabilă de interogare în pasul 2 add_rewrite_tag( "%custom_post_type%", '([^/]+)', "post_type=custom_post_type&name=" );
pentru a vedea paginile CPT în loc de un mesaj de eroare 404

Aceasta este singura soluție care a funcționat pentru mine. A trebuit doar să adaug o bară oblică la sfârșitul lui return $post_link
în pasul 3.

A funcționat bine, dar lipsește bara oblică finală. Te rog actualizează răspunsul pentru a include acest lucru! Un potențial dezavantaj: nu vei mai putea personaliza permalinkul din partea de front-end (de exemplu, când vrei să îl scurtezi în comparație cu titlul).

Această soluție funcționează bine pentru CPT, dar provoacă eroarea 404 pentru toate articolele de pe site-ul meu. Folosesc acest lucru într-un plugin, deci trebuie să funcționeze cu orice structură de permalink posibilă și nu sunt sigur dacă acest lucru este posibil.

Introdu următorul cod în înregistrarea taxonomiei.
'rewrite' => [
'slug' => '/',
'with_front' => false
]
Cel mai important lucru pe care trebuie să-l faci după modificarea codului
După ce ai modificat documentul taxonomiei pentru tipul personalizat de postare, încearcă să mergi la Setări > Legături permanente și salvează din nou setările, altfel vei primi eroarea 404 pagină negăsită.

Chiar funcționează, nu înțeleg cum nimeni nu a observat asta până acum. Desigur, acest lucru poate interfera cu alte pagini dacă au același permalink, dar dacă nu, este o soluție excelentă.

Am încercat asta. Oferă rezultatul dorit pentru linkurile tipului meu de postare personalizată. Totuși, 'prinde' toate slug-urile tipului POST sau PAGINĂ și încearcă să le rezolve ca URL pentru tipul meu de postare personalizată, apoi dă eroare 404. (da, am salvat permalinkurile).

Este posibil să existe același slug pentru o pagină și un tip de postare personalizată, schimbă slug-ul paginii tale și apoi verifică.

Nu funcționează. Returnează eroarea 404 chiar și după actualizarea legăturilor permanente.

@ChristineCooper Trebuie să urmezi acest pas
După ce ai modificat taxonomia tipului tău de postare personalizată, încearcă să mergi la Setări > Legături permanente și salvează din nou setările, altfel vei primi pagina 404 - negăsit.

Așa cum am menționat în ultimul meu comentariu, vei primi o eroare 404 chiar și după ce ai actualizat legăturile permanente. Te rog să încerci singur.

Funcționează perfect, mai ales când citești întregul mesaj, inclusiv partea cu "salvează din nou setările tale". +1

Din nou, chiar și după ce am salvat din nou setările pentru legături permanente, articolele și paginile nu mai funcționează (eroare 404)

Această soluție funcționează pentru eliminarea slug-ului din URL. Dar paginile de arhivă nu mai funcționează.

După cum au menționat și alții, acest lucru funcționează pentru postările CPT în sine. Dar acum provoacă o eroare 404 pentru Paginile obișnuite.

Poate că acest lucru funcționează pentru unii, dar nu și pentru alții din cauza altor plugin-uri care interferează? Adică, nici pentru mine nu funcționează într-un mediu în care WPML cu subdirectoare este configurat: www.mysite.com/en/CPT-item/ returnează 404.

Am încercat să înțeleg acest lucru nu demult și răspunsul scurt din câte știu este nu. Cel puțin nu din argumentul rewrite.
Explicația detaliată devine evidentă dacă analizezi codul actual al funcției register_post_type
în wp-includes/post.php linia 1454:
add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
Poți observa că adaugă prefixul $args->rewrite['slug']
la eticheta de rescriere %$post_type%
. S-ar putea credea "hai să setăm slug-ul la null
atunci", dar dacă te uiți câteva linii mai sus:
if ( empty( $args->rewrite['slug'] ) )
$args->rewrite['slug'] = $post_type;
Se poate observa că funcția mereu așteaptă o valoare pentru slug care să nu fie goală și altfel folosește tipul de postare.

Mulțumesc @JanBeck . Există un motiv major pentru care acest lucru există? De ce să nu modificăm acest fișier core cu o condiție pentru a exclude anumite tipuri de postări din această regulă?

Ar trebui să acorzi răspunsul lui Jan Beck. WordPress are nevoie de slug-ul post_type pentru a direcționa corect cererile. Această regulă previne conflictele de denumiri între paginile native WP (care se afișează fără slug) și orice tipuri de postări personalizate definite. Dacă elimini slug-ul, WordPress nu va ști diferența dintre o pagină numită "picnic" și un eveniment (tip de postare personalizat) numit "picnic".

Rezumat Plugin-uri
Este aproape 2020 și multe dintre aceste răspunsuri nu mai funcționează. Iată un rezumat al opțiunilor actuale:
- Răspunsul lui Matt Keys pare să fie singurul pe drumul cel bun dacă doriți o soluție personalizată. Niciunul dintre plugin-urile pe care le-am găsit nu poate face tot ceea ce este listat aici, în special verificarea duplicatelor. Această abordare pare a fi o oportunitate foarte bună pentru un plugin, dacă cineva ar dori să o preia.
- Permalink Manager Lite
- Cel mai bun dintre plugin-urile gratuite pe care le-am încercat.
- Oferă control complet asupra întregii structuri de permalinkuri pentru Pagini/Articole/CPT și permite ca acestea să fie identice. Interfața grafică este cu mult cea mai bogată în funcționalități.
- Permite suprascrierea completă pentru fiecare post și vă permite să vedeți care ar fi permalinkul original/implicit și să îl resetați la valoarea implicită dacă este necesar.
- Suportă multi-site.
- Nu verifică duplicatele între tipurile de postări, ceea ce este păcat. Dacă o pagină și un CPT au același URL, pagina se încarcă și CPT-ul devine inaccesibil. Fără avertismente sau erori, trebuie să faceți verificări manuale pentru duplicate.
- Toate funcționalitățile legate de taxonomii sunt în versiunea PRO. Notificările pentru upgrade sunt destul de insistente.
- Custom Permalinks
- Versiunea gratuită face multe. Doar permalinkurile pentru taxonomii și suportul premium par să fie reținute pentru versiunea pro.
- Vă permite să modificați întregul permalink pentru orice pagină/articol/CPT individual.
- Suportă multi-site.
- Nu vă permite să modificați structura implicită, așa că tipurile dvs. de postări personalizate vor rămâne de forma exemplu.com/cpt-slug/titlu-postare, dar le puteți modifica individual.
- Nu verifică duplicatele între tipurile de postări, ceea ce este păcat.
- Custom Post Type Permalinks
- Permite utilizatorilor non-developeri să modifice lucrurile care sunt deja ușor de schimbat cu
register_post_type
- Nu vă permite să modificați slug-ul de bază al CPT-ului - doar partea care vine după acesta - deci practic inutil pentru dezvoltatori și pentru problema din această întrebare.
- Permite utilizatorilor non-developeri să modifice lucrurile care sunt deja ușor de schimbat cu
- remove base slug... - neactualizat de câțiva ani... nu-l folosiți.

Pluginul Permalink Manager Lite este cu siguranță cea mai bună soluție: stabil, robust, curat, iar versiunea gratuită vă permite să eliminați baza slug-ului. Și funcționează și cu Polylang! Testat pe WordPress 5.4, cu tema TwentyTwenty, fără alte plugin-uri activate. Funcționează perfect pe Custom Post Type, indiferent dacă ați creat unul ierarhic (cu postări copil și postări nepot). Pentru oricine dorește o soluție curată.

Rezumat excelent. Codul din răspunsul meu rulează de ani de zile pe un site al unui client fără probleme. Un dezavantaj pe care unii l-au menționat în soluția mea este că nu funcționează pe permalink-urile implicite pentru tipul de postare încorporat 'blog' (post). În schimb, trebuie să existe un prefix precum: /blog/%postname%/. Pentru cei care folosesc WordPress ca CMS, s-ar putea să facă deja acest lucru, dar pentru alții acest lucru ar putea fi un obstacol, din păcate.

Ca răspuns la anterioarea mea soluție:
desigur, puteți seta parametrul rewrite
la false
atunci când înregistrați un nou tip de postare și să gestionați manual regulile de rescriere, astfel:
<?php
function wpsx203951_custom_init() {
$post_type = 'event';
$args = (object) array(
'public' => true,
'label' => 'Evenimente',
'rewrite' => false, // întotdeauna setați acest parametru la false
'has_archive' => true
);
register_post_type( $post_type, $args );
// acestea sunt argumentele actuale de rescriere
$args->rewrite = array(
'slug' => 'calendar'
);
// tot ce urmează este preluat din funcția register_post_type
if ( is_admin() || '' != get_option( 'permalink_structure' ) ) {
if ( ! is_array( $args->rewrite ) )
$args->rewrite = array();
if ( empty( $args->rewrite['slug'] ) )
$args->rewrite['slug'] = $post_type;
if ( ! isset( $args->rewrite['with_front'] ) )
$args->rewrite['with_front'] = true;
if ( ! isset( $args->rewrite['pages'] ) )
$args->rewrite['pages'] = true;
if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
$args->rewrite['feeds'] = (bool) $args->has_archive;
if ( ! isset( $args->rewrite['ep_mask'] ) ) {
if ( isset( $args->permalink_epmask ) )
$args->rewrite['ep_mask'] = $args->permalink_epmask;
else
$args->rewrite['ep_mask'] = EP_PERMALINK;
}
if ( $args->hierarchical )
add_rewrite_tag( "%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&pagename=" );
else
add_rewrite_tag( "%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=" );
if ( $args->has_archive ) {
$archive_slug = $args->has_archive === true ? $args->rewrite['slug'] : $args->has_archive;
if ( $args->rewrite['with_front'] )
$archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
else
$archive_slug = $wp_rewrite->root . $archive_slug;
add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
if ( $args->rewrite['feeds'] && $wp_rewrite->feeds ) {
$feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
}
if ( $args->rewrite['pages'] )
add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
}
$permastruct_args = $args->rewrite;
$permastruct_args['feed'] = $permastruct_args['feeds'];
add_permastruct( $post_type, "%$post_type%", $permastruct_args );
}
}
add_action( 'init', 'wpsx203951_custom_init' );
Puteți observa că apelul add_permastruct
nu mai include slug-ul.
Am testat două scenarii:
- Când am creat o pagină cu slug-ul "calendar", acea pagină este suprascrisă de arhiva tipului de postare care folosește același slug "calendar".
- Când am creat o pagină cu slug-ul "my-event" și un eveniment (CPT) cu același slug "my-event", este afișat conținutul tipului de postare personalizat.
- Orice alte pagini nu funcționează. Dacă vă uitați la imaginea de mai sus, devine clar de ce: regula tipului de postare personalizat se va potrivi întotdeauna cu un slug de pagină. Deoarece WordPress nu are cum să identifice dacă este vorba despre o pagină sau un tip de postare personalizat care nu există, va returna eroarea 404. De aceea aveți nevoie de un slug pentru a identifica fie pagina, fie CPT. O soluție posibilă ar fi să interceptați eroarea și să căutați o pagină care ar putea exista similar cu acest răspuns.

Deci dacă scopul este să eliminăm slug-ul pentru CPT-uri, nu am putea denumi CPT-ul cu ceva unic care nu ar intra în conflict, având în vedere că oricum nu va fi vizibil în URL? Sau post-name este posibilul conflict dacă este denumit la fel ca o pagină?

Am actualizat răspunsul meu pentru a arăta că acest lucru de fapt strică toate paginile. Fără un slug, WP va căuta un CPT în loc de o pagină și dacă nu îl găsește, va returna o eroare. Deci de fapt nu este legat de post-name.

Am înțeles. Ar trebui să existe reguli de rescriere care să adauge '-1' la URL-urile viitoare care intră în conflict, la fel ca postările native WP față de pagini. Am creat un ticket trac https://core.trac.wordpress.org/ticket/34136#ticket și aș dori să aflu părerea ta.

Context
Chiar după ce am căutat peste tot, nu am găsit o soluție adecvată pentru eliminarea slug-ului CPT din permalinkuri care să funcționeze efectiv și să fie consistentă cu modul în care WordPress analizează cererile. Se pare că toți ceilalți care caută aceeași soluție se află în aceeași situație ca mine.
După cum s-a dovedit, aceasta este de fapt o soluție în două părți.
- Eliminarea slug-ului CPT din permalinkuri
- Instruirea WordPress-ului cum să găsească postările din noile permalinkuri
Prima parte este destul de simplă și multe răspunsuri existente o au deja corect. Iată cum arată:
// elimină slug-ul CPT din permalinkuri
function remove_cpt_slug( $post_link, $post, $leavename ) {
if ( $post->post_type != 'custom_post_type' ) {
return $post_link;
} else {
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
}
add_filter( 'post_type_link', 'remove_cpt_slug', 10, 3 );
A doua parte este unde lucrurile devin complicate. După rezolvarea primei părți, permalinkurile CPT nu mai au slug-uri CPT. Dar acum problema este că WordPress nu știe cum să găsească postările din acele permalinkuri noi, deoarece tot ce știe este că permalinkurile CPT au slug-uri CPT. Așadar, fără un slug CPT în permalink, nu poate găsi postarea. De aceea, atunci când faci o cerere pentru postările tale în acest moment, primești o eroare 404 not found.
Deci, tot ce trebuie să faci acum este să instruiești WordPress cum să găsească postările tale folosind noile permalinkuri. Dar aceasta este partea în care răspunsurile existente nu funcționează foarte bine. Să ne uităm la câteva dintre aceste răspunsuri, de exemplu:
Funcția de mai jos funcționează destul de bine, dar va funcționa doar dacă structura permalinkurilor este setată pe Numele postării.
function parse_request_remove_cpt_slug( $query ) {
if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
if ( ! empty( $query->query['name'] ) ) {
global $wpdb;
$cpt = $wpdb->get_var("SELECT post_type FROM $wpdb->posts WHERE post_name = '{$query->query['name']}'");
// Adaugă CPT la lista de tipuri de postări pe care WordPress le va include când interoghează pe baza numelui postării.
$query->set( 'post_type', $cpt );
}
}
add_action( 'pre_get_posts', 'parse_request_remove_cpt_slug' );
Funcția de mai jos funcționează bine pentru tipul tău de postare personalizată, indiferent de structura permalinkului, dar va arunca o eroare pentru toate celelalte tipuri de postări.
function rewrite_rule_remove_cpt_slug() {
add_rewrite_rule(
'(.?.+?)(?:/([0-9]+))?/?$',
'index.php?custom_post_type=$matches[1]/$matches[2]&post_type=custom_post_type',
'bottom'
);
}
add_action( 'init', 'rewrite_rule_remove_cpt_slug', 1, 1 );
Există un alt răspuns care ar trebui să funcționeze ca o soluție independentă, dar care ajunge să creeze mai multe probleme decât soluții, cum ar fi erori în postările CPT, precum și în altele. Aceasta necesită modificarea argumentului rewrite în înregistrarea CPT, după cum urmează:
'rewrite' => array( 'slug' => '/', 'with_front' => false )
Până acum, toate răspunsurile existente pe care le-am găsit sunt ca cele de mai sus. Fie funcționează parțial, fie nu mai funcționează. Acest lucru se întâmplă probabil pentru că WordPress nu oferă o modalitate simplă de a elimina slug-ul CPT din permalinkurile tipurilor de postări personalizate și, prin urmare, aceste răspunsuri se bazează fie pe anumite scenarii particulare, fie pe o metodă improvizată.
Răspuns
Iată ce am creat încercând să găsesc o soluție care funcționează în majoritatea, dacă nu în toate, scenariile. Aceasta va elimina corect slug-ul CPT din permalinkurile CPT, precum și va instrui WordPress să găsească postările CPT din acele permalinkuri noi. Nu rescrie regulile în baza de date, așa că nu va trebui să resalvezi structura permalinkurilor. În plus, această soluție este consistentă cu modul în care WordPress analizează cererile pentru a găsi postări din permalinkuri, ceea ce o face o soluție mai acceptabilă.
Asigură-te să înlocuiești custom_post_type
cu numele propriului tip de postare personalizată. Apare o dată în fiecare funcție, deci în total de două ori.
// elimină slug-ul CPT din permalinkuri
function remove_cpt_slug( $post_link, $post, $leavename ) {
if ( $post->post_type != 'custom_post_type' ) {
return $post_link;
} else {
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
return $post_link;
}
}
add_filter( 'post_type_link', 'remove_cpt_slug', 10, 3 );
// instruiește WordPress cum să găsească postările din noile permalinkuri
function parse_request_remove_cpt_slug( $query_vars ) {
// returnează dacă este în panoul de administrare
if ( is_admin() ) {
return $query_vars;
}
// returnează dacă permalinkurile frumoase nu sunt activate
if ( ! get_option( 'permalink_structure' ) ) {
return $query_vars;
}
$cpt = 'custom_post_type';
// stochează valoarea slug-ului postării într-o variabilă
if ( isset( $query_vars['pagename'] ) ) {
$slug = $query_vars['pagename'];
} elseif ( isset( $query_vars['name'] ) ) {
$slug = $query_vars['name'];
} else {
global $wp;
$path = $wp->request;
// folosește calea URL ca slug
if ( $path && strpos( $path, '/' ) === false ) {
$slug = $path;
} else {
$slug = false;
}
}
if ( $slug ) {
$post_match = get_page_by_path( $slug, 'OBJECT', $cpt );
if ( ! is_admin() && $post_match ) {
// elimină orice element de eroare 404 not found din array-ul query_vars deoarece există deja o potrivire în CPT
if ( isset( $query_vars['error'] ) && $query_vars['error'] == 404 ) {
unset( $query_vars['error'] );
}
// elimină elementele inutile din array-ul query_vars original
unset( $query_vars['pagename'] );
// adaugă elementele necesare în array-ul query_vars
$query_vars['post_type'] = $cpt;
$query_vars['name'] = $slug;
$query_vars[$cpt] = $slug; // construiește elementul "cpt=>post_slug"
}
}
return $query_vars;
}
add_filter( 'request', "parse_request_remove_cpt_slug" , 1, 1 );
Considerații:
Această soluție exclude în mod intenționat structura de permalink Simplu din sfera sa, deoarece nu este una dintre structurile de permalink frumoase. Deci, va funcționa cu toate structurile de permalink, cu excepția celei Simple.
Deoarece WordPress nu previne automat crearea de slug-uri duplicate în diferite tipuri de postări, poți întâmpina probleme la accesarea postărilor care au același slug din cauza pierderii unicității în permalinkurile CPT după eliminarea slug-urilor CPT. Acest cod nu include nicio funcționalitate pentru a preveni acest comportament, așa că poți dori să găsești o soluție separată pentru a rezolva această problemă.
În cazul în care există un permalink duplicat, acest cod va da prioritate CPT-ului tău față de altele și, prin urmare, va afișa postarea din CPT-ul tău atunci când este solicitată.

La momentul scrierii, aceasta este cea mai bună soluție. Este simplă și corectă. Logica sa este ușor de înțeles și poate fi personalizată. De fapt, am personalizat această soluție pentru a elimina și taxonomy slugs.

Pentru a preveni crearea de slug-uri duplicate, puteți citi și personaliza codul din "Pasul 4" al răspunsului lui Matt Keys.

Am consolidat acest cod și cel al lui Matt Keys în acest gist, necesită mai multe teste dar pare să funcționeze bine. Practic, am modificat doar -duplicate pentru slug în ceva de genul -1,-2 etc. Cu siguranță există o cale mai bună de a face acest lucru. Ar putea fi util chiar să construiești o interfață mică în jurul ei pentru a seta 'location' la slug-ul CPT dorit. https://gist.github.com/cdsaenz/291d9599e1f20313c3a87edf48233176

și putem face câteva modificări la funcția menționată mai sus:
function na_parse_request( $query ) {
if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
if ( ! empty( $query->query['name'] ) ) {
$query->set( 'post_type', array( 'post', 'events', 'page' ) );
}
}
în:
function na_parse_request( $query ) {
if ( ! $query->is_main_query() || 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
return;
}
if ( ! empty( $query->query['name'] ) ) {
global $wpdb;
$pt = $wpdb->get_var(
"SELECT post_type FROM `{$wpdb->posts}` " .
"WHERE post_name = '{$query->query['name']}'"
);
$query->set( 'post_type', $pt );
}
}
pentru a seta valoarea corectă a post_type.

Pentru cei care citesc acest lucru și au avut probleme cu postările copil (child posts) așa cum am avut și eu, am descoperit că cea mai bună soluție este să adăugați propriile reguli de rescriere (rewrite rules).
Principala problemă pe care o întâmpinam era că WordPress tratează redirecționarea pentru paginile care sunt la 2 niveluri (postări copil) puțin diferit față de cele la 3 niveluri (copil al unei postări copil).
Asta înseamnă că atunci când am o structură ca /tip-post/nume-post/post-copil/, pot folosi /nume-post/post-copil și voi fi redirecționat către varianta cu tipul postului în față. Dar dacă am /tip-post/nume-post/post-copil/post-nepot, nu pot folosi /nume-post/post-copil/post-nepot.
Analizând regulile de rescriere, se pare că WordPress caută alte lucruri în afară de pagename la primul și al doilea nivel (cred că al doilea nivel se potrivește cu atașamente) și apoi face ceva acolo pentru a vă redirecționa către postarea corectă. La trei niveluri adâncime, acest mecanism nu funcționează.
Primul lucru pe care trebuie să-l faceți este să eliminați link-ul tipului de post și pentru postările copil. Această logică ar trebui să fie implementată așa cum se vede în răspunsul lui Nate Allen de mai sus:
$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
Eu am folosit o combinație de condiționale pentru a verifica dacă postarea are copii și alte aspecte pentru a obține permalink-ul corect. Această parte nu este prea complicată și veți găsi exemple de implementare în alte locuri.
Următorul pas este cel în care lucrurile se schimbă față de răspunsul dat. În loc să adăugăm elemente la interogarea principală (care a funcționat pentru postările personalizate și copiii lor, dar nu și pentru descendenții mai îndepărtați), am adăugat o regulă de rescrire care se adaugă la sfârșitul regulilor WordPress, astfel încât dacă pagename nu se potrivește și este pe cale să returneze un 404, va face o ultimă verificare pentru a vedea dacă o pagină din tipul de postare personalizată are același nume, altfel va returna 404.
Iată regula de rescriere pe care am folosit-o, presupunând că 'event' este numele CPT-ului vostru:
function rewrite_rules_for_removing_post_type_slug()
{
add_rewrite_rule(
'(.?.+?)(?:/([0-9]+))?/?$',
'index.php?event=$matches[1]/$matches[2]&post_type=event',
'bottom'
);
}
add_action('init', 'rewrite_rules_for_removing_post_type_slug', 1, 1);
Sper că acest lucru va ajuta pe cineva altcineva, deoarece nu am găsit nicio altă soluție care să abordeze postările copil ale copiilor și eliminarea slug-ului din acestea.

Se pare că există o greșeală de tipar în expresia regulată. Între '(:' este necesar un '?' pentru a o folosi ca submodel necapturant => '(?:'. Al treilea ? pare poziționat greșit, deoarece permite un prim submodel gol. Probabil ar trebui să fie poziționat între ( și :. Fără această greșeală, expresia va fi aceeași cu cea care poate fi găsită pentru tipul de postare încorporat 'page'.

Am avut aceleași probleme aici și se pare că nu există nicio mișcare pe site-ul WordPress. În situația mea particulară, unde pentru articolele individuale de blog era necesară structura /blog/%postname%/, această soluție
https://kellenmace.com/remove-custom-post-type-slug-from-permalinks/
a dus la o grămadă de erori 404
Dar împreună cu această abordare minunată, care nu folosește structura de permalink din backend pentru articolul de blog, în cele din urmă funcționează perfect. https://www.bobz.co/add-blog-prefix-permalink-structure-blog-posts/
Mulțumesc mult.

Am încercat și a funcționat.
Acesta este codul simplu pe care trebuie să îl folosești
register_post_type('wporg_product', array( 'labels' => array( 'name' => 'Portofoliu', 'singular_name' => 'Portofoliu', ), 'menu_icon' => 'dashicons-id', 'rewrite' => array( 'slug' => 'portfolio', 'with_front' => false ), // slug-ul meu personalizat
)
);
După modificarea acestui cod, trebuie să salvezi setările de permalink odată.

Acesta este ceea ce a funcționat pentru mine. Înlocuiește podcast
cu slug-ul tău CPT:
add_action('init', function () {
register_post_type(
'podcast',
[
'rewrite' => false,
]
);
});
add_filter('post_type_link', function ($post_link, $post, $leavename) {
if (isset($post->post_type) && $post->post_type === 'podcast') {
$post_link = home_url($post->post_name);
}
return $post_link;
}, 10, 3);
add_action('init', function () {
add_rewrite_rule('(.+?)/?$', 'index.php?podcast=$matches[1]', 'bottom');
});

Plugin-ul "Remove CPT base" funcționează.

Nu ai nevoie de atât de mult cod hardcodat. Folosește simplu un plugin ușor:
Are opțiuni personalizabile.

Acum înțeleg de ce ai primit voturi negative, acest lucru împiedică rezolvarea normală a linkurilor paginilor. Nu am observat pentru că primeam copii cache ale paginilor existente în ciuda reîmprospătării.

Accesând linkuri către pagini (care nu erau de tipul custom post type) din meniul principal, primeam erori 404, ca și cum pagina nu ar fi existat; asta e tot.

@Walf poți să îmi dai vreun exemplu de URL din cazul tău? (poți să ascunzi numele domeniului dacă dorești, am nevoie doar de un exemplu) mulțumesc, voi actualiza
