Last active
April 22, 2024 12:16
-
-
Save gmazzap/9520781 to your computer and use it in GitHub Desktop.
Just a rough plugin example to answer a WPSE question: How to display Wordpress User Registration Form in front-end of the website?
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 | |
namespace Custom_Reg; | |
class Custom_Reg { | |
protected $form; | |
protected $saver; | |
function __construct( Form $form, Saver $saver ) { | |
$this->form = $form; | |
$this->saver = $saver; | |
} | |
/** | |
* Check if the url to recognize is the one for the registration form page | |
*/ | |
function checkUrl() { | |
$url_part = $this->getUrl(); | |
$nonce = urlencode( wp_create_nonce( 'registration_url' ) ); | |
if ( ( $url_part === $nonce ) ) { | |
// do nothing if registration is not allowed or user logged | |
if ( is_user_logged_in() || ! get_option('users_can_register') ) { | |
wp_safe_redirect( home_url() ); | |
exit(); | |
} | |
return TRUE; | |
} | |
} | |
/** | |
* Init the form, if submitted validate and save, if not just display it | |
*/ | |
function init() { | |
if ( $this->checkUrl() !== TRUE ) return; | |
do_action( 'custom_reg_form_init', $this->form ); | |
if ( $this->isSubmitted() ) { | |
$this->save(); | |
} | |
// don't need to create form if already saved | |
if ( ! isset( $custom_reg_form_done ) || ! $custom_reg_form_done ) { | |
$this->form->create(); | |
} | |
load_template( $this->getTemplate() ); | |
exit(); | |
} | |
protected function save() { | |
global $custom_reg_form_error; | |
$this->saver->setFields( $this->form->getFields() ); | |
if ( $this->saver->validate() === TRUE ) { // validate? | |
if ( $this->saver->save() ) { // saved? | |
global $custom_reg_form_done; | |
$custom_reg_form_done = TRUE; | |
} else { // saving error | |
$err = $this->saver->getErrorMessage(); | |
$custom_reg_form_error = $err ? : __( 'Error on save.', 'custom_reg_form' ); | |
} | |
} else { // validation error | |
$custom_reg_form_error = $this->saver->getErrorMessage(); | |
} | |
} | |
protected function isSubmitted() { | |
$type = $this->form->getVerb() === 'GET' ? INPUT_GET : INPUT_POST; | |
$sub = filter_input( $type, 'custom_reg_form', FILTER_SANITIZE_STRING ); | |
return ( ! empty( $sub ) && $sub === get_class( $this->form ) ); | |
} | |
protected function getTemplate() { | |
$base = $this->form->getTemplate() ? : FALSE; | |
$template = FALSE; | |
$default = dirname( __FILE__ ) . '/default_form_template.php'; | |
if ( ! empty( $base ) ) { | |
$template = locate_template( $base ); | |
} | |
return $template ? : $default; | |
} | |
protected function getUrl() { | |
$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' ); | |
$relative = trim( str_replace( $home_path, '', add_query_arg( array() ) ), '/' ); | |
$parts = explode( '/', $relative ); | |
if ( ! empty( $parts ) && ! isset( $parts[1] ) ) { | |
return $parts[0]; | |
} | |
} | |
} |
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 | |
/** | |
* Plugin Name: Custom Registration Form | |
* Description: Just a rough plugin example to answer a WPSE question | |
* Plugin URI: http://wordpress.stackexchange.com/questions/10309/ | |
* Author: G. M. | |
* Author URI: http://wordpress.stackexchange.com/users/35541/g-m | |
* | |
*/ | |
if ( is_admin() ) return; | |
load_plugin_textdomain( | |
'custom_reg_form', | |
FALSE, | |
plugin_dir_path( __FILE__ ) . 'langs' | |
); | |
require_once plugin_dir_path( __FILE__ ) . 'FieldInterface.php'; | |
require_once plugin_dir_path( __FILE__ ) . 'fields.php'; | |
require_once plugin_dir_path( __FILE__ ) . 'Form.php'; | |
require_once plugin_dir_path( __FILE__ ) . 'Saver.php'; | |
require_once plugin_dir_path( __FILE__ ) . 'CustomReg.php'; | |
/** | |
* Generate dynamic registration url | |
*/ | |
function custom_registration_url() { | |
$nonce = urlencode( wp_create_nonce( 'registration_url' ) ); | |
return home_url( $nonce ); | |
} | |
/** | |
* Generate dynamic registration link | |
*/ | |
function custom_registration_link() { | |
$format = '<a href="%s">%s</a>'; | |
printf( | |
$format, | |
custom_registration_url(), __( 'Register', 'custom_reg_form' ) | |
); | |
} | |
/** | |
* Setup, show and save the form | |
*/ | |
add_action( 'wp_loaded', function() { | |
try { | |
$form = new Custom_Reg\Form; | |
$saver = new Custom_Reg\Saver; | |
$custom_reg = new Custom_Reg\Custom_Reg( $form, $saver ); | |
$custom_reg->init(); | |
} catch ( Exception $e ) { | |
if ( defined('WP_DEBUG') && WP_DEBUG ) { | |
$msg = 'Exception on ' . __FUNCTION__; | |
$msg .= ', Type: ' . get_class( $e ) . ', Message: '; | |
$msg .= $e->getMessage() ? : 'Unknown error'; | |
error_log( $msg ); | |
} | |
wp_safe_redirect( home_url() ); | |
} | |
}, 0 ); | |
/** | |
* Add fields to form | |
*/ | |
add_action( 'custom_reg_form_init', function( $form ) { | |
$classes = array( | |
'Custom_Reg\FullName', | |
'Custom_Reg\Login', | |
'Custom_Reg\Email', | |
'Custom_Reg\Country' | |
); | |
foreach ( $classes as $class ) { | |
$form->addField( new $class ); | |
} | |
}, 1 ); |
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 | |
get_header(); | |
global $custom_reg_form_done, $custom_reg_form_error; | |
if ( isset( $custom_reg_form_done ) && $custom_reg_form_done ) { | |
echo '<p class="success">'; | |
_e( | |
'Thank you, your registration was submitted, check your email.', | |
'custom_reg_form' | |
); | |
echo '</p>'; | |
} else { | |
if ( $custom_reg_form_error ) { | |
echo '<p class="error">' . $custom_reg_form_error . '</p>'; | |
} | |
do_action( 'custom_registration_form' ); | |
} | |
get_footer(); |
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 | |
namespace Custom_Reg; | |
interface FieldInterface { | |
/** | |
* Return the field id, used to name the request value and for the 'name' param of | |
* html input field | |
*/ | |
public function getId(); | |
/** | |
* Return the filter constant that must be used with | |
* filter_input so get the value from request | |
*/ | |
public function getFilter(); | |
/** | |
* Return true if the used value passed as argument should be accepted, false if not | |
*/ | |
public function isValid( $value = NULL ); | |
/** | |
* Return true if field is required, false if not | |
*/ | |
public function isRequired(); | |
/** | |
* Return the field input markup. The 'name' param must be output | |
* according to getId() | |
*/ | |
public function create( $value = ''); |
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 | |
namespace Custom_Reg; | |
abstract class BaseField implements FieldInterface { | |
protected function getType() { | |
return isset( $this->type ) ? $this->type : 'text'; | |
} | |
protected function getClass() { | |
$type = $this->getType(); | |
if ( ! empty($type) ) return "{$type}-field"; | |
} | |
public function getFilter() { | |
return FILTER_SANITIZE_STRING; | |
} | |
public function isRequired() { | |
return isset( $this->required ) ? $this->required : FALSE; | |
} | |
public function isValid( $value = NULL ) { | |
if ( $this->isRequired() ) { | |
return $value != ''; | |
} | |
return TRUE; | |
} | |
public function create( $value = '' ) { | |
$label = '<p><label>' . $this->getLabel() . '</label>'; | |
$format = '<input type="%s" name="%s" value="%s" class="%s"%s /></p>'; | |
$required = $this->isRequired() ? ' required' : ''; | |
return $label . sprintf( | |
$format, | |
$this->getType(), $this->getId(), $value, $this->getClass(), $required | |
); | |
} | |
abstract function getLabel(); | |
} | |
class FullName extends BaseField { | |
protected $required = TRUE; | |
public function getID() { | |
return 'fullname'; | |
} | |
public function getLabel() { | |
return __( 'Full Name', 'custom_reg_form' ); | |
} | |
} | |
class Login extends BaseField { | |
protected $required = TRUE; | |
public function getID() { | |
return 'login'; | |
} | |
public function getLabel() { | |
return __( 'Username', 'custom_reg_form' ); | |
} | |
} | |
class Email extends BaseField { | |
protected $type = 'email'; | |
public function getID() { | |
return 'email'; | |
} | |
public function getLabel() { | |
return __( 'Email', 'custom_reg_form' ); | |
} | |
public function isValid( $value = NULL ) { | |
return ! empty( $value ) && filter_var( $value, FILTER_VALIDATE_EMAIL ); | |
} | |
} | |
class Country extends BaseField { | |
protected $required = FALSE; | |
public function getID() { | |
return 'country'; | |
} | |
public function getLabel() { | |
return __( 'Country', 'custom_reg_form' ); | |
} | |
} |
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 | |
namespace Custom_Reg; | |
class Form { | |
protected $fields; | |
protected $verb = 'POST'; | |
protected $template; | |
protected $form; | |
public function __construct() { | |
$this->fields = new \ArrayIterator(); | |
} | |
public function create() { | |
do_action( 'custom_reg_form_create', $this ); | |
$form = $this->open(); | |
$it = $this->getFields(); | |
$it->rewind(); | |
while( $it->valid() ) { | |
$field = $it->current(); | |
if ( ! $field instanceof FieldInterface ) { | |
throw new \DomainException( "Invalid field" ); | |
} | |
$form .= $field->create() . PHP_EOL; | |
$it->next(); | |
} | |
do_action( 'custom_reg_form_after_fields', $this ); | |
$form .= $this->close(); | |
$this->form = $form; | |
add_action( 'custom_registration_form', array( $this, 'output' ), 0 ); | |
} | |
public function output() { | |
unset( $GLOBALS['wp_filters']['custom_reg_form'] ); | |
if ( ! empty( $this->form ) ) { | |
echo $this->form; | |
} | |
} | |
public function getTemplate() { | |
return $this->template; | |
} | |
public function setTemplate( $template ) { | |
if ( ! is_string( $template ) ) { | |
throw new \InvalidArgumentException( "Invalid template" ); | |
} | |
$this->template = $template; | |
} | |
public function addField( FieldInterface $field ) { | |
$hook = 'custom_reg_form_create'; | |
if ( did_action( $hook ) && current_filter() !== $hook ) { | |
throw new \BadMethodCallException( "Add fields before {$hook} is fired" ); | |
} | |
$this->getFields()->append( $field ); | |
} | |
public function getFields() { | |
return $this->fields; | |
} | |
public function getVerb() { | |
return $this->verb; | |
} | |
public function setVerb( $verb ) { | |
if ( ! is_string( $verb) ) { | |
throw new \InvalidArgumentException( "Invalid verb" ); | |
} | |
$verb = strtoupper($verb); | |
if ( in_array($verb, array( 'GET', 'POST' ) ) ) $this->verb = $verb; | |
} | |
protected function open() { | |
$out = sprintf( '<form id="custom_reg_form" method="%s">', $this->verb ) . PHP_EOL; | |
$nonce = '<input type="hidden" name="_n" value="%s" />'; | |
$out .= sprintf( $nonce, wp_create_nonce( 'custom_reg_form_nonce' ) ) . PHP_EOL; | |
$identity = '<input type="hidden" name="custom_reg_form" value="%s" />'; | |
$out .= sprintf( $identity, __CLASS__ ) . PHP_EOL; | |
return $out; | |
} | |
protected function close() { | |
$submit = __('Register', 'custom_reg_form'); | |
$out = sprintf( '<input type="submit" value="%s" />', $submit ); | |
$out .= '</form>'; | |
return $out; | |
} | |
} |
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 | |
namespace Custom_Reg; | |
class Saver { | |
protected $fields; | |
protected $user = array( 'user_login' => NULL, 'user_email' => NULL ); | |
protected $meta = array(); | |
protected $error; | |
public function setFields( \ArrayIterator $fields ) { | |
$this->fields = $fields; | |
} | |
/** | |
* validate all the fields | |
*/ | |
public function validate() { | |
// if registration is not allowed return false | |
if ( ! get_option('users_can_register') ) return FALSE; | |
// if registration is not allowed return false | |
if ( ! $this->getFields() instanceof \ArrayIterator ) return FALSE; | |
// first check nonce | |
$nonce = $this->getValue( '_n' ); | |
if ( $nonce !== wp_create_nonce( 'custom_reg_form_nonce' ) ) return FALSE; | |
// then check all fields | |
$it = $this->getFields(); | |
while( $it->valid() ) { | |
$field = $it->current(); | |
$key = $field->getID(); | |
if ( ! $field instanceof FieldInterface ) { | |
throw new \DomainException( "Invalid field" ); | |
} | |
$value = $this->getValue( $key, $field->getFilter() ); | |
if ( $field->isRequired() && empty($value) ) { | |
$this->error = sprintf( __('%s is required', 'custom_reg_form' ), $key ); | |
return FALSE; | |
} | |
if ( ! $field->isValid( $value ) ) { | |
$this->error = sprintf( __('%s is not valid', 'custom_reg_form' ), $key ); | |
return FALSE; | |
} | |
if ( in_array( "user_{$key}", array_keys($this->user) ) ) { | |
$this->user["user_{$key}"] = $value; | |
} else { | |
$this->meta[$key] = $value; | |
} | |
$it->next(); | |
} | |
return TRUE; | |
} | |
/** | |
* Save the user using core register_new_user that handle username and email check | |
* and also sending email to new user | |
* in addition save all other custom data in user meta | |
* | |
* @see register_new_user() | |
*/ | |
public function save() { | |
// if registration is not allowed return false | |
if ( ! get_option('users_can_register') ) return FALSE; | |
// check mandatory fields | |
if ( ! isset($this->user['user_login']) || ! isset($this->user['user_email']) ) { | |
return false; | |
} | |
$user = register_new_user( $this->user['user_login'], $this->user['user_email'] ); | |
if ( is_numeric($user) ) { | |
if ( ! update_user_meta( $user, 'custom_data', $this->meta ) ) { | |
wp_delete_user($user); | |
return FALSE; | |
} | |
return TRUE; | |
} elseif ( is_wp_error( $user ) ) { | |
$this->error = $user->get_error_message(); | |
} | |
return FALSE; | |
} | |
public function getValue( $var, $filter = FILTER_SANITIZE_STRING ) { | |
if ( ! is_string($var) ) { | |
throw new \InvalidArgumentException( "Invalid value" ); | |
} | |
$method = strtoupper( filter_input( INPUT_SERVER, 'REQUEST_METHOD' ) ); | |
$type = $method === 'GET' ? INPUT_GET : INPUT_POST; | |
$val = filter_input( $type, $var, $filter ); | |
return $val; | |
} | |
public function getFields() { | |
return $this->fields; | |
} | |
public function getErrorMessage() { | |
return $this->error; | |
} | |
} |
Hi Giuseppe, really an excellent work. I'm trying to getting it work but I'm failing. Can't realize where I'm idling... May you help with some sample on how to use it, please?
thanks,
kr, Dario.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thx ... for this work ...
can you post an example how to use your work in a concrete example ...
thx a lot