I want my post-links to look like /%post_id62%_%postname%/ where %post_id62% is the post ID in base62 encoding (e.g. http://example.com/y9Rlf_test/) and my shortlinks to consist of /%post_id62% only (e.g. http://example.com/y9Rlf). This is what i’ve got so far (in my functions.php
) which obviously doesn’t work:
add_action( 'init', 'yoyo_init' );
function yoyo_init() {
add_rewrite_tag( '%post_id62%', '([A-Za-z0-9]+)' );
}
add_action('generate_rewrite_rules','yoyo_generate_rewrite_rules');
function yoyo_generate_rewrite_rules($yoyo_rewrite) {
global $wp_rewrite;
$new_rules['/([0-9A-Za-z]+)/?$'] = 'index.php?p=' .
base622dec($wp_rewrite->preg_index(1)); // DOESNT WORK OF COURSE (executed only once when rewrite_rules are generated)
$wp_rewrite->rules = array_merge($new_rules, $wp_rewrite->rules);
}
add_filter( 'post_link', 'yoyo_post_link', 10, 2 );
function yoyo_post_link( $permalink, $post ) {
if ( false !== strpos( $permalink, '%post_id62%' ) ) {
$post_id62 = dec2base62( $post->ID );
$permalink = str_replace( '%post_id62%', $post_id62, $permalink );
}
return $permalink;
}
add_filter('pre_get_shortlink', 'yoyo_custom_shortlink', 10, 4);
function yoyo_custom_shortlink($false, $post_id, $context, $allow_slugs) {
global $wp_query;
if($post_id or ($context == 'query' and $post_id = $wp_query->get_queried_object_id())) {
return home_url('/' . dec2base62($post_id));
}
return false;
}
function dec2base62($number) {
$digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; $string = ''; while($number > 0) { $string = $digits[$number % 62] . $string; $number = floor($number / 62); }
return $string;
}
function base622dec($string) {
$digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; $number = 0; while(strlen($string) and ($number *= 62 or strlen($string))) { $number += strpos($digits, $string[0]); $string = substr($string, 1); }
return $number;
}
Any idea how to tackle the problem?
Bonus points for avoiding the -N slug suffix when there’s another post with the same title created (which might be avoided actually when setting the link structure to “/%post_id62%_%postname%/” but in order to have the shortlink functionality it should be “/%post_id62%” I guess; cf. Turn off %postname% auto-incrementing?)!
Thanks!
You only made a mistake in the final step, when you convert the base62-encoded ID back to a decimal ID. You should not do this by changing the rewrite rules, as they are only patterns, not actual rules per post.
What you want is take an incoming URL, let WordPress parse it using the rewrite rules, but then before it is passed to the query engine, check for the
post_id62
variable and set the actualp
(post id) variable based on it. You can do this in therequest
filter, which is applied inWP::parse_request()
.However, this will not solve the
postname-N
problem. WordPress will still callwp_unique_post_slug
on thepost_name
field, andpost_name
will not include thepost_id62
part (since the database is independent of the rewrite rules). As Mike suggested in the followup comments to his answer, you should either figure out a way to include thepost_id62
part in thepost_name
field, or (and this might be the better way) ignore the%postname%
part in the URL and just slap a postname-with-stripped-number-suffix string at the end.You will also run into issues with your shortlinks, since they have the same format (any letter or digit) as a page. Is
/banana/
a page with the title “Banana” or a shortlink to the post with ID 34440682410 – which isbanana
in your base-62 encoding?