Numeric Slugs

|

It’s getting to be the end of 2015, and so I figured I’d update my website theme for the new year. I use MAMP to make a local install of WordPress on my Mac and then build the theme using the most recent version. As of this writing, the most recent version of WordPress is 4.4. However, I found out that in version 4.3, numeric post slugs began appending a “-2” to the slug to prevent possible conflicts with date-based permalinks.

Sadly, this change completely screws up my permalink structure for my portfolio and webcomic sites. Sure, it would be easy enough to add an additional element to the URL such as “http://ellejohara.com/threads/page/001/” where I add “page”, but I don’t really want to do that.

I picked through the source code and found the new lines that do the check for date conflicts. After puzzling through it for an hour or so, I figured out how to work around the check.

In wp-includes/post.php, the lines of code added to check the permalink structure for numbers begins on line 3616. I’ll comment on what the code does line-by-line.


// Prevent new post slugs that could result in URLs that conflict with date archives.
$post = get_post( $post_ID );
// Get the post ID

$conflicts_with_date_archive = false;
// Make a conflict catcher variable we can use for later

if ( 'post' === $post_type && ( ! $post || $post->post_name !== $slug ) && preg_match( '/^[0-9]+$/', $slug ) && $slug_num = intval( $slug ) ) {
// if the type of post is 'post' AND there is either no post id or the post name is not the same as the post slug AND the slug contains numbers AND those numbers can be successfully converted into an integer, then do the following:

$permastructs = array_values( array_filter( explode( '/', get_option( 'permalink_structure' ) ) ) );
// Get the permalink structure and split its parts into an array

$postname_index = array_search( '%postname%', $permastructs );
// Look for the array value '%postname%' and get its matching key

/*
* 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'.
*/
// This is a big one, so I'll break it down a bit

if ( 0 === $postname_index
// if '%postname%' is the only element in the permalink structure

|| // OR

( $postname_index && '%year%' === $permastructs[ $postname_index - 1 ] && 13 > $slug_num )
// there is more than one element in the permalink structure AND '%year%' comes before '%postname%' AND the slug integer is less than 13 (1 - 12)

|| // OR

( $postname_index && '%monthnum%' === $permastructs[ $postname_index - 1 ] && 32 > $slug_num )
// there is more than one element in the permalink structure AND '%monthnum%' comes before '%postname%' AND the slug integer is less than 32 (1 - 31)

) { // THEN

$conflicts_with_date_archive = true;
// set the conflict catcher variable to TRUE

}
}

This $conflicts_with_date_archive variable is then used a few lines later in the if statement that checks bad slugs. If it’s a bad slug, add a 2 to the slug to prevent a possible date-based permalink conflict.

The code clearly states that any integer slug could be interpreted as a date, so it calls it bad and adds the 2. But I figure dates really only need either a two-digit or a four-digit number, one represents days or months, and the other represents the year. So if only two or four-digit numbers are needed for date-based permalinks, then why shut out all numbers?

After line 3619, I added another if statement with a few preg_match rules to look for the number of digits in the slug integer. If it finds a single digit, two digits, or four digits, then it marks the slug as a date conflict and adds the two. If the integer slug is three digits, or five or more digits, there is no conflict and you get the numeric slug you want. Here’s what I did:


if((preg_match('/^\d{1}$/', $slug_num)) || (preg_match('/^\d{2}$/', $slug_num)) || (preg_match('/^\d{4}$/', $slug_num))) {

Don’t forget to add another closing curly bracket after line 3636 or you’ll break PHP.

WordPress seemed to work just fine for me for years and years with three-digit and five-digit slugs, and I’m hoping it will continue to work now that I’ve added this additional if statement. If you plan on using this fix to get numeric slugs working again, I don’t recommend hacking the WordPress source code itself to do it. It would be better to hook the function with a custom one in the functions.php file in your theme, or to make a plugin. Since I’ve never bothered learning how to make WordPress plugins, I don’t have one here to download. Sorry. But hopefully this will spark the imagination of others to do so.

I just wanted my numeric slugs back.