Using relative URLs in WordPress

Relative URLs has some benefits: smaller page size (and thus download time) and making the site more portable when you move to another domain. The 2nd problem often happens and it can make your post links broken. Although it can be solved using some backup & restore plugin like BackupBuddy, or using Search and Replace plugin, we better avoid it before it happens. This post will show you how to make your WordPress site support relative URLs.

Note: The topic of relative URLs in WordPress is not new, some people discussed in forum, and there’s also a solution. What I’m trying to do in this post is making a better, more completed solution.

Remove protocol and domain from absolute URLs

Basically, we think about a string replacement: replace home_url() by / from absolute URLs, and we can write a simple function like this:

function rw_remove_root( $url ) {
    $url = str_replace( home_url(), '', $url );
    return '/' . ltrim( $url, '/' );

But do you know that WordPress has a built-in function for this purpose? It’s wp_make_link_relative. The function is in /wp-includes/formatting.php file. Here it is:

function wp_make_link_relative( $link ) {
    return preg_replace( '|https?://[^/]+(/.*)|i', '$1', $link );

Pretty simple. What it does is removing protocol and domain name from the absolute URLs (without using home_url).

Making WordPress relative URLs

Now what we have to do is apply this function to post, category, term, archive, … links. Fortunately, WordPress always uses filters in getting URL functions. All of them are in wp-includes/link-template.php and wp-includes/taxonomy.php files. So, we’ll add wp_make_link_relative filter to those functions. Here’s the the code that you can put in functions.php file of your theme or in your plugin:

add_filter( 'post_link', 'wp_make_link_relative' );       // Normal post link
add_filter( 'post_type_link', 'wp_make_link_relative' );  // Custom post type link
add_filter( 'page_link', 'wp_make_link_relative' );       // Page link
add_filter( 'attachment_link', 'wp_make_link_relative' ); // Attachment link
add_filter( 'get_shortlink', 'wp_make_link_relative' );   // Shortlink

add_filter( 'get_pagenum_link', 'wp_make_link_relative' );          // Paginated link
add_filter( 'get_comments_pagenum_link', 'wp_make_link_relative' ); // Paginated comment link

add_filter( 'term_link', 'wp_make_link_relative' );   // Term link, including category, tag
add_filter( 'search_link', 'wp_make_link_relative' ); // Search link

add_filter( 'post_type_archive_link', 'wp_make_link_relative' ); // Post type archive link

// Date archive link
add_filter( 'day_link', 'wp_make_link_relative' );
add_filter( 'month_link', 'wp_make_link_relative' );
add_filter( 'year_link', 'wp_make_link_relative' );

Or better code with simple improvements:

$filters = array(
    'post_link',       // Normal post link
    'post_type_link',  // Custom post type link
    'page_link',       // Page link
    'attachment_link', // Attachment link
    'get_shortlink',   // Shortlink

    'post_type_archive_link',    // Post type archive link
    'get_pagenum_link',          // Paginated link
    'get_comments_pagenum_link', // Paginated comment link

    'term_link',   // Term link, including category, tag
    'search_link', // Search link

    'day_link',   // Date archive link

foreach ( $filters as $filter ) {
    add_filter( $filter, 'wp_make_link_relative' );

After doing that, whenever you show a link in a theme template file, for ex. using the_permalink() function, the corresponding filters will be applied (in this case: post_link), including our wp_make_link_relative function. That means all URLs in your WordPress site will be changed relative URLs automatically without touching to template files. Enjoy relative URLs!

Relative URLs in feed or sitemap

(Updated on 12/06/2012)

After making this technique live on Deluxe Blog Tips, I found some problems:

  • The URLs in feed are relative, which is not expected. This was reported by Jared.
  • If you’re using WordPress SEO plugin by Yoast, the URLs in sitemap are relative, too, which causes some problems in Google Webmaster Tool.

So, I update the code to make the filters are applied only when we need. I might miss some cases when it doesn’t work, and hope to hear your feedback:

add_action( 'template_redirect', 'rw_relative_urls' );

function rw_relative_urls() {
    // Don't do anything if:
    // - In feed
    // - In sitemap by WordPress SEO plugin
    if ( is_feed() || get_query_var( 'sitemap' ) )

    $filters = array(
    foreach ( $filters as $filter )
        add_filter( $filter, 'wp_make_link_relative' );

I’m using relative URLs in Deluxe Blog Tips, and will update this post if I found any bugs.


  1. Just noticed this awesome comment form, can you write an article on this too ? Between nice article…

    1. Glad you like this comment form. I take the idea from sites and the code is still in test. I want receive more feedback from commenters before writing about it.

  2. One of my clients where asking about this a few months back. Wish I found this back then,


  3. You probably should use site_url() instead of home_url(). I interacted with a core WP developer to get the scoop on the differences between site_url() and home_url() and I document it here in [this answer on][1]. You could also expand this article to discuss things like the global constants that WP has for URLs and paths, as well as the functions that WP has for URLs and paths. For instance, in plugin development, I use plugins_url() function a lot, and it’s quirky. As for global constants, WP has a ton of them such as ABSPATH, WP_CONTENT_DIR, and so on. Last, you may want to add some cautionary notes about using some of these functions and constants with older versions of WordPress. For instance, I think site_url() works in 2.8 but get_site_url() didn’t arrive until 2.9.2. In general, you’ll find some of these functions and constants regarding paths aren’t there until WP 2.8, which is why my plugins that I build require at least WP 2.8 or greater.


  4. Correction in my last post, please. The “get_site_url()” function didn’t arrive until version 3.0, not 2.9.2, and it offers a few extra features to site_url(). (However, I still don’t use it because I find site_url() fits most of my needs with interacting with the site URL.)

    1. Thanks for your comment!

      In terms of replacing domain name, both `site_url` and `home_url` works well. In my understand, the difference comes *only* when you put WP in a folder.

      BTW, I don’t use `home_url` at the end, because WP already has a function for that purpose, that function works in all cases and WP-independent.

  5. Great article! I actually created a plugin, that includes this functionality (among other things) which is based off of the Roots Theme — but since the preg_replace() syntax is a bit different, I’d be interested in seeing if this way works any better. Currently, the relative URL function has an issue when WordPress is installed more than one-level deep – do you know if this does as well? Thanks!

    1. This technique still works then (with my latest method, not the method of using `home_url`). I’ve just looked at your code, and see you’re using `site_url`. Maybe it’s the problem.

  6. Great tip for the url’s – thanks!

    And I juts wanted to give another thumbs up on your comments form layout. LOve to see an article on this, also – it is too sweet. Great work – thanks again. 🙂

  7. Thanks for the useful article!
    But how does it comport with url changing plugins, like wpml?

    1. We should find a filter that the plugin supports, and report to the plugin author if it doesn’t. I’m not sure about WPML 🙁

  8. I used to use relative links, but when people would view articles in web based rss feed readers, the links would stay relative to the reader, e.g. Any suggestions on how to deal with that?

  9. I dont know.. for SEO purposes and to specify a canonical URL, I much prefer the absolute version.

  10. I’m gone to tell my little brother, that he should also pay a quick visit this web site on regular basis to take updated from latest gossip.

  11. Regarding the problem of making the site more portable when you move to another domain, there is another solution that I use all the time to move sites from development URLs to live sites. It’s the WP Migrate DB plugin: It does a global search/replace on the database, changing not just URLs but file paths and string lengths on serialized data.

    1. Thanks for mentioning that plugin. My first choice always is BackupBuddy. The second is Search and Replace. I used it (Search & Replace) several times and it worked nicely. Looks like that the WP Migrate DB can do the migration automatically, which is awesome. I’ll give it a try when I have a chance. Thanks.

  12. I’m a bit confused by the home_url() reference in there – can you explain it? I was expecting it to make home_url references in the template rewrite to “/”, but it isn’t for me it isn’t – Im still getting the domain.

    1. Hi, `home_url()` returns the URL of your homepage, not the domain. So, replacing it with `/` will make the URL relative. What are you confused here?

  13. imho to many hook…
    This should be enough: add_filter( ‘home_url’, ‘wp_make_link_relative’ );

    … it seems to work well

  14. I am using WordPress 3.3.1 and trying to put the following in my functions.php page for my theme (in order to implement the relative links feature). But it does not work.

    add_action(‘template_redirect’, ‘rewrite_relative_urls’);
    function rewrite_relative_urls() {
    echo “Testing template_redirect”; // this part works

    if ( is_feed() || get_query_var( ‘sitemap’ ) )

    add_filter( ‘post_link’, ‘wp_make_link_relative’ ); // Normal post link
    add_filter( ‘post_type_link’, ‘wp_make_link_relative’ ); // Custom post type link

    However, if I do not use add_action hook for template_redirect to call the above function and simply add the following filters, the relative links feature works.

    add_filter( ‘post_link’, ‘wp_make_link_relative’ ); // Normal post link
    add_filter( ‘post_type_link’, ‘wp_make_link_relative’ ); // Custom post type link

    Do you know why?

    1. Cuz u put the add_filter hooks inside of the rewrite function which is wrong. Try this:
      add_action(‘template_redirect’, ‘rewrite_relative_urls’);
      function rewrite_relative_urls() {
      echo “Testing template_redirect”; // this part works

      if ( is_feed() || get_query_var( ‘sitemap’ ) )

      add_filter( ‘post_link’, ‘wp_make_link_relative’ ); // Normal post link
      add_filter( ‘post_type_link’, ‘wp_make_link_relative’ ); // Custom post type link

  15. Hi! Thanks for the useful article! But i cant add filter for the_post_thumbnail. Added in array “the_post_thumbnail”, but this dont work. How remove absolute URL for thumbnail?

  16. I know this post is years old, but is it still valid? I’m running into the https issue of css & uploaded images in the “featured” post not showing because they are showing http instead.

  17. Thank you for this great article.
    It seems the only links remained absolute are `author_link`, and the link used for editing a post, and image links (what are they both called?)

    1. Hi,
      can you please help me I am new to WordPress, where should I put this code? which file? and where on the page exactly?

    2. Hi,
      try to put the code in the functions.php file which is in your theme folder, and where exactly? in anywhere in that file, if doesn’t work search on `?>` in the end of functions file and replace it with the code

  18. can we have any function which can make my all assets files (css,images,icon) path as relative? , i am facing one issue with my recent site, there i have migrated it to SSL (https://), but my site giving me mix content issues due to my featured images are still coming with HTTP://

  19. First of all thanks but I’m adding the code on the theme function.php but nothing happen.

  20. I have another problem. My WordPress only shoes relative URLs and I don’t change anything. I want to use absolute URLs but really don’t know where the failure is 🙁

  21. I dont get it…. How can the function ‘wp_make_link_relative()’ in formatting.php file be called from within functions.php file??? And wat abt the one input parameter that ‘wp_make_link_relative()’ expects? I’m sorry but, i’m a complete noob to php. Please help.

Comments are closed.