permalinks – Dlaczego posty nigdy nie mogą mieć numeru jako linku?
![permalinks – Dlaczego posty nigdy nie mogą mieć numeru jako linku?](https://oen.pl/wp-content/uploads/2023/09/apple-touch-icon@2.png)
Dlaczego sufiksy są dodawane do (niektórych) numerycznych post-slugów
Posty w WordPressie mogą prawie zawsze zawierać numeryczne linki permalinkowe, z wyjątkiem sytuacji, gdy mogą one kolidować z innym postem, kanałem lub post
archiwum dat typu post lub są w inny sposób zastrzeżone. wp_unique_post_slug()
Funkcja łagodzi te konflikty poprzez dodanie sufiksu.
Potencjalne konflikty daty i archiwum występują, gdy %postname%
spełnia jeden z trzech warunków:
/*
* Potential date clashes are as follows:
*
* - Any integer in the first permastruct position could be a year.
* - An integer between 1 and 12 that follows 'year' conflicts with 'monthnum'.
* - An integer between 1 and 31 that follows 'monthnum' conflicts with 'day'.
*/
Tak więc, podczas korzystania /%postname%/
same w sobie jako struktura permalinków, numeryczne nazwy wpisów zawsze będą skutkować dołączonymi ślimakami, ponieważ WordPress uznaje je za reprezentujące roczne archiwum – jest to jeden z kilku powodów, dla których warto używać bardziej wytrzymałych struktur permalinków.
Można by argumentować, że WordPress nie powinien uwzględniać liczb od 0 do roku założenia bloga, a może nawet setek lub milionów lat na razie. Jednak przy uwzględnianiu takich mało prawdopodobnych scenariuszy kod nie przyjmuje żadnych założeń dotyczących środowiska ani konfiguracji (użytkownik mógłby skonfigurować swój system tak, jakby rok wynosił „1”, lub publikować posty z datą wiele tysięcy lat późniejszą, aby wzmocnić fikcyjną wiedzę), co jest prawdopodobnie bardziej odpowiedzialnym podejściem.
Rozwiązanie
Od wersji 4.3.1 zachowanie WordPressa pozostałoby niezmienione, gdyby „baza” została w jakiś sposób dodana do archiwów postów opartych na dacie, jak to można zrobić w przypadku niestandardowych typów postów. Tak więc jedynym bezpośrednim rozwiązaniem jest użycie czegoś innego niż /%postname%/
dla Twojej struktury permalinków (na przykład statyczny prefiks nie będący liczbą: /blog/%postname%/
. Lub dodając kategorię posta: /%category%/%postname%/
).
Alternatywnie, ręczne dodanie dowolnego znaku niebędącego cyfrą, przyjaznego dla adresu URL, do nazwy każdego wpisu uniemożliwi dodanie sufiksu.
Możliwe obejścia/haki
Wszystkie pozostałe rozwiązania stają się w pewnym sensie „hakerskie”, ponieważ nie wykorzystują już podstawowych zachowań WordPressa do rozwiązania problemu, lecz raczej próbują obejść go, stosując narzędzia w nietypowy i często zawiły sposób.
Na przykład możesz użyć 'wp_unique_post_slug'
filtruj, aby ignorować mało prawdopodobne konflikty:
// Make some "reasonable" assumptions about the dates of this blog's content.
// These assume standard date & time settings for the host.
define( 'REASONABLE_YEAR_ARCHIVE_LOWER', 2003 ); // Unlikely that this blog published content before WP's initial release.
define( 'REASONABLE_YEAR_ARCHIVE_UPPER', 3000 ); // Probably won't publish content after/with the year 3000.
add_filter( 'wp_unique_post_slug', 'wpse_210487_reasonably_unique_post_slug', 10, 6 );
/**
* If WordPress modified a post-slug to avoid conflicts with date archives when
* %postname% is the first permastruct, undo the modification if the slug is an
* "unreasonable" year. NOTE: this is a hack, and has a high potential for
* introducing new bugs, particularly after the year
* REASONABLE_YEAR_ARCHIVE_UPPER.
*/
function wpse_210487_reasonably_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
global $wpdb, $wp_rewrite;
$permastructs = array_values( array_filter( explode( " get_option( 'permalink_structure' ) ) ) );
// Don't re-process the slug if:
if( 'post' !== $post_type // - the item is not a 'post'
|| $original_slug === $slug // - the item's slug was not altered to resolve a conflict
|| 0 !== array_search( '%postname%', $permastructs ) // - the permalink structure does not start with %postname%
|| ! preg_match( '/^[0-9]+$/', $slug ) // - the slug is not strictly numeric
)
return $slug;
// If the original slug conflicted with another post, use the WordPress-altered slug
$check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $original_slug, $post_type, $post_ID ) );
if( $post_name_check )
return $slug;
// If the original slug conflicted with a feed, use the WordPress-altered slug
if ( is_array( $wp_rewrite->feeds ) && in_array( $original_slug, $wp_rewrite->feeds ) )
return $slug;
// If the original slug was otherwise reserved, use the WordPress-altered slug
if( apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $original_slug, $post_type ) )
return $slug;
// Otherwise, if the numeric slug will never reasonably conflict with a year archive, undo WordPress's slug modification
$slug_num = intval( $original_slug );
if( REASONABLE_YEAR_ARCHIVE_LOWER > $slug_num || REASONABLE_YEAR_ARCHIVE_UPPER < $slug_num )
return $original_slug;
return $slug;
}
Proszę zauważyć, że nie testowałem powyższego kodu i stanowczo odradzam jego używanie. Może się zdarzyć, że nawet po zastosowaniu zamierzonego ślimaka, nadal zostanie on przekierowany do archiwum opartego na dacie.
Mogą istnieć również inne (prawdopodobnie również chałupnicze) rozwiązania wykorzystujące Rewrite API.