2 comments

  1. Here’s the solution I came up with that relies on the info already present in the database.

    Background

    Each password-protected post stores the password in plaintext in the wp_posts table (in the post_password column). We can use that to query the db for any posts that have that password assigned and get the post info based on that. From there, we can redirect to the password-protected post.

    Assumptions/constraints

    The OP stated that a custom login form would be used for clients to enter their special password. I’m assuming that form is created and can use a GET request to send the password since it’s already plaintext.

    The OP also stated each password protecting the post/page would be unique. I’m assuming that unique password is generated separately from this answer.

    How it works

    A query string of client_key is sent (either through the GET of the form, or through a link) and checked using get_query_var(). If it’s present, check the wp_posts table for the first post that has a password set that equals the client_key and return the row as an object.

    Sanity check: if object has been created, create a couple of variables to use in our JavaScript function.

    Echo a script element into the DOM that will run a POST function to wp-login.php. This mimics the form posting that would normally happen when a password-protected page is visited for the first time. There, the client would be prompted for the password to view the post content, and once it was given a cookie is created to allow future access to the content.
    This function does the same form submission behind the scenes, the redirects to the appropriate post (based on GUID).

    Finally, only run the function on the front-end of the site, when wp_head is fired (when jQuery is [usually] loaded).

    The code

    <?php
    /**
     * Add our custom query string to the global query_vars.
     *
     * @param array $vars The global vars used throughout WP.
     *
     * @return array
     */
    function wpse134962_add_query_vars_filter( $vars ) {
        $vars[] = 'client_key';
    
        return $vars;
    }
    
    add_filter( 'query_vars', 'wpse134962_add_query_vars_filter' );
    
    /**
     * Redirect to a password-protected page based on the query string.
     *
     * If client_key is passed in the query string, check the database for a post that
     * has a password assigned that equals the client_key. If one is found, submit the
     * login form to create the cookie that allows entry, then redirect to the post.
     */
    function wpse134962_password_redirect() {
        $client_key = get_query_var( 'client_key' ) ? get_query_var( 'client_key' ) : '';
    
        if ( ! empty( $client_key ) ) {
            /** @var wpdb $wpdb */
            global $wpdb;
            $query          = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_password = %s", $client_key );
            $password_posts = $wpdb->get_row( $query );
    
            if ( isset( $password_posts ) ) {
                $post_id   = $password_posts->ID;
                $login_url = site_url( 'wp-login.php' );
    
                echo <<<HTML
    <script>
    jQuery(function() {
    var postURL = "$login_url?action=postpass",
        postData = {
            post_password: "$client_key"
        },
        postRedirect = function() {
            document.location = "{$password_posts->guid}";
        };
    jQuery.post( postURL, postData, postRedirect() );
    })();
    </script>
    HTML;
    
            }
        }
    
    }
    
    if ( ! is_admin() ) {
        /** Only fire on the front end of the site. */
        add_action( 'wp_head', 'wpse134962_password_redirect' );
    }
    
  2. I answered my own question. Here’s a plugin that does almost exactly what I needed, but I needed the same functionality on custom post types:

    Smart Passworded Pages

    I just modified the plugin and made my own for personal use.

    Editing for usefulness:

    This plugin contains only one PHP file. In this file is a single class by the name of “smartPWPages” that contains 3 functions. Within the “process_form” function is a call to the get_pages function. In version 3.8.1, the plugin didn’t work out of the box, so I removed the “child_of” and “parent” args from the get_pages call. After removing these args, the plugin works, but only for pages. In order to make it work for a custom post type, you can simply change the “post_type” arg to your custom post type instead of “page”.

    These minor tweaks enabled me to set up a client portal using a custom post type, which has a single log in page where users are redirected to their proper area based on the password entered. I could see many uses for this for items such as project management systems and the like. Definitely a useful plugin.

Comments are closed.