प्रक्रिया में 2 चरण शामिल हैं:
- सामने का रूप दिखाएं
- डेटा सबमिट करने पर सेव करें
3 अलग-अलग दृष्टिकोण हैं जो मेरे दिमाग में सामने वाले को दिखाने के लिए आते हैं:
- इसे अधिक "फ्रंटएंड" बनाने के लिए बिल्ट-इन रजिस्ट्रेशन फॉर्म, एडिटिंग स्टाइल आदि का उपयोग करें।
- एक वर्डप्रेस पृष्ठ / पोस्ट का उपयोग करें, और एक शोर्ट का उपयोग करके प्रदर्शन फ़ॉर्म
- एक समर्पित टेम्पलेट का उपयोग किसी भी पृष्ठ / पोस्ट से जुड़ा नहीं है, लेकिन एक विशिष्ट यूआरएल द्वारा कहा जाता है
इस उत्तर के लिए मैं बाद का उपयोग करूँगा। कारण हैं:
- बिल्ट-इन रजिस्ट्रेशन फॉर्म का उपयोग करना एक अच्छा विचार हो सकता है, गहरे कस्टमाइज़ेशन बिल्ट-इन फॉर्म का उपयोग करके बहुत कठिन हो सकते हैं, और यदि कोई कस्टमाइज़ करना चाहता है तो दर्द को बढ़ा सकता है।
- एक शोर्टकोड के साथ संयोजन में एक वर्डप्रेस पेज का उपयोग करें, इतना विश्वसनीय नहीं है, और मुझे यह भी लगता है कि शोर्टकोड का उपयोग कार्यक्षमता के लिए नहीं किया जाना चाहिए, बस स्वरूपण और इस तरह के लिए
1: यूआरएल का निर्माण
हम सभी जानते हैं कि वर्डप्रेस साइट का डिफ़ॉल्ट पंजीकरण फॉर्म अक्सर स्पैमर्स के लिए एक लक्ष्य है। कस्टम url का उपयोग इस समस्या को हल करने में मदद करता है। इसके अलावा, मैं एक चर url का उपयोग करना चाहता हूं , अर्थात पंजीकरण फॉर्म url हमेशा समान नहीं होना चाहिए, इससे स्पैमर्स का जीवन कठिन हो जाता है। चाल url में एक गैर का उपयोग करके किया जाता है :
/**
* 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' )
);
}
इस फ़ंक्शंस का उपयोग करना टेम्प्लेट में प्रदर्शित करना आसान है, भले ही यह गतिशील हो, पंजीकरण फ़ॉर्म का लिंक।
2: url को पहचानें, Custom_Reg\Custom_Reg
कक्षा का पहला स्टब
अब हमें url को पहचानने की आवश्यकता है। इस प्रस्ताव के लिए मैं एक कक्षा लिखना शुरू करूँगा, जो उत्तर में बाद में समाप्त होगी:
<?php
// don't save, just a stub
namespace Custom_Reg;
class Custom_Reg {
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;
}
}
protected function getUrl() {
$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
$relative = trim(str_replace($home_path, '', esc_url(add_query_arg(array()))), '/');
$parts = explode( '/', $relative );
if ( ! empty( $parts ) && ! isset( $parts[1] ) ) {
return $parts[0];
}
}
}
फ़ंक्शन url के पहले भाग को देखता है home_url()
, और यदि यह हमारे नॉन से मेल खाता है तो यह TRUE पर लौटता है। यह फ़ंक्शन हमारे अनुरोध की जांच करने और हमारे फ़ॉर्म को प्रदर्शित करने के लिए आवश्यक कार्रवाई करने के लिए उपयोग किया जाएगा।
3: Custom_Reg\Form
वर्ग
अब मैं एक क्लास लिखूंगा, जो फॉर्म मार्कअप जनरेट करने के लिए जिम्मेदार होगा। मैं इसे एक संपत्ति में स्टोर करने के लिए उपयोग करूँगा टेम्पलेट फ़ाइल पथ जिसे फ़ॉर्म प्रदर्शित करने के लिए उपयोग किया जाना चाहिए।
<?php
// file: Form.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_registration_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;
}
}
क्लास ने सभी क्षेत्रों को जोड़ने के लिए फार्म मार्कअप लूपिंग उत्पन्न की, create
जिनमें से प्रत्येक पर कॉलिंग विधि भी शामिल है। प्रत्येक क्षेत्र का उदाहरण होना चाहिए Custom_Reg\FieldInterface
। नॉन वेरिफिकेशन के लिए एक अतिरिक्त छिपा हुआ क्षेत्र जोड़ा जाता है। फॉर्म विधि डिफ़ॉल्ट रूप से 'POST' है, लेकिन इसे setVerb
विधि का उपयोग करके 'GET' में निपटाया जा सकता है । एक बार बनाया गया मार्कअप $form
ऑब्जेक्ट ऑब्जेक्ट के अंदर सहेजा जाता है जिसे output()
विधि द्वारा प्रतिध्वनित किया जाता है, हुक में 'custom_registration_form'
हुक किया जाता है: फॉर्म टेम्पलेट में, बस कॉल do_action( 'custom_registration_form' )
फॉर्म को आउटपुट करेगा।
4: डिफ़ॉल्ट टेम्पलेट
जैसा कि मैंने कहा कि फॉर्म के लिए टेम्प्लेट को आसानी से ओवरराइड किया जा सकता है, हालांकि हमें फॉलबैक के रूप में एक बुनियादी टेम्प्लेट की आवश्यकता होती है। मैंने यहाँ लिखा है एक बहुत ही कठिन टेम्पलेट, एक वास्तविक टेम्पलेट की तुलना में अवधारणा का प्रमाण अधिक है।
<?php
// file: default_form_template.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();
5: Custom_Reg\FieldInterface
इंटरफ़ेस
प्रत्येक फ़ील्ड में एक ऑब्जेक्ट होना चाहिए जो निम्नलिखित इंटरफ़ेस को लागू करता है
<?php
// file: FieldInterface.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 = '');
}
मुझे लगता है कि टिप्पणियां बताती हैं कि इस इंटरफ़ेस को लागू करने वाले वर्गों को क्या करना चाहिए।
6: कुछ क्षेत्रों को जोड़ना
अब हमें कुछ क्षेत्रों की आवश्यकता है। हम एक फाइल बना सकते हैं, जिसे 'field.php' कहा जाता है, जहां हम फील्ड क्लासेस को परिभाषित करते हैं:
<?php
// file: fields.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' );
}
}
मैंने डिफॉल्ट इंटरफ़ेस इम्प्लिमेंटेशन को परिभाषित करने के लिए बेस क्लास का उपयोग किया है, हालाँकि, कोई बहुत ही कस्टमाइज़्ड फ़ील्ड को सीधे इंटरफ़ेस को लागू कर सकता है या बेस क्लास को बढ़ा सकता है और कुछ तरीकों को ओवरराइड कर सकता है।
इस बिंदु पर हमारे पास फ़ॉर्म प्रदर्शित करने के लिए सब कुछ है, अब हमें फ़ील्ड को सत्यापित करने और सहेजने के लिए कुछ चाहिए।
7: Custom_Reg\Saver
वर्ग
<?php
// file: Saver.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 no fields are setted 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;
}
}
उस वर्ग में, 2 मुख्य विधियाँ हैं, एक ( validate
) जो खेतों को लूप करती है, उन्हें मान्य करती है और एक सरणी में अच्छे डेटा को सहेजती है, दूसरी ( save
) डेटाबेस में सभी डेटा को सहेजती है और नए उपयोगकर्ता को ईमेल के माध्यम से पासवर्ड भेजती है।
8: परिभाषित कक्षाओं का उपयोग करना: Custom_Reg
कक्षा को पूरा करना
अब हम Custom_Reg
कक्षा पर फिर से काम कर सकते हैं , उन तरीकों को जोड़ सकते हैं जो परिभाषित की गई वस्तुओं को "glues" करते हैं और उन्हें काम करते हैं
<?php
// file Custom_Reg.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];
}
}
}
कक्षा का निर्माणकर्ता एक उदाहरण को स्वीकार करता Form
है Saver
।
init()
विधि (का उपयोग करके checkUrl()
) के बाद url के पहले भाग को देखें home_url()
, और यदि यह सही गैर के साथ मेल खाता है, तो यह जाँचता है कि क्या फॉर्म पहले ही सबमिट किया गया था, यदि ऐसा है तो Saver
ऑब्जेक्ट का उपयोग करते हुए , यह उपयोगकर्ता नाम को सत्यापित और सहेजता है, अन्यथा बस फॉर्म को प्रिंट करें ।
init()
विधि 'custom_reg_form_init'
प्रपत्र आवृत्ति को तर्क के रूप में पास करने वाले एक्शन हुक को भी आग लगाती है: इस हुक का उपयोग फ़ील्ड जोड़ने के लिए, कस्टम टेम्पलेट को सेटअप करने के लिए और फॉर्म विधि को अनुकूलित करने के लिए भी किया जाना चाहिए।
9: चीजों को एक साथ रखना
अब हमें मुख्य प्लगइन फाइल लिखने की आवश्यकता है, जहां हम कर सकते हैं
- सभी फ़ाइलों की आवश्यकता है
- टेक्सटोमैन को लोड करें
- तत्काल पूरी तरह से हुक का उपयोग करके इस पर तत्काल
Custom_Reg
वर्ग और कॉल init()
विधि का उपयोग करके स्टार्टअप पूरी प्रक्रिया
- फ़ील्ड बनाने के लिए फ़ील्ड जोड़ने के लिए 'custom_reg_form_init' का उपयोग करें
इसलिए:
<?php
/**
* Plugin Name: Custom Registration Form
* Description: Just a rough plugin example to answer a WPSE question
* Plugin URI: https://wordpress.stackexchange.com/questions/10309/
* Author: G. M.
* Author URI: https://wordpress.stackexchange.com/users/35541/g-m
*
*/
if ( is_admin() ) return; // this plugin is all about frontend
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 );
10: लापता कार्य
अब हमेशा के लिए किया जाता है। हमें बस टेम्पलेट को कस्टमाइज़ करना है, शायद हमारे विषय में एक कस्टम टेम्पलेट फ़ाइल जोड़ना है।
हम इस तरह से केवल विशिष्ट पंजीकरण पृष्ठ पर विशिष्ट शैलियों और लिपियों को जोड़ सकते हैं
add_action( 'wp_enqueue_scripts', function() {
// if not on custom registration form do nothing
if ( did_action('custom_reg_form_init') ) {
wp_enqueue_style( ... );
wp_enqueue_script( ... );
}
});
उस विधि का उपयोग करके हम ग्राहक पक्ष सत्यापन को संभालने के लिए कुछ js स्क्रिप्ट्स को संलग्न कर सकते हैं, जैसे यह एक । उस स्क्रिप्ट का काम करने के लिए आवश्यक मार्कअप को आसानी से Custom_Reg\BaseField
कक्षा को संपादित करने के लिए नियंत्रित किया जा सकता है ।
यदि हम पंजीकरण ईमेल को अनुकूलित करना चाहते हैं, तो हम मानक विधि और मेटा पर सहेजे गए कस्टम डेटा का उपयोग कर सकते हैं, हम उनका उपयोग ईमेल में कर सकते हैं।
अंतिम कार्य जिसे हम संभवतः कार्यान्वित करना चाहते हैं, निवेदन को डिफ़ॉल्ट पंजीकरण फ़ॉर्म से रोकना है, जितना आसान:
add_action( 'login_form_register', function() { exit(); } );
सभी फाइलें यहां एक जिस्ट में मिल सकती हैं ।