Pretty Login URL: a Simple Rewrite API Plugin Example

A few days ago, the fine folks from DigWP have published a .htaccess trick to enable logging in from yoursite.com/login instead of yoursite.com/wp-login.php.

Their trick is perfectly valid, yet improvable: it requires editing of the .htaccess, a file you don't want noobs to mess with. So my thoughts were: "OK, that's nice and everything, but a simple plugin would be cleaner, easier for beginners, and more portable". Let's do this?

Rewrite API to the rescue

There's an API in WordPress that's exactly designed to create rewrite rules in a more convenient and dynamic way than having to play with the .htaccess file: the Rewrite API.

The Rewrite API is the part of the WordPress engine that handles all the internal URL rewriting, to have neat stuff like yoursite.com/2011/01/happy-new-year/ instead of yoursite.com/index.php?p=1337. In the admin area, the Permalink Settings that allow you to specify your Pretty Permalink structure (for instance /%year%/%month%/%postname%/) leverage that API.

The original .htaccess trick is simply to rewrite /login to /wp-login.php, or, in plain English: "if someone requests the URL 'login', then show them the content of wp-login.php". The bit to add to your .htaccess is:

  1. RewriteRule ^login$ http://yoursite.com/wp-login.php [NC,L]

There's a simple function in the Rewrite API which job is exactly to create this kind of rewrite rules: add_rewrite_rule()

Create a rule with add_rewrite_rule()

This function, to be found in wp-includes/rewrite.php, has the following syntax and parameters: add_rewrite_rule( $regex, $redirect, $after ) where

  • $regex is a string that contains the Regular Expression (or RegEx) to match requests
  • $redirect is a string for the location to redirect to
  • the optional $after specifies where to add the rule in the list: 'bottom' (default) if you want your RewriteRule to be matched after everything has failed, or 'top' if you want it to have greater priority and eventually supersede potentially conflicting rules (for instance if you have a page titled "Login")

So, basically, all it takes to programatically create the rewrite rule for our Pretty Login URL plugin is the following snippet:

  1. // Create new rewrite rule
  2. add_action( 'init', 'wp_ozh_plu_rewrite' );
  3. function wp_ozh_plu_rewrite() {
  4.     add_rewrite_rule( 'login/?$', 'wp-login.php', 'top' );
  5. }

The regexp used here will match 'login', 'login/' but not 'login/somethingelse'.

Complete plugin: Pretty Login URL

There's a little catch with rewrite rules in the Rewrite API: for performance reasons, they are not generated every single time WordPress instantiates and displays a page. For this reason, when you create or deregister a rewrite rule, you need to "flush" the list to force a refresh. Therefore, the complete plugin will monitor activation and deactivation to make sure the list is flushed when appropriate

  1. <?php
  2. /*
  3. Plugin Name: Ozh' Pretty Login URL
  4. Plugin URI: http://planetozh.com/blog/?s=pretty+login+url
  5. Description: Pretty Login URL
  6. Version: 0.1
  7. Author: Ozh
  8. Author URI: http://ozh.org/
  9. */
  10.  
  11. // Add rewrite rule and flush on plugin activation
  12. register_activation_hook( __FILE__, 'wp_ozh_plu_activate' );
  13. function wp_ozh_plu_activate() {
  14.     wp_ozh_plu_rewrite();
  15.     flush_rewrite_rules();
  16. }
  17.  
  18. // Flush on plugin deactivation
  19. register_deactivation_hook( __FILE__, 'wp_ozh_plu_deactivate' );
  20. function wp_ozh_plu_deactivate() {
  21.     flush_rewrite_rules();
  22. }
  23.  
  24. // Create new rewrite rule
  25. add_action( 'init', 'wp_ozh_plu_rewrite' );
  26. function wp_ozh_plu_rewrite() {
  27.     add_rewrite_rule( 'login/?$', 'wp-login.php', 'top' );
  28. }
  29. ?>

Also available as a regular downloadable plugin from wordpress.org.

And that's it. You like?

That's probably the most simple and bare bones example of use of the Rewrite API you can think of, and this API contains a lot more powerful functions to create permalink structures, custom feeds and funky rewrite tricks.

If you liked this article, hey, I have some news for you: my upcoming book Professional WordPress Plugin Development will have a whole chapter on the Rewrite API, full of hands-on detailed examples and real life cases. Buy it now! ;)

