In: , , ,
On: 2011 / 01 / 14 Viewed: 73977 times
Shorter URL for this post: http://ozh.in/uf

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. }

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! ;)

Shorter URL

Want to share or tweet this post? Please use this short URL: http://ozh.in/uf

Metastuff

This entry "Pretty Login URL: a Simple Rewrite API Plugin Example" was posted on 14/01/2011 at 4:33 pm and is tagged with , , ,
Watch this discussion : Comments RSS 2.0.

39 Blablas

  1. 1
    Eric United States »
    replied, on 14/Jan/11 at 5:14 pm # :

    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. 2
    Craig Canada »
    said, on 14/Jan/11 at 5:41 pm # :

    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. 3
    Ozh France »
    commented, on 14/Jan/11 at 6:26 pm # :

    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. 4
    MadtownLems United States »
    said, on 14/Jan/11 at 10:22 pm # :

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

  5. 5
    thompson United States »
    replied, on 15/Jan/11 at 1:15 am # :

    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. 6
    Michael Fields United States »
    commented, on 15/Jan/11 at 3:28 pm # :

    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. 7
    Adam W. Warner United States »
    commented, on 15/Jan/11 at 3:38 pm # :

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

  8. 8
    Chris Coyier United States »
    replied, on 15/Jan/11 at 4:43 pm # :

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

  9. 9
    geminorum United Kingdom »
    replied, on 17/Jan/11 at 11:18 pm # :

    how about adding wp-signup.php too?

  10. 10
    Ozh France »
    wrote, on 17/Jan/11 at 11:36 pm # :

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

  11. 11
    Travis United States »
    commented, on 22/Jan/11 at 6:09 am # :

    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. 12
    Jamal Mohamed Djibouti »
    replied, on 22/Jan/11 at 9:38 am # :

    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. 13
    Pete Thailand »
    replied, on 31/Jan/11 at 4:46 pm # :

    Yes, I like! Thanks :)

  14. 14
    iMp Malaysia »
    thought, on 03/Feb/11 at 9:47 am # :

    I also want to know just like Travis

  15. 15
    Ozh France »
    said, on 03/Feb/11 at 4:05 pm # :

    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. 16
    Travis United States »
    wrote, on 03/Feb/11 at 4:13 pm # :

    Well, don't I feel silly!

    Thanks for the followup comment, Ozh.

  17. 17
    Stacy United States »
    commented, on 24/Feb/11 at 6:54 pm # :

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

  18. 18
    D.K. United States »
    wrote, on 24/Feb/11 at 7:10 pm # :

    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. 19
    troy United States »
    wrote, on 24/Feb/11 at 11:34 pm # :

    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. 20
    Troy United States »
    thought, on 25/Feb/11 at 1:14 am # :

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

  21. 21
    Ozh France »
    replied, on 25/Feb/11 at 1:36 am # :

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

  22. 22
    rapetou France »
    said, on 07/Mar/11 at 9:49 am # :

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

    a+

  23. 23
    Cas Germany »
    said, on 15/May/11 at 4:39 pm # :

    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. 24
    Andkon Philippines »
    said, on 17/May/11 at 4:54 am # :

    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. 25
    Peter Truong Australia »
    replied, on 20/May/11 at 10:27 am # :

    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. 26
    Nick Daugherty United States »
    replied, on 20/Jul/11 at 2:33 am # :

    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. 27
    AZRainman United States »
    said, on 03/Aug/11 at 9:44 pm # :

    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. 28
    Y3 Philippines »
    thought, on 04/Aug/11 at 1:03 am # :

    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. 29
    Mike Canada »
    wrote, on 24/Aug/11 at 4:12 am # :

    It's not working with BuddyPress :(

  30. 30
    Y3 Philippines »
    said, on 24/Aug/11 at 10:44 am # :

    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. 31
    Poptropica Philippines »
    said, on 26/Aug/11 at 6:50 am # :

    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. 32
    Nick Daugherty United States »
    said, on 26/Aug/11 at 8:43 pm # :

    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. 33
    Affan Pakistan »
    replied, on 29/Aug/11 at 9:50 am # :

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

  34. 34
    rudolf Spain »
    replied, on 31/Aug/11 at 10:22 am # :

    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. 35
    HCE United States »
    wrote, on 24/Sep/11 at 7:04 pm # :

    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. 36
    marlboro888 United States »
    thought, on 03/Dec/11 at 10:24 am # :

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

  37. 37
    Z Denmark »
    wrote, on 22/Feb/12 at 12:14 am # :

    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. 38
    Best Coccyx Cushion India »
    wrote, on 21/Jul/12 at 5:28 pm # :

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

  39. 39
    Arnaldo Brazil »
    thought, on 15/Mar/14 at 1:16 am # :

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

Leave a Reply

Comment Guidelines or Die

  • HTML: You can use these tags: <a href=""> <em> <i> <b> <strong> <blockquote>
  • Posting code: Post raw code (no <> &lt; etc) within appropriate tags : [php][/php], [css][/css], [html][/html], [js][/js], [sql][/sql], [xml][/xml], or generic [code][code]
  • Gravatars: Curious about the little images next to each commenter's name ? Go to Gravatar.
  • Spam: Various spam plugins on patrol. I'll put pins in a Voodoo doll if you spam me.
  • I will mark as Spam test comments, all comments with SEO names (ie "My Cool Online Shop" instead of "Joe") or containing forum-like signatures.

Read more ?