{"id":1637,"date":"2011-01-14T16:33:06","date_gmt":"2011-01-14T14:33:06","guid":{"rendered":"http:\/\/planetozh.com\/blog\/?p=1637"},"modified":"2026-05-09T16:05:51","modified_gmt":"2026-05-09T14:05:51","slug":"pretty-login-url-a-simple-rewrite-api-plugin-example","status":"publish","type":"post","link":"https:\/\/planetozh.com\/blog\/2011\/01\/pretty-login-url-a-simple-rewrite-api-plugin-example\/","title":{"rendered":"Pretty Login URL: a Simple Rewrite API Plugin Example"},"content":{"rendered":"<p>A few days ago, the fine folks from DigWP have published a <a href=\"http:\/\/digwp.com\/2011\/01\/simpler-login-url\/\">.htaccess trick<\/a> to enable logging in from <tt>yoursite.com\/login<\/tt> instead of <tt>yoursite.com\/wp-login.php<\/tt>.<\/p>\n<p>Their trick is perfectly valid, yet improvable: it requires editing of the <tt>.htaccess<\/tt>, a file you don&#39;t want noobs to mess with. So <a href=\"http:\/\/digwp.com\/2011\/01\/simpler-login-url\/#comment-15812\">my thoughts<\/a> were: &quot;OK, that&#39;s nice and everything, but a simple plugin would be cleaner, easier for beginners, and more portable&quot;. Let&#39;s do this?<br \/>\n<!--more--><\/p>\n<h2>Rewrite API to the rescue<\/h2>\n<p>There&#39;s an API in WordPress that&#39;s exactly designed to create rewrite rules in a more convenient and dynamic way than having to play with the <tt>.htaccess<\/tt> file: the Rewrite API.<\/p>\n<p>The Rewrite API is the part of the WordPress engine that handles all the internal URL rewriting, to have neat stuff like <tt>yoursite.com\/2011\/01\/happy-new-year\/<\/tt> instead of <tt>yoursite.com\/index.php?p=1337<\/tt>. In the admin area, the Permalink Settings that allow you to specify your Pretty Permalink structure (for instance <tt>\/%year%\/%month%\/%postname%\/<\/tt>) leverage that API.<\/p>\n<p>The original <tt>.htaccess<\/tt> trick is simply to rewrite <tt>\/login<\/tt> to <tt>\/wp-login.php<\/tt>, or, in plain English: &quot;if someone requests the URL &#39;login&#39;, then show them the content of wp-login.php&quot;. The bit to add to your <tt>.htaccess<\/tt> is:<\/p>\n<div class=\"igsh-code-box\" id=\"ig-sh-1\"><pre class=\"language-none line-numbers\" data-no-optimize=\"1\" data-cfasync=\"false\"><code class=\"language-none\">RewriteRule ^login$ http:\/\/yoursite.com\/wp-login.php [NC,L]<\/code><\/pre><\/div>\n<p>There&#39;s a simple function in the Rewrite API which job is exactly to create this kind of rewrite rules: <tt>add_rewrite_rule()<\/tt><\/p>\n<h2>Create a rule with add_rewrite_rule()<\/h2>\n<p>This function, to be found in <a href=\"http:\/\/core.trac.wordpress.org\/browser\/tags\/3.0.4\/wp-includes\/rewrite.php#L19\">wp-includes\/rewrite.php<\/a>, has the following syntax and parameters: <tt>add_rewrite_rule( $regex, $redirect, $after )<\/tt> where<\/p>\n<ul>\n<li><tt>$regex<\/tt> is a string that contains the Regular Expression (or RegEx) to match requests<\/li>\n<li><tt>$redirect<\/tt> is a string for the location to redirect to<\/li>\n<li>the optional <tt>$after<\/tt> specifies where to add the rule in the list: &#39;bottom&#39; (default) if you want your RewriteRule to be matched after everything has failed, or &#39;top&#39; if you want it to have greater priority and eventually supersede potentially conflicting rules (for instance if you have a page titled &quot;Login&quot;)<\/li>\n<\/ul>\n<p>So, basically, all it takes to programatically create the rewrite rule for our Pretty Login URL plugin is the following snippet:<\/p>\n<div class=\"igsh-code-box\" id=\"ig-sh-2\"><pre class=\"language-php line-numbers\" data-no-optimize=\"1\" data-cfasync=\"false\"><code class=\"language-php\">\/\/ Create new rewrite rule\r\nadd_action( &#039;init&#039;, &#039;wp_ozh_plu_rewrite&#039; );\r\nfunction wp_ozh_plu_rewrite() {\r\n    add_rewrite_rule( &#039;login\/?$&#039;, &#039;wp-login.php&#039;, &#039;top&#039; );\r\n}<\/code><\/pre><\/div>\n<p>The regexp used here will match &#39;login&#39;, &#39;login\/&#39; but not &#39;login\/somethingelse&#39;.<\/p>\n<h2>Complete plugin: Pretty Login URL<\/h2>\n<p>There&#39;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 &quot;flush&quot; the list to force a refresh. Therefore, the complete plugin will monitor activation and deactivation to make sure the list is flushed when appropriate<\/p>\n<div class=\"igsh-code-box\" id=\"ig-sh-3\"><pre class=\"language-php line-numbers\" data-no-optimize=\"1\" data-cfasync=\"false\"><code class=\"language-php\">&lt;?php\r\n\/*\r\nPlugin Name: Ozh&#039; Pretty Login URL\r\nPlugin URI: http:\/\/planetozh.com\/blog\/?s=pretty+login+url\r\nDescription: Pretty Login URL\r\nVersion: 0.1\r\nAuthor: Ozh\r\nAuthor URI: http:\/\/ozh.org\/\r\n*\/\r\n\r\n\/\/ Add rewrite rule and flush on plugin activation\r\nregister_activation_hook( __FILE__, &#039;wp_ozh_plu_activate&#039; );\r\nfunction wp_ozh_plu_activate() {\r\n    wp_ozh_plu_rewrite();\r\n    flush_rewrite_rules();\r\n}\r\n\r\n\/\/ Flush on plugin deactivation\r\nregister_deactivation_hook( __FILE__, &#039;wp_ozh_plu_deactivate&#039; );\r\nfunction wp_ozh_plu_deactivate() {\r\n    flush_rewrite_rules();\r\n}\r\n\r\n\/\/ Create new rewrite rule\r\nadd_action( &#039;init&#039;, &#039;wp_ozh_plu_rewrite&#039; );\r\nfunction wp_ozh_plu_rewrite() {\r\n    add_rewrite_rule( &#039;login\/?$&#039;, &#039;wp-login.php&#039;, &#039;top&#039; );\r\n}\r\n?&gt;<\/code><\/pre><\/div>\n<p>Also available as a regular <a href=\"http:\/\/wordpress.org\/extend\/plugins\/ozh-simpler-login-url\/\">downloadable plugin<\/a> from wordpress.org.<\/p>\n<h2>And that&#39;s it. You like?<\/h2>\n<p>That&#39;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.<\/p>\n<p>If you liked this article, hey, I have some news for you: my upcoming book <a href=\"http:\/\/amzn.to\/plugindevbook\">Professional WordPress Plugin Development<\/a> will have a whole chapter on the Rewrite API, full of hands-on detailed examples and real life cases. Buy it now! ;)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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&#39;t want noobs to mess with. So my thoughts were: &quot;OK, that&#39;s nice and everything, but a simple plugin would be\u2026<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21],"tags":[194,85,389,245],"class_list":["post-1637","post","type-post","status-publish","format-standard","hentry","category-published","tag-htaccess","tag-plugins","tag-rewrite","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/posts\/1637","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/comments?post=1637"}],"version-history":[{"count":1,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/posts\/1637\/revisions"}],"predecessor-version":[{"id":3904,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/posts\/1637\/revisions\/3904"}],"wp:attachment":[{"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/media?parent=1637"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/categories?post=1637"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/planetozh.com\/blog\/wp-json\/wp\/v2\/tags?post=1637"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}