Chronicles of a build - the signup plugin 06

Disclaimer

What I write in these posts is not the perfect travel of an expert and consumed WordPress developer but the gnarly and error-prone stroll of an average developer (pun intended).
I will make mistakes and will try to correct them along the road and mean to share the path I’ve taken with all its fallback and wrong turns and not to show the best possible one.

Follow along

After setting up the plugin using grunt-init I’ve deployed it in my local site and made it available on GitHub. I will commit to the GitHub repository throughout the work and the plugin can be downloaded and installed in WordPress. The code I show becomes much more comprehensible when observed in context.
See the earlier post of the series to catch-up.

Adding the shortcode

Following the guidelines of the WordPress Codex about shortcodes I add the plugin shortcode and its callback function in its front-end class, class-member_signup.php and make it output a form element with the right, test-wise, id attribute:

add_shortcode( 'membersignup', array( $this, 'display_login_form') ); // called in __construct method
...
public function display_login_form( $atts, $content='' ){
    return "<form id="member_login_form">Member login form</form>";
} 

Redirecting users to the custom login page

Sticking to the rule of writing as little code as possible to pass the test (be it an acceptance test or a unit test) I add the simplest possible action to redirect users to the custom login page in the front-end class of the plugin like this

/**
 * Add an action to redirect users to the member login page
 */
add_action( 'wp_loaded', array( $this, 'redirect_to_member_login' ) );

/**
 * Redirects not logged-in visitors to a custom login page
 * @return none
 */
public function redirect_to_member_login(){
    // logged-in users go their usual way
    if  ( is_user_logged_in() )
        return;
    // only attempt redirection if visiting the login page
    if ( $GLOBALS[ 'pagenow'] != 'wp-login.php') 
        return;
    // Check for POST or GET requests to avoid blocking custom login functions
    // original code by user Anatoly of StackOverflow
    // http://stackoverflow.com/questions/1976781/redirecting-wordpresss-login-register-page-to-a-custom-login-registration-page
    if ( isset( $_POST['wp-submit'] ) ||   // in case of LOGIN
        ( isset($_GET['action']) && $_GET['action']=='logout') ||   // in case of LOGOUT
        ( isset($_GET['checkemail']) && $_GET['checkemail']=='confirm') ||   // in case of LOST PASSWORD
        ( isset($_GET['checkemail']) && $_GET['checkemail']=='registered') ) {
        return;
    }
    // get the plugin set options
    $membersignup_options = get_option( 'membersignup_options', array() );
    // is the custom login page has been set use it else default it to the default login page
    $custom_login_page_url = get_site_url( null, '/wp-login.php' );
    if ( isset( $membersignup_options['custom_member_login_page_url'] )) {
        $custom_login_page_url = $membersignup_options['custom_member_login_page_url']; 
    } 
    wp_redirect( $custom_login_page_url );
    exit();
}

Please note that I hook into wp_loaded hook in place of hooking into init hook. I’ve spent some time trying to figure out why my function, the same you see above, did not trigger the redirect. Using Debug Bar and its Debug Bar Action and Filters Addon I could spot my function being called by init hook
[caption id=“attachment_180” align=“aligncenter” width=“653”]Init hook callbacks Init hook callbacks[/caption]
but still the redirect did not happen. Looking at WordPress Plugin API action reference I simply moved down the list to the wp_loaded hook, which means attaching the callback function to later calls, and tried. Maybe earlier hooks than wp_loaded would work but attaching a redirect action to scripts or UI related hooks smells bad.
[caption id=“attachment_181” align=“aligncenter” width=“748”]Action reference hook list Action reference hook list[/caption]

A quick recap before running the first test again

The first test will simply try to go the site login page as a non logged-in user expecting to find an element with an id="member_login_form" attribute in the page.

  • To redirect visitors to the custom login page I hook into wp_loaded, make some checks and send them… where?
  • To send visitors to a non hard-coded custom login page I have added an option for the site administrators to set the page the visitors will get redirected to
  • Since I can’t hard-code the page the visitors will get redirected to I have added a shortcode the site administrators can use to output the login form in any page
  • In that output I control I’ve added an empty form element with the right attribute

The green light

Running the Selenium test I had set up earlier I now can see the green light of success. The first end-to-end or acceptance test is passed.
[caption id=“attachment_182” align=“aligncenter” width=“757”]First green light First green light[/caption]

Set up new smaller tests

The test my code just passed in Selenium is too high-level to drive the quality of the code. I did nothing any plugin, developed using functional or OOP techniques, could not have accomplished. In fact until now what the plugin does is really nothing exceptional: there are many plugins available that will do the same with more options.
What I’m trying to do is to develop this plugin using a Test Driven Development: I developed the bare functions the acceptance test drove me to develop.
Next step is taking this process into the unit-testing level refactoring what is working code into testable code written using OOP techniques to make the code easy to support, expand and fix.
The code I’ve written is not the best possible code and I can think of many simple tests it will not pass. But I do not care because I will know.
That’s the prize I like about TDD: I move from working state to working state and not from an I-don’t-know-why-but-it-works to an I-don’t-know-why-it-doesn’t-work state.

If I’ve ignited your interest in TDD as a concept, not in the WordPress ecosystem alone, then I suggest the book Growing Object-Oriented Software Guided by Tests.