39 comments

  1. Eric

    Fantastic tutorial, and it does a fantastic job of incorporating the activation/deactivation hooks as well (which is the key point glossed over in most other examples … sadly including my own).

    Yet another reason I'm looking forward to reading the advanced plug-in dev book!

  2. Craig

    Ozh,
    This is for a site install in the root directory, correct? I installed my blog in a sub-folder of the root as suggested in a WP security article. Would the code have to be altered to point at the wp-login file which is now one folder removed from the root?

  3. Ozh

    Craig » This works fine either with WP installed normally at the root on in a subdir, but it probably won't work (untested) if you can access the site on its root (yoursite.com/) while having WP installed in yoursite.com/wordpress/ as explained here. In such a case, the rewrite rule would probably be add_rewrite_rule( 'login/?$', '/wordpress/wp-login.php', 'top' ); but, again, untested.

  4. MadtownLems

    Tested in multisite without sending people to the root blog's login page? :)

  5. thompson

    Hey Ozh, Is it possible to set up a different permalink structures for a given post type? For example, my permalink structure for posts is %postname%, which I want to keep. But for my 'recipe' custom post type, I'd prefer to use /%postname%/%post-id%.

  6. Michael Fields

    Thanks for writing this up. Honestly, it's one of the parts of WordPress I have little/no experience with. I'll usually jump straight into .htaccess to accomplish similar things on a per-project basis. Actually understanding the Rewrite API would allow me to create portable rewrites which would be awesome. Can't wait for the book to really dig into this topic!

  7. Adam W. Warner

    Ozh, this is really great, thank you so much for turning this into a simple plugin!

  8. Chris Coyier

    Excellent. Thanks for taking this further. I'll update the original article.

  9. geminorum

    how about adding wp-signup.php too?

  10. Ozh

    geminorum » now you should be able to figure that out, right? Right?

  11. Travis

    Ozh, I'm assuming that adding the following after line 27 should accomplish the same for /admin and /wp-admin.php, yes? I tried it, but didn't achieve the desired result. Any suggestions?

    1. add_rewrite_rule( 'admin/?$', 'wp-admin.php', 'top' );
  12. Jamal Mohamed

    I don't know if its misfortune, voodoo, or anything in that company, but this seems not to work on WP multi-site installations.

    It works fine on single WordPress sites, but on MS it throws horrible 404 error whenever I try to access

    1. domain.ext/login/

    or

    1. sub.domain.ext/login/

    or even

    1. domain.ext/site2/login/

    I just wanted to know if its the same for everyone or just me.

  13. Pete

    Yes, I like! Thanks :)

  14. iMp

    I also want to know just like Travis

  15. Ozh

    iMp & Travis » there is no "wp-admin.php" file. It's either "wp-login.php" or "wp-admin/index.php". Note that sending to the login form or the admin area is exactly the same: if logged, user sent to the login form is redirected instead to the admin area ; a user sent to the admin area is redirected to the login form is not logged.

  16. Travis

    Well, don't I feel silly!

    Thanks for the followup comment, Ozh.

  17. Stacy

    @ Jamal Mohamad, it doesn't work for my MS install either.

  18. D.K.

    This should be a core feature, so I've added it to the WordPress ideas.

    If you agree vote for it on WordPress.org.

  19. troy

    What would I have to do to get it to work in an instance where WordPress is installed in a sub folder (http://example.com/wpinstall/) but would still want to login from the root (http://example.com/login)?

  20. Troy

    Nevermind, I seem to have done it by adding the directory before /wp-login.php in .htaccess for the root alone.

  21. Ozh

    D.K. » This won't ever be a core feature. People who need this can simply add this plugin.

  22. rapetou

    Bonjour,
    pour ce cette modif marche, il faut la placer au début du fichier .htaccess.

    a+

  23. Cas

    I tried to get this running on a MU install placing the rewrite function in a mu-plugin. No result. The main site's "new" login-URL http://my-site.tld/login/ produced a 404. Did I miss something? Running latest WP version, other URL-rewrites (permalinks) working fine as usual. I use sub-directories as Blog-URLs, though, like http://my-site.tld/blog-name.

  24. Andkon

    I really like your work, I alwayz love the ohz-admin dropdown menu you create. It is much organize than using the side left bar panel. Anyway, about your login, I hope there is a screen shot how it looks like. I will always be a fan of your work.

  25. Peter Truong

    Hi,

    I am new to wordpress and a very basic user. I am learning tho :)

    I cannot find the .htaccess file anywhere. I want to change the login slug.

    I host my site with Crazydomains, and access the files and folders there via the cPanel file manager, but searched everywhere in vain for this htaccess file.

    Is there another way I can search for this file?

    thanks
    Pete

  26. Nick Daugherty

    Has anyone gotten this to work with WP Multi-site?

    I've searched Google for an hour and can't find any good reason why this wouldn't be working in WPMS.

  27. AZRainman

    Kudos to you! I was messing around for a couple hours and wondering why I couldn't get the rewrite rule to function properly. The flush process is what all the other pundits failed to mention.

    Thanks for the plugin. I wish I would of came here first.

  28. Y3

    You have the best plugin ever, I have been having your Ohz plugin since I started my wordpress project. the navigation control on the backend is much friendlier to used rather the original left sidebar of wordpress, and its updated to the latest version of wordpress of 3.2 Brilliant! Super Amazing! I hope you will continue your kindness to everyone!

  29. Mike

    It's not working with BuddyPress :(

  30. Y3

    There is no doubt that this code really works.. ozh has been made my site totally great to handle.. its been a year already since enjoying your plugins. your totally one of the best plugins developer….10 star for ozh!

  31. Poptropica

    A brillaint and a helpful tutorial. I love to see more of your code.. Thanks a lot ozh.. a great artist in the world of coding!

  32. Nick Daugherty

    Finally got an answer for WP Multisite users…

    Rather than try to use Ozh's plugin (with Multisite), this is much better handled by a true rewrite rule, something like:

    1. RewriteRule ^login/?$ /wp-login.php [NC,L]

    (untested)

    Using WP's built in rewrites is not such a good idea because you have to flush the rules option for every single blog, which is why the plugin doesn't work for Multisite users.

  33. Affan

    What if you want to send some query parameters?
    redirect admin/?try=1 to wp-admin.php?try=1

  34. rudolf

    ok, i'm testing this on my machine (osx 10.6.8 + MAMP 1.9), but i guess it's not an issue

    1. the home (localhost:8888) and the siteurl (localhost:8888/site) are… different, the rewrite rule should be

    1. RewriteRule ^site/login/?$ /site/wp-login.php [QSA,L]

    or

    1. RewriteRule ^login/?$ /site/wp-login.php [QSA,L]

    but not as it is doing right now

    1. RewriteRule ^login/?$ /wp-login.php [QSA,L]

    this extra code solve this issue

    1. $home = get_option('home');
    2. $siteurl = get_option('siteurl');
    3. $diff = -1*(strlen($siteurl)-strlen($home));
    4. $urlogin = ($diff==0) ? 'wp-login.php' : substr($siteurl, $diff+1).'/wp-login.php';        
    5. add_rewrite_rule( 'login/?$', $urlogin, 'top' );

    2. is it just me, or the rule is not being deleted on de-activation?

    3. and, again, just me, or the rule is being written in the middle of the #WORDPRESS block?

    well, looks like issues 2 and 3 are some handicap in wordpress core, i've checked the documentation, tried other functions combinations, to no avail…

  35. HCE

    Hello!

    I'm new to WordPress and have no background in coding.

    I understand this plugin allows you to change the /wp-login, but does it also change the /wp-admin? When I'm logged in to my Dashboard I notice the url is /wp-admin/index.php and everything I click on has /wp-admin in the url. EX: Pages = /wp-admin/edit.php?post_type=page. My main goal is to change the /wp-admin. Please advise.

    Thanks!

  36. marlboro888

    Am I the only one get 404 page? Tried to make it work but no luck! :|

  37. Z

    No, you are not Marlboro.

    I have the same problem. Getting a 404.

    I even tried to restart Apache Server. No luck.

    My site is in the root. domain/wp-admin works fine. But after installing plugin domain/login should work. But it doesn't. :(

  38. Best Coccyx Cushion

    Thanks very much for creating a very simple but very good security plugin for non technical users like me. I love this plugin.

  39. Arnaldo

    Did anyone get to solve the issue on multisite installation?
    It really doesn't work on MS. I can only get 404s.

Comments are closed.