My permalinks is in the format domain.com/post-id/post-slug

I notice this is a great choice for permalinks as I can share articles with a short URL like domain.com/123

But when I go to this short url, should it not redirect to show the full URL, becuase in the adress bar its only showing domain.com/123

Any setting to do to update the URL to the actual, without putting any additional load or the server.

UPDATE: My requirement is not to get a shortlink. Rather to convert an URL fragment to the full URL.

For eg: If I type domain.com/123/wrong-slug it gets corrected to domain.com/123/correct-slug but if I type domain.com/123 it doesn't get corrected to domain.com/123/post-slug

  • How does it currently redirect to the proper url when you use domain.com/123/wrong-slug? Do you have a rewrite rule in .htaccess? Does it redirect to the full url if you use a trailing slash? domain.com/123
    – iyrin
    Jan 10, 2014 at 17:11

4 Answers 4



I think the reason why

a) domain.com/123

is not redirected back to

b) domain.com/123/post-slug

with the /%post_id%/%postname%/ permalinks settings, is that the matched rule is:

[matched_rule] => ([0-9]+)(/[0-9]+)?/?$

You can get that information from the global $wp object.

There are other useful informations in $wpavailable after the wp action:

Example (post): domain.com/123/post-slug/

[query_vars] => Array
        [p] => 123
        [page] => 
        [name] => post-slug

[query_string] => p=123&name=post-slug
[request] => 123/post-slug
[matched_rule] => ([0-9]+)/([^/]+)(/[0-9]+)?/?$
[matched_query] => p=123&name=post-slug&page=
[did_permalink] => 1

Example (post): domain.com/123/:

[query_vars] => Array
        [p] => 123
        [page] => 
[query_string] => p=123
[request] => 123
[matched_rule] => ([0-9]+)(/[0-9]+)?/?$
[matched_query] => p=123&page=
[did_permalink] => 1

Example (page): domain.com/hello-world/:

[query_vars] => Array
        [page] => 
        [pagename] => hello-world

[query_string] => pagename=hello-world
[request] => hello-world
[matched_rule] => (.?.+?)(/[0-9]+)?/?$
[matched_query] => pagename=hello-world&page=
[did_permalink] => 1

Redirect example:

Here's an example how to redirect from a) to b) using information from the global $wp object:

add_action( 'wp', function(){
    global $wp;
    if( is_numeric( $wp->request ) && empty( $wp->query_vars['page'] ) )
        wp_redirect( get_permalink( absint( $wp->request ) ), 301 );

i.e. we redirect when the page query varaible is not set and the request is numeric.

ps: I just want to mention that this is using the wp action, that is fired rather late, but before the template_redirect action, allowing the redirect possible.

I also tried to come up with an example that is not using the $_SERVER variable ;-)

Hope this helps.

  • In your redirect example there's an error: you are checking for ! isset($wp->query_vars['page']) but $wp->query_vars['page'] is set, but it's NULL. You should add || empty($wp->query_vars['page']) inside if condition.
    – gmazzap
    Jan 12, 2014 at 16:41
  • @G.M. thanks for spotting out that oversight of mine. But I think we can just use empty() (some tests here on codepad.org/W1hGPiKY ). I updated the answer. One should keep in mind that the string "0" is considered empty by the empty() function. So instead one might use ! isset( $wp->query_vars['page'] ) || 0 === mb_strlen( $wp->query_vars['page'] ).
    – birgire
    Jan 12, 2014 at 18:08
  • Worked like a charm. So I can use it without any worry right? Like any issue may not crop up. Just wanted a confirmation from your side @birgire Jan 13, 2014 at 13:11
  • Great - worked on my install as well. You should, as with any code snippet, test it well before you use it.
    – birgire
    Jan 13, 2014 at 14:06

The shortlink of a WordPress post is on default domain.com/?p=30, not the Id after the domain. If you like a permalink to the ID as shortlink for each post, then is this possible via a plugin.

The follow source is a example.

add_filter('get_shortlink', 'fb_custom_shortlink_filter');
function fb_custom_shortlink_filter() {
    global $post;

    return get_site_url() . '/fb/' . $post->ID;

enter image description here

But if you will use the page in the front end with this new short url, is a rewrite important. Below a solution for php and a enhancement in the htaccess.

Add the source in a plugin and add this to the front end or add in the theme file index.php. The source check the value token from the url. This is only possible ,if you enhance the url via mor_rewrite modul in the .htaccess, see below.

if ( ! empty( $_GET['token'] ) ) {
  $id = strip_tags( $_GET['token'] );
  if ( is_numeric( $id ) ) {
    header( $_SERVER['SERVER_PROTOCOL'].' 301 Moved Permanently' );
    header( 'Location: ' . get_site_url() . '?p=' . $id );

header( $_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found' );
header( 'Status:404' );
die( '404 Not Found' )

The rewrite inside the .htaccess

  RewriteEngine on
  RewriteCond   %{REQUEST_FILENAME} !-d
  RewriteCond   %{REQUEST_FILENAME} !-f
  RewriteRule   (.*) index.php?token=$1 [QSA,L]

This is the closest I got. It makes URLs like what you wanted work: domain.com/123

// refresh/flush permalinks in the dashboard if this is changed in any way
add_filter( 'generate_rewrite_rules', 'create_post_id_url' );
function create_post_id_url( $wp_rewrite ) {
    $feed_rules = array(
        '(\d+)' => 'index.php?p='.$wp_rewrite->preg_index(1)
    $wp_rewrite->rules = $feed_rules + $wp_rewrite->rules;

Add this anywhere (e.g. in functions.php), go to Settings > Permalinks and then Save.

The only issue with this approach is that the the user will stay on domain.com/123 and won't be redirected to the canonical version (domain.com/123/post-name). It's not really much of an issue since you already have a canonical link in the <head> of the website, so it's not an issue for search engines. It could actually be considered an advantage since the user doesn't have to wait for a redirect.

The alternative would be just using links like domain.com/?p=123. They are only 3 characters longer and don't add any load on the server — they already work.

In the end, why do you even need short urls? Twitter automatically shortens all URLs, I do not see any need to do it nowadays, they just impair the readability of URLs.


You can use the following htaccess rule for redirecting domain.com/post-id to domain.com/post-id/post-slug.

RedirectMatch 301 ^/(\d+)$ http://domain.com/?p=$1

Put this rule on top of the WordPress's default rules.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.