Override single WordPress pages with .htaccess

Until recently, Striderweb.com was made up of static HTML files except for the blog sections themselves. After a while, I decided I wanted to run the entire site off of WordPress, but to do that I realized that the existing pages would have issues until I had converted all of them by remaking them inside the WordPress hierarchy. (The “hard” .htm files would conflict with WordPress Pages that have a similar “virtual” location.)

After a bit of tinkering, I figured out that this could be fixed with a small change to the mod_rewrite section that WordPress puts into the site’s .htaccess file. As a happy side effect, this system also allows you to manually cache a particular page, such as if you are suddenly getting hammered by an Instalanche or a Digg link.

Open your site’s .htaccess and you should see the following, which was put there by WordPress:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Change it to this:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
#	RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}/index.htm !-f
RewriteCond %{REQUEST_FILENAME}/index.php !-f
RewriteRule . /index.php [L]
</IfModule>

# BEGIN WordPress
# END WordPress

With this modification to the basic WordPress .htaccess rewrite, you can now put a hard-coded file in a particular place in the hierarchy.

How Does it Work?

For an example, let’s look at this page in a typical WordPress site:

http://example.com/archives/123

With WordPress running the site, there is no actual folder called “archives”, and in turn no actual “123” folder or file. WordPress is creating the pages on the fly as they are called. Normally, if you were to actually put a folder called “archives” in that location, WordPress would hand control over to the actual directory.

We, however, don’t want that. We want WordPress to relinquish control with /archives/123, but not with, say, /archives/122, or even just /archives.

Our new .htaccess code above changes how WordPress handles “real” directories. With the new code, it only gives up control if the directory in question contains a file named either “index.htm” or “index.php

So, to manually override /archives/123, we create an “archives” directory at the root of the site. In “archives”, we create a “123” folder; and inside that, we create either index.htm or index.php that contains the override page.

Note that the base /archive directory, and any other pages or posts within it (e.g. /archives/122), are still controlled as normal by WordPress.

Another part of the reason I did this was that I have a page on this site that is a demonstration of a CSS method, and I wanted the demo page to be an independent page not run by WordPress (specifically, not complicated by the WordPress template).

You can see it in action here:

http://striderweb.com/nerdaphernalia/webcraft/complexspiral/

Note that http://striderweb.com/nerdaphernalia/webcraft/ is still run normally by the WordPress install that runs the rest of Nerdaphernalia. If I wanted to, I could also make sub-pages of the “ComplexSpiral” page that are also run by WordPress.

You will also note that the “ComplexSpiral” page is listed in the Page listing created by WordPress. That is, the WordPress system knows that there’s a page there, even though it’s not running it. How did I do that? Quite simply, actually. I just made a page with the same address within WordPress — a “placeholder” of sorts. It doesn’t matter what’s in the placeholder page1, because we’ll never see it — it’s overridden by the hard-coded page we created. But it creates the entry within the WordPress system and thus we see a link to the page within the normal WordPress page listings.

(And yes, you could use it to override a particular post, too.)

There is one final step, and this is important: Be sure to change the permissions on your .htaccess file so that WordPress doesn’t overwrite it with the defaults.

Enjoy!

1: I generally fill it with: “This text is a placeholder. If you’re reading this, something’s wrong. Please let me know so I can fix it.”
This entry was posted in GUI Goodness, Tha Interweb, Webcraft and tagged , , , . Bookmark the permalink.

