8

I would like to extend the WordPress password protection of posts by adding extra input field for user email.

So in order to see the content user will have to know the password and previously given email that is stored in custom meta field of the protected post.

I was trying to find a good hook checking that extra field but without any success. Could you give me some ideas how to make it? I don't want to create user accounts for this kind of feature.

7

When you set a post as password protected, the protection happen on get_the_content() function. There WordPress check for a post password cookie, and if not set, not valid or expired then show the password form.

This password form is submitted to wp-login.php, there a cookie is setted according to the password wrote in the form, then the request is redirected to the post again.

The process can be described like so:

  1. go to post page
  2. call the_content()
  3. check the cookie
  4. if not valid show the password form
  5. submit form to wp_login.php
  6. wp_login.php
  7. set the cookie based on pwd submitted and redirect to post page
  8. start again form #1

What we can do:

  • at point #4 use the hook 'the_password_form' to edit the output of the form, adding a field for the email and a hidden field with the post id (at this point we are inside get_the_content function so we have access to global post variable)
  • Unluckily at point #3 there we can't change the result of cookie check (or at least we can't in a easy and reliable way). But at point #7 WordPress has a filter hook that allow to set the cookie expiration: if we set that time to a past timestamp, then the cookie will not be set (and if existx it will be deleted) and so the validation will fail. So we can use that hook to check the email submitted via the form and thanks to the post id in the hidden field we can compare it with the emails in the meta, if the email si not given or is wrong we return a past timestamp.

First step:

/**
 * Customize the form, adding a field for email and a hidden field with the post id
 */
add_filter( 'the_password_form', function( $output ) {

  unset( $GLOBALS['the_password_form'] );
  global $post;
  $submit = '<input type="submit" name="Submit" value="' . esc_attr__('Submit') . '" /></p>';
  $hidden = '<input type="hidden" name="email_res_postid" value="' . $post->ID . '">';
  $email = '</p><p><label for="email_res">' . __( 'Email:' );
  $email .= '<input name="email_res" id="email_res" type="text" size="20" /></label></p><p>';
  return str_replace( $submit, $hidden . $email . $submit, $output );

}, 0 );

And the second:

/**
 * Set the post password cookie expire time based on the email
 */
add_filter( 'post_password_expires', function( $valid ) {

  $postid = filter_input( INPUT_POST, 'email_res_postid', FILTER_SANITIZE_NUMBER_INT );
  $email = filter_input( INPUT_POST, 'email_res', FILTER_SANITIZE_STRING );
  // a timestamp in the past
  $expired = time() - 10 * DAY_IN_SECONDS;
  if ( empty( $postid ) || ! is_numeric( $postid ) ) {
      // empty or bad post id, return past timestamp
      return $expired;
  }
  if ( empty($email) || ! filter_var($email, FILTER_VALIDATE_EMAIL) ) {
      // empty or bad email id, return past timestamp
      return $expired;
  }
  // get the allowed emails
  $allowed = array_filter( (array)get_post_meta( $postid, 'allow_email' ), function( $e ) {
    if ( filter_var( $e, FILTER_VALIDATE_EMAIL) ) return $e;
  });
  if ( ! empty( $allowed ) ) { // some emails are setted, let's check it
    // if the emails posted is good return the original expire time
    // otherwise  return past timestamp
    return in_array( $email, $allowed ) ? $valid : $expired;
  }
  // no emails are setted, return the original expire time
  return $valid;

}, 0 );

We are done.

Now create a post, save as password protected and set some allowed emails in custom fields using the key 'allow_email'. There's no limit on number of the emails you can add...


Settings:

Custom fields to allow email post protection


post protection via password


Result (TwentyThirteen with no additional styling):

Result in TwentyThirteen with no additional styling

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.