WordPress permalinks, also known as rewrite rules or pretty links have been a feature since nearly the first version of WordPress. Once something to brag about, today this feature is as standard as features get and not even worth mentioning on the features list.

Having numerous permalinks working out-of-the-box means that 99% of WordPress users don’t have anything to set up and things work for them as soon as they install WP. That’s great; it’s one of the reasons we love WP. However, there are situations where you want to remove or modify default permalinks.

What are “default permalinks”?

To make matters clear we’re not talking about “default permalinks,” we’re talking about default rewrite rules. It may seem like a subtle difference (or even that those two things are the same), but the difference is quite significant. WP generates permalinks based on rewrite rules.

A default WordPress installation has 87 rewrite rules (first code sample below will get you the list). On the other hand, it has only a few permalinks. The root (home page) one, various feed permalinks and those related to the REST API. That’s it. As you add more content, the number of permalinks grows. Some are known and obvious like domain.com/category/my-cat/, and some are less obvious ones like domain.com/category/my-cat/feed/. Rewrite rules are responsible for “generating” and managing those permalinks. While changing a post’s permalink is easy, changing or removing others requires a bit of code.

Why would (or even should) I remove default rewrite rules?

Some argue that it makes WP faster. I don’t agree. Strictly speaking, it probably will speed-up internal URL parsing by a half of a millisecond, but even that assumption is generous. It’s just not worth it speed wise.

Then there’s the argument of just cleaning up. If I don’t need or use something, why would I have it? That’s a valid point. You like to keep things neat.

The reason why we remove default rewrite rules is to keep things clean and “less exposed” when making WordPress powered SaaS apps. Our WP SaaS installations most certainly don’t use feeds, nor categories, nor tags. We also don’t want access to /authors/ or the monthly archives. So it makes sense to remove all those URLs. When someone accesses them, they get a standard 404 page. Nothing breaks; WP handles everything by default.

Let’s get coding

Add this to the theme’s functions.php or somewhere in a plugin.

add_filter( 'rewrite_rules_array', 'show_rewrite_rules' );

function show_rewrite_rules( $rules ) {
  echo nl2br( var_export( $rules, true ) );
  die;
}

Is nothing happening? That’s expected. The rewrite_rules_array filter only runs when rules are changed or being flushed. Open Dashboard – Settings – Permalinks and you’ll see the output. Alternatively, add flush_rewrite_rules() to your code. Every time you make a change to rewrite rules you have to flush them. Either visit Permalinks in admin or use flush_rewrite_rules().

Let’s finally remove some rules. We’ll go with everything related to /author/. This code takes care of it.

add_filter( 'rewrite_rules_array', 'remove_author_rewrite_rules' );

function remove_author_rewrite_rules( $rules ) {
  foreach ( $rules as $rule => $rewrite ) {
    if ( preg_match( '/author\//', $rule ) ) {
      unset( $rules[$rule] );
    }
  }
     
  return $rules;
}

The other, slightly more drastic approach to removing rules is defining what rules to keep, instead of specifying which ones to remove. With that approach, this code removes everything besides the REST API related rewrite rules.

add_filter( 'rewrite_rules_array', 'remove_almost_all_rewrite_rules' );

function remove_almost_all_rewrite_rules( $rules ) {
  foreach ( $rules as $rule => $rewrite ) {
    if ( !preg_match( '/wp-json\//', $rule ) ) {
      unset( $rules[$rule] );
    }
  }
     
  return $rules;
}

Finally, this is the code we use to clean up for WP SaaS installations.

add_filter( 'rewrite_rules_array', 'clean_rewrite_rules' );

function clean_rewrite_rules( $rules ) {
  foreach ( $rules as $rule => $rewrite ) {
    if ( preg_match( '/(feed|attachment|archives|trackback|comment|author|year|search|category|embed|tag|register|page\/)/', $rule ) ) {
      unset( $rules[$rule] );
    }
  }
     
  return $rules;
}

Although not a topic of this article it’s worth mentioning that you can quickly add new rewrite rules, or modify existing ones the same way we’re removing them. Just edit the array, make sure you return it in the filter and flush rules.

Nothing works! I broke everything!

Since rewrite rules use regular expressions writing and debugging them can get tricky, but you can’t break anything. If you’ve added a broken rule or removed too many rules, the first step is to comment out that piece of code or remove it in any other way. The second one is to rebuild permalinks. That’s the step most people miss and it’s crucial. Just open Settings – Permalinks, and that’s it. If you prefer doing it in code run flush_rewrite_rules(). Or you can always use WP Reset to completely reset your whole WP installation, including rewrite rules.

Still doesn’t work? Then it’s cache. Instead of opening site.com/something/ open site.com/something/?rnd=624 to get around browser’s cache.

  1. Thank you soo much. You have saved my life in this moment. I have been searching for a solution in all internet with no success and I had no idea how to solve my problem until now. My problem was that I had a permalink broken and could’n fix it with simply re-saving permalink page. The URL did’n work with the same slug, but when I changed the slug it worked, then returned to the old slug and broke again… But I needed the old slug anyway. So, I went to database and look what was the problem and, there was… an unespected rewrite rule I did’n wanted, related to that slug. So I tried to delete the entire rewrite-rule but it always regenerated again and again in the rewrite_rule field (option_value). So, This is the only place that I could find a solution for that. Sorry for my bad english and thanks again.

  2. Hey, I need to rewrite URL

    mydomain.com/film

    to rewrite

    mydomain.com/best/film

    and this URL

    mydomain.com/movies/film

    to rewrite

    mydomain.com/best/movies

    I am trying to do this but having an error

    function prefix_WP_rewrite_rule() {
        add_rewrite_rule( ‘best/([^/]+)/film’, ‘index.php?WP=$matches[1]&photos=yes’, ‘top’ );
        add_rewrite_rule( ‘film/([^/]+)/movies’, ‘index.php?WP=$matches[1]&videos=yes’, ‘top’ );
    }
     
    add_action( ‘init’, ‘prefix_WP_rewrite_rule’ );

    I have seen the code in this tutorial and implemented it step by step.

  3. i have problem with images urls
    i was using image4io CDN image opimization plugin & it uploads images from medialibrary to thier CDN & Rerwite images url to thier CDN
    After I deactivate the plugin .. image url still pointed to thier CDN not my Site so images goes blank & thier support dosn’t provide my with solution .
    Do you have guide to remve CDN URLS from my images & trun it back in to my original Site url ?


Leave a Reply

Your email address will not be published. Required fields are marked *