19 Responses to Override single WordPress pages with .htaccess

  1. chaoskaizer says:

    brill, good articles. thanks for thr .htaccess tips.

  2. Ben Tremblay says:

    Yes, “brill” covers it. Thanks for spending the extra time to explain … so many really good plugins don’t share their voodoo … this serves as a real good working example, kinda like a tutorial.

    p.s. I just grabbed your pull-quote plugin; it’s really lovely. (You gonna create a plugins category?

  3. Strider says:

    Ben — I’m trying (retroactively in some cases) to keep blog categories fairly broad. (Though I will probably be moving my plugins to a dedicated “WordPress” section instead of “Features”)

    You can, however, pull up a page of just WordPress-related posts by clicking on the WordPress tag at the end of this post — in the “Filed Under” list. Looks kinda like this: WordPress. You can even get an RSS feed by tacking /feed/ to the end of the URL.

    Just one more thing I love about WordPress — great URL structure! 🙂

  4. Ben Tremblay says:

    I think there’s something about the Category/Tag relationship I don’t understand. To my way of thinking, tags should be as though nested beneath category … so (making up an example here) Extension/WordPress should produce a different set than Extenxion/Firefox … I don’t think that happens at the moment.

    I’m rushing right now, so forgive me if this is valueless to you, but it’s interesting:
    There are 30ish top-level categories, each with a number of 2nd level categories, each with a number of 3rd level categories… when I add additional 3rd level categories, often they don’t show up in admin>manage>categories or on
    the site itself, though they are in MySQ”
    Is there a limit” in the [WP-Pro] list

  5. Ben Tremblay says:

    And yaa, that was a typo … my example shudda used Extension in both cases. *sigh*

  6. This is good stuff! I’m having a similar .htaccess problem that maybe somebody here could help me with. I have the standard wordpress stuff shared above in my htaccess file and have also added the following:

    RewriteEngine On
    RewriteRule ^product/([0-9]+)/$ /product.php?sku=$1

    I’m trying to be able to use product/1234 in the url string but still grab the sku number as a GET variable on my static (not controlled by wordpress) product.php page.

    If I delete the wordpress stuff, my rewriterule works perfectly, but of course the rest of the site doesn’t because the wordpress directives are gone. But with the wordpress stuff in place my rewriterule doesn’t work. Any suggestions for me?

  7. Strider says:

    Ben — for my take on tags vs. categories, see this post.

  8. Jason says:

    I want to be able to modifiy the wordpress templates. I was told a while back all you had to do was make a .htaccess file and some information inside that file to be able to modifiy templates inside wordpress dashboard. What code do i need to accomplish this.

  9. Stephen says:

    Jason —

    The method described here completely overwrites a page with a static HTML page. I don’t think you can do it on WordPress.com.

    If you mean modifying the template on an install you’re hosting yourself… just modify the template files!

  10. michael says:

    Hi,

    I have an existing website in a directory with htm files – directory/index.htm
    I have also installed wp in the same directory – directory/index.php

    I would like that the request
    http://www.doamin.com/directory would use the index.htm
    (currently the index.php overrides the index.htm)
    but the wp should still work if I use for example
    http://www.doamin.com/directory/index.php
    or http://www.doamin.com/directory/blog

    I tried your above script but do not get it to work.
    Any help appreciated.
    Michael

  11. Stephen says:

    You might set the server settings so that .htm files take higher precedence than .php files.

    Not sure if WordPress will like that though…

  12. michael says:

    Hi Stephen,
    Thanks for writing back.
    I came up with a “not perfect solution”

    1.change the filename in the wordpress root from index.php to a filename like base.php

    2.I use wordpress >htaccess if you have permalinks enabled:
    change in .htaccess in the line RewriteRule index.php to base.php + make the file not writable, because as soon you add a page wordpress, wordpress rewrites the .htaccess

    results:
    http://www.domain.com -> shows http://www.domain.com/index.htm
    http://www.domain.com/anyPageNameFromWordpress -> brings up wordpress
    then you can navigate inside the wordpress files
    If you have chosen page “home” as your static page that button brings you to shows http://www.domain.com/index.htm – although you can disable the static page choice and activate it when the site is launched in wordpress.

    Hope this helps others
    Michael

  13. Stephen says:

    Michael —

    A better solution: Make the index file into a WordPress template. In WordPress, edit the front page and set its template to that new template. No monkeying with .htaccess is necessary.

    This is how I do it on this site. The front page at http://striderweb.com/ runs off of WordPress, but it’s basically a hard HTML file.

  14. You saved my life =)

  15. Leo Bazán says:

    @Jared Elvidge

    Jared, try adding the “[L]” flag at the end of the line, like this:

    RewriteRule ^product/([0-9]+)/$ /product.php?sku=$1 [L]

    That flag makes that line the last to be executed, only if your pattern matches. In case your pattern doesn’t match, the line is skipped and the WR’s ones will be executed.

    PS: Excuse my English, since it’s not my native language :S

  16. alex says:

    Hi,

    Does this also work for dynamic pages in a subfolder??

    I am a bit stuck with my setup.

    I have WP in my root
    I have a folder Jobs with php files which connects with the DB and do some searches and outputs them.
    -WP
    –jobs
    –other appl.

    In my ideal situation i want to use

    db content

    in jobs

    But also SEO friendly url’s like
    jobs/sector/job-detail
    jobs/sub-sector/search-detail/job-detail

    so now i have an index.php in jobs looking like
    require(‘./../wp-blog-header.php’);
    get_header();

    But i realize WP will return a page not found with jobs, jobs/$1/ jobs/$1/$2 etc

    What should i do??

  17. Pingback: htaccess tricks and tips — Studio404 Web Agency

  18. Pingback: Directory Overriding on Wordpress - Tech Magazine

  19. Varun says:

    Hello Stephen, Wonderful article on htaccess and you describe with example, I am going to try out these on my site, Hope it work fine.

Leave a Reply

Your email address will not be published.