-
-
Save tommcfarlin/2bf25b85a6360808ea61 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This file is enqueued by means of wp_enqueue_script() - variables are passed | |
* in from PHP by means of wp_localize_script() | |
* | |
*/ | |
/* TM: We use an anonymous function to invoke the JavaScript. Also refactored for proper | |
* WordPress coding standards. | |
*/ | |
(function( $ ) { | |
'use strict'; | |
$(function() { | |
$('#btn-new-user').click( function(event) { | |
// Prevent default action | |
// ----------------------- | |
event.preventDefault(); | |
// Show 'Please wait' loader to user | |
// --------------------------------- | |
$( '.indicator' ).fadeIn( 400 ); | |
$( '.result-message' ).hide(); | |
// Collect data from inputs, and slot into variables | |
// ------------------------------------------------- | |
var reg_nonce = $( '#cw_new_user_nonce' ).val(); | |
var reg_user_role = $( '#cw_user_role' ).val(); | |
var reg_email = $( '#cw_email' ).val(); | |
var reg_firstname = $( '#cw_firstname' ).val(); | |
var reg_lastname = $( '#cw_lastname' ).val(); | |
var reg_cw_ajax = 'true'; // TM: I think this would work better as a boolean literal rather than as a string. | |
// AJAX URL: where to send data (set in the localize_script function) | |
// -------------------------------------------------- | |
var ajax_url = carawebs_reg_vars.carawebs_ajax_url; | |
var coordinatorID = carawebs_reg_vars.carawebs_coordinator_id; | |
// Data to send | |
// ----------------- | |
data = { | |
action: 'register_new_user', | |
cw_coord_id: coordinatorID, | |
cw_user_role: reg_user_role, | |
cw_new_user_nonce: reg_nonce, | |
cw_email: reg_email, | |
cw_firstname: reg_firstname, | |
cw_lastname: reg_lastname, | |
cw_ajax: reg_cw_ajax // let the processing function know it's Ajax - callback function can be tailored. | |
}; | |
// Do AJAX request | |
$.post( ajax_url, data, function( respons e) { | |
if ( response ) { | |
alert( 'Response from server is: ' + response.status ); | |
// Hide 'Please wait' indicator | |
$( '.indicator' ).hide(); | |
var status = response.status; | |
// TM: Rewritten to use Yoda Conditions as per the WPCS | |
if( 'error' === response.status ) { | |
$( '.result-message' ).empty(); // Clear old user list/error messages | |
var output = response.message // decided to build message in PHP and send as a string | |
$( '.result-message' ).append( output ); | |
$( '.result-message' ).show( 800 ); // Show results div | |
} else { | |
// Clear the form, so that another user can be easily registered | |
$( '#user-reg-form' )[0].reset(); | |
$( '.result-message' ).empty(); // Clear old user list/error messages | |
// Build a success message | |
var studentReturn = | |
"<p>" + response.message + "</p>"; | |
$( '.result-message' ).html( studentReturn ); | |
$( '.result-message' ).show( 800 ); // Show results div | |
} | |
} | |
}); | |
}); | |
//var coordinatorID = carawebs_reg_vars.carawebs_coordinator_id; | |
//$('#coord-id').html('<h3>' + coordinatorID + '</h3>'); | |
// Handle another form on the same page | |
$( '#btn-different-id' ).click( function(event) { | |
// Process the form data | |
}); | |
}); | |
})( jQuery ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Facade function to control form validation, data processing and error/success reporting. | |
* | |
* @param int $coordinator_ID User Id of originating coordinator | |
* @param string $user_role The user role for the newly created user | |
* | |
* The function has empty values for $coordinator_ID and $user_role by default, because: | |
* - If the form is submitted by PHP, the values will be passed in from the originating call and will be available | |
* for form processing. | |
* - If the form is submitted by Ajax, the function will be called by add_action('wp_ajax_..., function_name) | |
* and the relevant values will be submitted by the jQuery .post() function in ajax-reg.js. | |
* | |
* | |
*/ | |
/** | |
* TM: This function is a bit long such that it should probably be refactored so that each conditional | |
* is calls it's own method. So rather than having so many if and if/else branches in the code it would | |
* still have the actual conditionals but it would call "private functions") like this: | |
* | |
* if ( conditional ) { | |
* _acme_function_do_work( $params ); | |
* } | |
* | |
* This will make the code easier to trace and even read a bit more line English. A lot of this is like | |
* the work that you're doing with classes where to ultimate goal is to get the units of work down to the | |
* most atomic level possible. | |
*/ | |
} | |
function carawebs_userform_process_facade ( $coordinator_ID = '', $user_role = '' ) { | |
if ( ! empty( $_POST ) ) { | |
if ( isset ($_POST['cw_new_user_nonce'] ) ) { | |
$nonce = $_POST['cw_new_user_nonce']; | |
} | |
// check to see if the submitted nonce matches the generated nonce | |
// TM: Always use braces, even in one line conditionals/loops/etc. It's too dangerous not to :). | |
if ( ! wp_verify_nonce( $nonce, 'cw_new_user' ) ) { | |
die ( 'Sorry, but the security check has failed and we can\'t process this form'); | |
} | |
// Define variables and set to empty values, then add $_POST data if set. | |
// ------------------------------------------------------------------------- | |
$firstname = $email = $lastname = $user_role = $coordinator_ID = ''; | |
$firstname = ( isset( $_POST['cw_firstname'] ) ) ? $_POST['cw_firstname'] : ''; | |
$lastname = ( isset( $_POST['cw_lastname'] ) ) ? $_POST['cw_lastname'] : ''; | |
$email = ( isset( $_POST['cw_email'] ) ) ? $_POST['cw_email'] : ''; | |
$user_role = ( isset( $_POST['cw_user_role'] ) ) ? $_POST['cw_user_role'] : ''; | |
$coordinator_ID = ( isset( $_POST['cw_coord_id'] ) ) ? $_POST['cw_coord_id'] : ''; // if Ajax submission, set by ajax-reg.js | |
$cw_ajax = isset( $_POST['cw_ajax'] ) ? $_POST['cw_ajax'] : 'false'; // Set cw_ajax in the jQuery function - this allows a differential response for ajax submissions | |
// TM: the above 'true/false' values would probably be better as boolean literals than string literals | |
// Validate form data | |
// ------------------- | |
$form = new CW_Reg_Validator( $firstname, $lastname, $email ); | |
$form->is_valid(); | |
$errors = $form->get_errors(); // Get the validation errors, if they exist. | |
// Form data is valid | |
// ----------------------------------------------------------------------- | |
if ( 'true' == $form->is_valid() ) { // returns 'true' if no validation errors found | |
// Create new user | |
// --------------- | |
$new_user = new CW_Create_User( $user_role, $coordinator_ID, $form->get_values() ); | |
// register a user, using values that have been checked for errors & sanitised | |
// If the user is created, $user_created will be set to true. | |
$user_created = $new_user->register( $user_role ); | |
// User Creation Success | |
// --------------------- | |
if ( true == $user_created ){ | |
/** | |
* Build a success message - common for PHP & Ajax | |
* | |
* $new_user->new_user_info = array( | |
* 'first_name' => $user->user_firstname, | |
* 'last_name' => $user->user_lastname, | |
* 'email' => $user->user_email, | |
* 'login' => $user->user_login, | |
* 'display_name' => $user->user_nicename, | |
* ); | |
* | |
*/ | |
// Build a success message | |
// ----------------------- | |
$new_user_details = $new_user->new_user_info; | |
/* TM: If you wrap the string in double-quotes ("), you won't have to escape (\') single quotes | |
* and you can also drop the variables directly in the string and they'll be processed. | |
* For example: | |
* | |
* $user_created = "You've just created a new $user_role."; | |
*/ | |
$user_created = 'You\'ve just created a new ' . $user_role . '. Their details are: | |
<ul class="user-list"> | |
<li>Name: ' . $new_user_details['first_name'] . ' ' . $new_user_details['last_name'] . '</li> | |
<li>Email: ' . $new_user_details['email'] . '</li> | |
<li>Login Username: ' . $new_user_details['login'] . '</li> | |
<li>Display name: ' . $new_user_details['display_name'] . '</li> | |
</ul>'; | |
// Success Return for Ajax | |
// --------------- | |
if ( 'true' == $cw_ajax ) { | |
$response = array(); // this will be a JSON array | |
$response['status'] = 'success'; | |
$response['message'] = $user_created; | |
wp_send_json( $response ); // sends $response as a JSON object | |
} else { | |
// Success Return for PHP | |
// --------------- | |
echo $new_user->success_message; | |
} | |
} else { | |
// User Creation Failure | |
// --------------------- | |
$user_creation_failure = 'User creation failed.'; | |
// TODO: Proper error reporting here. | |
// Failure return for Ajax | |
// --------------- | |
if ('true' == $cw_ajax) { | |
$response = array(); // this will be a JSON array | |
$response['status'] = 'error'; | |
//$response['message'] = json_encode($errors, JSON_FORCE_OBJECT); | |
$response['message'] = $user_creation_failure;//json_encode($user_creation_failure); | |
} else { | |
// Failure return for PHP | |
// --------------- | |
echo $user_creation_failure; | |
} | |
} | |
} | |
// Form Data is invalid: Response | |
// ----------------------------------------------------------------------- | |
if ( ! empty( $errors ) ) { | |
// Build the error message | |
// ------------------------ | |
$error_message = | |
'<p>Sorry - we can\'t process your form because:</p> | |
<ul class="error-list">'; | |
foreach ( $errors as $error ) { | |
$error_message .= '<li>' . $error . '</li>'; | |
} | |
$error_message .= '</ul>'; | |
if ( 'true' == $cw_ajax ) { | |
// Error message for Ajax | |
// ----------------------- | |
$response = array(); // this will be a JSON array | |
$response['status'] = 'error'; | |
$response['message'] = $error_message; | |
wp_send_json( $response ); // sends $response as a JSON object | |
} else { | |
// Error message for PHP | |
// --------------------- | |
echo $error_message; | |
} | |
} | |
} | |
$view = new CW_View_Form( $user_role, $coordinator_ID ); | |
echo $view->render(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* CW_Create_User - Create a new user from form input. | |
* | |
* All input values MUST have been sanitized previously. Form render, validation & sanitization | |
* is handled by separate classes, to separate the logic. | |
* | |
* This class is called by a facade type function. For Student Studio, the following classes are related: | |
* | |
* - CW_Reg_Validator, which validates & sanitizes input, /classes/class-cw-reg-validator.php | |
* - CW_View_Form, which builds the form, /classes/class-cw-view-form.php | |
* | |
* The facade function used for supervisor & student registration is carawebs_userform_process_facade(), | |
* located in /lib/forms.php | |
* | |
* WordPress Version 4.1 | |
* @package CW_Create_User | |
* @author David Egan <[email protected]> | |
* | |
* @TODO return error messages if: | |
* - email doesn't get sent | |
* - wp_insert_user fails | |
* | |
*/ | |
class CW_Create_User { | |
public $new_user_info = array(); | |
public $insert_user_error; | |
public $firstname; | |
public $lastname; | |
public $email; | |
public $user_role; | |
public $coordinator_ID; | |
public $username; | |
public $success_message; | |
/** | |
* Construct method to set properties. | |
* @param string $user_role This will be either 'student', 'supervisor'. | |
* @param int $coordinator_ID The originating coordinator's user ID | |
* @param array $user_values | |
*/ | |
function __construct ( $user_role, $coordinator_ID, $user_values ) { | |
$this->user_role = $user_role; | |
$this->coordinator_ID = $coordinator_ID; | |
$this->firstname = $user_values['first_name']; | |
$this->lastname = $user_values['last_name']; | |
$this->email = $user_values['email']; | |
$this->username = $user_values['email']; | |
} | |
/** | |
* Uses wp_insert_user to programmatically create a new user. New user will have an auto-generated password. | |
* The user login is set to the email address. Uses add_user_meta to set the user role. | |
* @param string $user_role User role: 'student' or 'supervisor' | |
* @return [type] [description] | |
*/ | |
public function register( $user_role ) { | |
$password = wp_generate_password(); | |
$username = $this->username; | |
$userdata = array( | |
'user_login' => $this->email, | |
'user_pass' => $password, | |
'user_email' => $this->email, | |
'first_name' => $this->firstname, | |
'last_name' => $this->lastname, | |
'user_nicename' => $this->firstname, | |
); | |
$user_id = wp_insert_user( $userdata ) ; | |
if ( is_wp_error( $user_id ) ) { | |
// If there is an error inserting a new user... | |
$insert_user_error = $user_id->get_error_message(); | |
} else { | |
// Set the user role | |
// ----------------- | |
$user = new WP_User( $user_id ); | |
$user->set_role( $this->user_role ); | |
// Set the Student's Coordinator | |
// ------------------------------ | |
add_user_meta( $user_id, 'coordinator_id', $this->coordinator_ID ); // $coordinator_id comes from the originating page | |
$coordinator_info = get_userdata( $this->coordinator_ID ); | |
$coordinator_name = $coordinator_info->user_firstname . ' ' . $coordinator_info->user_lastname; | |
// Build an array that can be returned, for a success message | |
// ---------------------------------------------------------- | |
$this->new_user_info = array( | |
'first_name' => $user->user_firstname, | |
'last_name' => $user->user_lastname, | |
'email' => $user->user_email, | |
'login' => $user->user_login, | |
'display_name' => $user->user_nicename, | |
); | |
return true; | |
// TM: This shouldn't ever fire since a return statement is directly before it. | |
$this->email_new_user( $password ); | |
} | |
} | |
/** | |
* Send email to the new user with instructions & password. | |
* Email content is generated from the content of a specified 'email' CPT - | |
* this will allow site admins to control the message. | |
* | |
* @TODO make message specific to 'student' and 'supervisor' user roles. | |
* @TODO set up success and error messages. | |
* @param string $password Auto generated password. | |
* @return [type] [description] | |
* | |
*/ | |
public function email_new_user( $password ){ | |
// Email the user | |
// -------------- | |
// Allow html in email | |
add_filter( 'wp_mail_content_type', function($content_type){ | |
return 'text/html'; | |
}); | |
/** | |
* TODO allow Admin to select the attachment in back end of site | |
*/ | |
//$attachments = array( WP_CONTENT_DIR . '/uploads/2015/01/RDBMStoMongoDBMigration.pdf' ); | |
$headers = 'From: [email protected]' . "\r\n"; | |
$welcome = 'Welcome, ' . $this->firstname . '!'; | |
/** | |
* TODO set this up so that the right 'email' CPT is referenced. | |
* It might be better to set up to reference by post_title, and instruct client to | |
* give appropriate name to the relevant email CPT. | |
*/ | |
$post_id = 62; // Refers to the Student Intro email custom post - rough & ready solution. | |
$post_object = get_post( $post_id ); | |
$mailmessage = $post_object->post_content; // Build a mail message from the content of a post. | |
$mailmessage .= '<hr><p>Your password is: ' . $password . '</p>'; | |
wp_mail( $this->email, $welcome, $mailmessage, $headers/*, $attachments*/ ); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class to validate & sanitise form input. | |
* | |
* WordPress Version 4.1 | |
* @package CW_Reg_Validator | |
* @author David Egan <[email protected]> | |
* | |
* | |
*/ | |
class CW_Reg_Validator { | |
public $form_errors = array(); | |
public $user_values = array(); | |
/** | |
* Construct method | |
* @param string $firstname Un-sanitized form input | |
* @param string $lastname Un-sanitized form input | |
* @param string $email Un-sanitized form input | |
* | |
*/ | |
function __construct ( $firstname, $lastname, $email ) { | |
$this->firstname = $firstname; | |
$this->lastname = $lastname; | |
$this->email = $email; | |
} | |
/** | |
* Check validity of class proprties | |
* @return boolean Returns true if there are no errors, otherwise pushes errors into $form_errors array. | |
* | |
*/ | |
public function is_valid() { | |
// allow letters (both cases), hyphen, space and (\'). | |
$preg_str_check="#[^][(\\\\') A-Za-z-]#"; | |
if ( empty( $this->email ) ) { | |
array_push( $this->form_errors, 'You must enter an email address.' ); | |
} | |
if ( empty( $this->firstname ) ) { | |
array_push( $this->form_errors, 'You must enter a first name.' ); | |
} | |
if( preg_match( $preg_str_check, $this->firstname ) ) { | |
array_push( $this->form_errors, 'The first name you entered doesn\'t look right - please try again with alphabet characters only.' ); | |
} | |
if ( empty( $this->lastname ) ) { | |
array_push( $this->form_errors, 'You must enter a last name.' ); | |
} | |
if( preg_match( $preg_str_check, $this->lastname ) ) { | |
array_push( $this->form_errors, 'The last name you entered doesn\'t look right - please try again with alphabet characters only.' ); | |
} | |
if ( ( $this->email) && ! is_email( $this->email ) ) { | |
array_push( $this->form_errors, 'The email address you submitted doesn\'t look right - please try again, with the format [email protected]'); | |
} | |
if ( email_exists( $this->email ) ) { | |
array_push( $this->form_errors, 'This email is already in use.'); | |
} | |
if ( empty( $this->form_errors ) ) { // There are no errors, so return the string 'true' | |
// TM: Inconsistently returning true and 'true' in your code. Pick one variable type and be consistent with it throughout. | |
return 'true'; | |
} | |
} | |
/** | |
* Return form submission/validation errors | |
* @return array Form errors. | |
* | |
*/ | |
public function get_errors() { | |
return $this->form_errors; | |
} | |
/** | |
* Sanitize input data. | |
* @param string $data Form input data: firstname, lastname, email. | |
* @return string Cleaned up data - sanitised. | |
*/ | |
public function sanitise_inputs( $data ) { | |
$data = trim( $data ); | |
$data = stripslashes( $data ); | |
$data = strip_tags( $data ); | |
$data = htmlspecialchars( $data ); | |
/* TM: May simplify this to the following: | |
* return trim( stripslashes ( strip_tags( htmlspecialchars( $data ) ) ) ); | |
*/ | |
return $data; | |
} | |
/** | |
* Build an array of data relating to the new user & return it. | |
* @return array contains user firstname, lastname, email address. | |
* | |
*/ | |
public function get_values() { | |
$this->firstname = $this->sanitise_inputs($this->firstname); | |
$this->lastname = $this->sanitise_inputs($this->lastname); | |
$this->email = sanitize_email($this->email); | |
$this->user_values = array( | |
'first_name' => $this->firstname, | |
'last_name' => $this->lastname, | |
'email' => $this->email | |
); | |
return $this->user_values; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Create a HTML form for front-end user registration. | |
* WordPress Version 4.1 | |
* @package CW_View_Form | |
* @author David Egan <[email protected]> | |
* | |
* | |
*/ | |
class CW_View_Form { | |
public $proto_session_id; | |
/** | |
* Create a user registration form. | |
* @param string $user_role User role for this instance: 'student' or 'supervisor' | |
* @param int $coordinator_ID User ID of originating coordinator | |
* | |
* | |
*/ | |
/** | |
* Set up properties | |
* @param string $user_role The user role for the new user | |
* @param int $coordinator_ID The user ID of the originating coordinator | |
*/ | |
function __construct ( $user_role, $coordinator_ID ) { | |
$this->user_role = $user_role; | |
$this->coordinator_ID = $coordinator_ID; | |
//$this->sessionnonce = $sessionnonce; | |
$this->proto_session_id = md5( 'whoohoo'. microtime() ); // do we need an original nonce?? | |
// TM: Ideally, I also use whatever nonce WordPress generates. Easiest for code maintainability. | |
} | |
/** | |
* Build a front-end form for user creation | |
* @return string Form html | |
* | |
*/ | |
public function render() { | |
$user_role = ucfirst($this->user_role); | |
$_SESSION['cw_session_id'] = $this->proto_session_id; | |
// TM: Consider moving this to a 'partial' file that is basically an HTML file with nested PHP and then run an include_once | |
$form = ' | |
<div class="cw-registration-form"> | |
<form id="user-reg-form" class="registration-form" role="form" action="' . $_SERVER['REQUEST_URI'] . '" method="post"> | |
<input id="cw_user_role" type="hidden" name="cw_user_role" value="' . $this->user_role . '" /> | |
<input type="hidden" size="45" name="sessionnonce" value="' . $this->proto_session_id . '" /> | |
<div class="form-group"> | |
<label for="cw_firstname" class="sr-only">' . $user_role . '\'s First Name</label> | |
<input autocomplete="off" type="text" name="cw_firstname" id="cw_firstname" value="" placeholder="' . $user_role . '\'s First Name" class="form-control" /> | |
</div> | |
<div class="form-group"> | |
<label for="cw_lastname" class="sr-only">' . $user_role . '\'s Last Name</label> | |
<input autocomplete="off" type="text" name="cw_lastname" id="cw_lastname" value="" placeholder="' . $user_role . '\'s Last Name" class="form-control" /> | |
</div> | |
<div class="form-group"> | |
<label for="cw_email" class="sr-only">' . $user_role . '\'s Email</label> | |
<input autocomplete="off" type="email" name="cw_email" id="cw_email" value="" placeholder="' . $user_role . '\'s Email" class="form-control" /> | |
</div>' . | |
wp_nonce_field('cw_new_user','cw_new_user_nonce', true, true ) . | |
'<input type="submit" name="cw_register" class="btn btn-primary" id="btn-new-user" value="Register" /> | |
</form> | |
<div class="indicator">Please wait...</div> | |
<div class="result-message well topspace"></div> | |
</div>'; | |
return $form; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment