Total Pageviews

Thursday, March 24, 2011

Wordpress Password Protected Page - Add error message

A client wanted to password protect a page and have a custom login for the pages. They also requested the password page show an error message. The first part of this request is truely easy. I place a hook inside the theme's function.php like this:

add_filter( 'the_password_form', 'custom_password_form' );
function custom_password_form() {
global $post;
$label = 'pwbox-'.( empty( $post->ID ) ? rand() : $post->ID );
$o = '

<div class="main login">
                <div class="logo"> </div>
<div class="login_form">
<h2>Seating Options Pricing Tool</h2>
<form class="protected-post-form" action="' .  get_option('site_url') . '/wp-pass.php" method="post">

<label for="' . $label . '">Password</label>
<input name="post_password" id="' . $label . '" type="password" size="20"  />

<div class="form_options">
<div class="remember"><input type="checkbox"> Remember Me</div>
<input type="submit" name="Submit" value="Log In" class="submitBtn" />
</div>
</form>
</div>

</div>


';
return $o;
}

Then I modify the page to show certain content if authenticated correctly and the login form again if not:


<?php get_header(); ?>


<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
<?php if ( !post_password_required($post) ) {
        // logged in
        <div class="content">

   the_content();
        </div>
}
else
{
//pulls login page from functions.php
        <div class="login"> 

   the_content(); 
        </div>
}
?>

<?php endwhile; ?>
<?php get_footer(); ?>



The request to have an error for invalid requested was a little tricky. First I copied the wp-pass.php file and copied it to my theme. (so when I update my wordpress I wont loose this)  Next I modified the custom_password_form function's form field to post to my themes form.  Afterwards I modified the copied wp-pass.php file like so:


<?php
/**
 * Creates the password cookie and redirects back to where the
 * visitor was before.
 *
 * @package WordPress
 */

/** Make sure that the WordPress bootstrap has run before continuing. */
require( $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php');

$redirect = wp_get_referer();
$passwordtried='';

if ( get_magic_quotes_gpc() )
$_POST['post_password'] = stripslashes($_POST['post_password']);

$redirect= str_replace("?try=1", "", $redirect);
$passwordtried='?try=1';

// 10 days
setcookie('wp-postpass_' . COOKIEHASH, $_POST['post_password'], time() + 864000, COOKIEPATH);

wp_safe_redirect($redirect.$passwordtried);
exit;
?>

Since the authentication happens later in the page load by reading the cookie I am merely adding a querystring variable to the redirect of "try=1" I suppose if it were necessary I could increment this amount but for this client it was not.

Next I modified my page.php to look for the querystring only when the page has been authenticated correctly otherwise I am showing the login form again. If I find the try querystring variable I remove it and redirect. I am doing this above the get_header tag to make sure I don't get any errors.


<?php if ( !post_password_required($post) ) {

//do this before content is loaded. this is removing and incorrect password tries from the url
if($_GET["try"])
{
$redirect = wp_get_referer();
$redirect= str_replace("?try=1", "", $redirect);
wp_safe_redirect($redirect);
}
}
?>
<?php get_header(); ?>

Now I modified my custom_password_form function inside the functions.php inside my theme again. This time I am adding checks for this try querystring variable and adding classes and spans:

function custom_password_form() {
global $post;
$label = 'pwbox-'.( empty( $post->ID ) ? rand() : $post->ID );
$o = '
<div class="main login">
                <div class="logo"> </div>
<div class="login_form">
<h2>Seating Options Pricing Tool</h2>
<form class="protected-post-form" action="' .  get_option('site_url') . '/wp-pass.php" method="post">
<label for="' . $label . '">Password'.(($_GET["try"])?" <span class='error'>That was an invalid password</span>":"").'</label>
<input name="post_password" id="' . $label . '" type="password" size="20" '.(($_GET["try"])?'class="error"':'').'  />
<div class="form_options">
<div class="remember"><input type="checkbox"> Remember Me</div>
<input type="submit" name="Submit" value="Log In" class="submitBtn" />
</div>
</form>
</div>
</div>
';
return $o;
}

Finally I modify the style sheet with my new classes.
span.error{
color:red;
display:block;
float:right;
}
input.error
{
border:1px solid red;
}


Hope this helps someone. If you know of a different approach let me know. 

2 comments:

relish27 said...

Thanks! I got it to work because of you. Two things I wanted to ask about.

1) You said that you posted to your wp-pass page, but it looks like you are posting to the original wp-pass.php page in your HTML code. Should it actually go elsewhere?

2) I tried to have it post to a copy of the wp-pass.php page in my theme, but it returned a 404. So then I renamed it wp-pass-tickets.php (just a new name) and left it in the root. This worked. Is that a safe thing to do? Or is there a better place to put it?

Thanks!

Ameen Khatri said...

I have read your article, it is very informative and helpful for me.I admire the valuable information you offer in your articles. Thanks for posting it.. autoblog wordpress website