2

I want to access my post with id 17 like this:

http://localhost/archives/17/moot-bla-foo-ramble

In other words, the id shall decide, everything thereafter may (or may not) be the slug or anything else. Much like these links leading to the same page (many other sites do the same):

I tried to define a rewrite-rule like this near the top of my .htaccess:

RewriteRule ^archives/(\d{1,12})(?:/.*) archives/$1 [NC]

This almost works, i.e. goes to the right page, but get's me a page-not-found then, because wordpress looks at PATH_INFO again (I think) and states $query_string now is string attachment=moot-bla-foo-ramble

I do not want to do a 301 redirect.

My favourite or course, if such thing existed in Permalink Settings:Custom Structure

/archives/%post_id%/%wildcard%

Albeit that would make the 'ramble' mandatory, so even better...

/archives/%post_id%(/%wildcard%)?

wishful thinking, I guess.

3 Answers 3

2

You shouldn't use the htaccess instead you should use the WordPress APIs

e.g.

function custom_rewrite( $wp_rewrite ) {

    $feed_rules = array(
        'archives/(\d+)(?:/.*)+'    =>  'index.php?p='. $wp_rewrite->preg_index(1)
);

    // ( array merge must be done this way, to ensure new rule comes first )
    $wp_rewrite->rules = $feed_rules + $wp_rewrite->rules;
}
// refresh/flush permalinks in the dashboard if this is changed in any way
add_filter( 'generate_rewrite_rules', 'custom_rewrite' );
3
  • 1
    Thank you, great solution! I edit-in the correct Reg-Exp.
    – Frank N
    Apr 10, 2012 at 11:50
  • And just for the record: RewriteRule ^archives/([0-9]+)(?:/.*) index.php?p=$1 [NC] aka _directly writing to the index.php GET-Form works, but gets you a 301 redirect (triggered by WP). Better than nothing...
    – Frank N
    Apr 10, 2012 at 11:52
  • it worked, but it broke my (normal, not in any way enhanced) tag and category urls... :-( Sorry!
    – Frank N
    Apr 12, 2012 at 22:03
1

Essentially the same as @Tom's answer, but using the provided add_rewrite_rule wrapper:

add_action('init','wpse48481_rewrite_rules');
function wpse48481_rewrite_rules(){
    add_rewrite_rule('^archives/([0-9]{1,})/','index.php?p=$matches[1]','top');
}

This will check for urls of the form:

 http://www.yoursite.com/archives/99/something-else

and interpret it as the post/page/cpt with ID =99. Of course the regex can be whatever you like...

9
  • Thank you! Does this wrapper save me (and my theme users) of the costly (around 200ms) resp. one-time-manual flush thing?
    – Frank N
    Apr 10, 2012 at 12:12
  • [0-9]{1,} <=> [0-9]+ :-)
    – Frank N
    Apr 10, 2012 at 12:12
  • re: manual flushing, nope afraid not. Apr 10, 2012 at 12:21
  • Does not work for me. As soon as I go for the actual use case with trailing stuff add_rewrite_rule('^archives/(\d+)(?:/.*)+$','index.php?p=$matches[1]','top'); I get a e404 with a query string of 'somthing-else' (much like my first htaccess attempt). I did ensure the function is called, I did ensure flush. Regardless of (non)use of ^ and $
    – Frank N
    Apr 10, 2012 at 12:29
  • 1
    This is bad practice, generating and adding rewrite rules is expensive, and you're doing it here on every page load. Instead hook into the generate_rewrite_rules action
    – Tom J Nowell
    Apr 10, 2012 at 14:32
0

I am sorry to say, but all this brought me into kneep-deep troubles. Suddenly tag and category urls ceased to work, giving a "Well this is embarrassing" empty search page...

Even a neutral, non-changing callback triggered by flush w/o adding anyrules would break things like * /archives/tag/kiwis * /archives/categories/fruits

Removing it all and saving /wp-admin/options-permalink.php (i.e. numeric settings) fixes it again. Repeatedly. Very verified. Also see this thread at wordpress.org.

Basically, spending a day, I have come up with a very simple hack, that appears to work. adding this in the .htacces, before the wordpress block

RewriteRule ^archives/(\d{1,12})(?:/.*) archives/$1 [NC,L]

adding this in my theme's functions.php. Directly. No hook.

if ( isset($_SERVER["REDIRECT_URL"]) )
    $_SERVER["REQUEST_URI"] = $_SERVER["REDIRECT_URL"];

Yep, pretty dirty, writing to a $_SERVER variable. And voila, all my testcases work ( simple url, ramble-attached url, tags, category, ...) (nb: without the if your very start page ceases to work (never-ending redirect loop)

5
  • Clearly our rewrite rules worked, they just had the incorrect priority/ordering so they took priority over the tag and category rewrite rules. Adjusting the priority of the filter action etc would have corrected the issue (possibly even swapping the order of the array addition operation). You should've come back and made this apparent before spending a day on your own solution
    – Tom J Nowell
    Apr 11, 2012 at 14:41
  • How do I change priority / order? (other than manually fiddling with the array?)
    – Frank N
    Apr 12, 2012 at 22:04
  • well instead of A = B + A, you could try A = A + B when adding the new rules to the old ones. There's also the priority on the add_filter call, the third parameter? You needn't re-order the array, just the order of execution. Monkeyman rewrite rules will tell you more about ordering.
    – Tom J Nowell
    Apr 13, 2012 at 9:03
  • There is also the $position parameter on add_rewrite_rule in stephens answer which is currently set to 'top', perhaps a lower priority would work better? e.g. 'bottom'
    – Tom J Nowell
    Apr 13, 2012 at 9:03
  • I tried A = A + B. No luck :-( I am happy with my (arguably dodgy but lean)solution. Thank you for all your effort.
    – Frank N
    Apr 17, 2012 at 9:45

Your Answer

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

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