Multisite mode allows you to use one WordPress installation for multiple sites at the same time. In this case, each site gets its own tables in the database with a unique prefix.
Tables with data of registered users are common for all network sites. This is a definite plus and by registering once you can get access to several sites. Moreover, on each site, the same account can have different rights. For example, a user might be an editor on one side and an administrator on another.
In a typical WordPress installation, the registration, login, and password reset page displays a wp-login.php.
- wp-login.php – authorization
wp-login.php?action=register – registration
wp-login.php?action=lostpassword – Password reset
In Multisite mode, the WordPress core starts to behave a little differently and when you click on the link, you wp-login.php?action=register will be redirected to wp-signup.php. This is your network registration page that comes with WordPress by default.
In addition to registering regular user accounts, you can also create a new site on it if the super administrator has enabled this feature in the network settings (Network Admin → Settings → Network Settings).
In most themes, the registration page does not look very good. Many themes use CSS frameworks like Bootstrap and their own specific classes to style different elements on the page, so it’s hard to write a single HTML that fits everyone.
But do not despair if the page looks untidy. The file wp-signup.php is a great thing at first, when there is no time to work through every detail of the site – you can focus on other more important pages and content.
When you’re ready to make your own signup page, this wp-signup.php is a good reference and example to help you understand the range of features that WordPress provides for processing and validating user input and creating new accounts.
Contents
- 0.1 Network main site
- 0.2 functions.php alternative
- 0.3 What are MU plugins?
- 0.4 File order
- 0.5 Registration page
- 0.6 Redirect to the required registration page
- 0.7 wp-signup.php functionality
- 0.8 Copy the functionality of wp-signup.php
- 0.9 Registration form output
- 0.10 Activation page
- 0.11 Activation emails with correct links
- 0.12 Close access to wp-signup.php and wp-activate.php
- 1 Conclusion
Network main site
By default, WordPress opens a registration page ( wp-signup.php) on the main domain (website) of the web. However, you can create registration pages for each site in the network, even if they have different domains and topics.
We will consider the case when all sites in the network use the same theme, but each of them has a registration page. Sites differ in language (English and Russian), so the registration page will be displayed in the “native” language of the site. In case sites use different themes, it will all depend on which themes they are, whether the same layout is suitable for them (a great situation that can push you to unify all your themes) or whether it is worth developing pages individually.
functions.php alternative
The file functions.php is familiar to many WordPress users thanks to events and filters that make editing very easy. In our case, taking into account the fact that the registration functionality is designed for several sites, it makes sense to move it to MU plugins.
What are MU plugins?
MU plugins (Must Use Plugins) are loaded when you open any site on the network. They cannot be disabled or enabled in the WordPress admin area, they always work. It is worth noting that MU plugins are loaded before regular plugins, skins, and before the WordPress core is fully loaded, so calling some functions can lead to fatal errors in PHP.
This “early” loading has its advantages. For example, inside any theme, you can not cling to some events from plugins that work even before loading functions.php.
In Jetpack, for example, there are events of the form jetpack_module_loaded_related-posts( related-posts – the name of the module), with which you can track the activity of modules. This event cannot be “hooked” from functions.php because it fires even before the theme is loaded – plugins are loaded before themes.
You can take a look at the big picture of the WordPress loading order and event firing on the Action Reference page in the Codex.
File order
MU plugins can contain any number of files and structure that seems logical to you. I follow a hierarchy like this:
| mu-plugins | | load.php | | selena network | | | sign up | | | | plugin.php | | | ... | | | jetpack | | | | plugin.php
The file load.php includes translations and all the necessary “plugins”:
// Load translations for MU plugins load_muplugin_textdomain( 'selena_network', '/selena-network/languages/' ); // Functionality for the registration page require WPMU_PLUGIN_DIR . '/selena-network/signup/plugin.php'; // Another plugin // require WPMU_PLUGIN_DIR ...
selena-network Plugin folders are stored inside the directory. Each has its own plugin.php, which we connect to load.php. This gives flexibility and the ability to instantly disable and enable individual components on a working project in case of an emergency.
Registration page
Having figured out where and how we will write the code, we can move on to creating the registration page.
Let’s create a page with an address through the usual interface. You can use any URL that seems appropriate for your project as the address.example.org/signup/
Redirect to the required registration page
In order for WordPress to know about our new registration page and redirect to it when you click on the “Sign up” link, a filter is used wp_signup_location. It can be found inside wp-login.php and it is he who is responsible for the redirect to wp-signup.php the default.
case 'register' : if ( is_multisite() ) { wp_redirect( apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ) ); exit; // ...
As you remember, by default, the registration page opens on the main network domain. That is why it is used here network_site_url().
Let’s add our handler to the filter in mu-plugins/selena-network/signup/plugin.php, which will give the address of the registration page on the current site:
function selena_network_signup_page( $url ) { return home_url( 'signup' ); } add_filter('wp_signup_location', 'selena_network_signup_page', 99);
selena_network – the prefix that I use in the names of all functions inside the MU plugins on my site to avoid collisions, it should be replaced with your own unique prefix. Add filter priority 99 because some plugins like bbPress and BuddyPress can overwrite this address with their own (MU plugins are loaded before normal plugins, see above).
Note that home_url(), which, unlike network_site_url(), gives the address of the current site, not the main site of the network.
wp-signup.php functionality
The file wp-signup.php contains a large number of functions and code. To see the big picture, you can use code folding. As a rule, in English, this is called “code folding”
At the very beginning of the file from lines 1 to 80 (in version 4.1.1), various checks are made and the “start” of the page is displayed using get_header().
Next, a lot of methods are declared, and before we start working with them, it’s worth understanding what each function does. Many of them often use other functions prefixed with wpmu_, all of which are declared in a wp-includes/ms-functions.php. This section is hard to understand without seeing the code yourself. Below is a short description of the main functions in case you have any difficulties.
- wpmu_signup_stylesheet() – output additional CSS on the registration page.
- show_blog_form() – fields for site registration (address, name, visibility for search engines).
- validate_blog_form()- checking the entered site address and name using wpmu_validate_blog_signup().
- show_user_form() — fields for user registration (login and e-mail address).
- validate_user_form()— verification of the entered login and email address. mail using wpmu_validate_user_signup().
- signup_another_blog()- fields for registering new sites with help show_blog_form()for users who are already registered on the site.
- validate_another_blog_signup()- checks the site address and title using validate_blog_form().
- signup_user() – the main function for displaying the fields of the registration page.
- validate_user_signup() – checks the username and email address. mail using validate_user_form().
- signup_blog() – fields for entering the address, name and visibility of the site (the second step of registration) using show_blog_form().
- validate_blog_signup() — checks the login, email address. mail, address and site name.
At the very bottom of the file wp-signup.php(from line 646 in version 4.1.1) is the main logic of the registration page, which uses all the methods described above. This part of the code is not moved into a function. Called at the end get_footer().
Copy the functionality of wp-signup.php
Next, the procedure for copying wp-signup.php to MU plugins and making changes to the “fork” will be described. Perhaps this may not seem the right way. Instead, you can write your own functions for validating and displaying forms from scratch using classes rather than regular functions. In my opinion, wp-signup.php there is already all the necessary logic for our page, it remains only to make small changes.
When updating WordPress, and changes from time to time wp-signup.php, but this does not mean that you will have to synchronize your “fork” with each release. The functions inside wp-signup.php are essentially just outputting HTML, validating data, creating accounts and sites, and the methods with the prefix wpmu_declared in ms-functions.php.
Let’s create a function that will display the registration form on the page. To do this, copy the wp-signup.php из WordPress root to mu-plugins/selena-network/signup/. Let’s connect it inside mu-plugins/selena-network/signup/plugin.php).
require WPMU_PLUGIN_DIR . '/selena-network/signup/wp-signup.php';
Remove all required and unnecessary checks from the very beginning of the copied file. In version 4.1.1, this is all the code from lines 1 to 80.
We are now ready to create the main function to display the signup form. To do this, we will transfer all the logic from line 646 to the very end of the file into a function called selena_network_signup_main. At the very end, we will remove the two extra closing ones </div>(lines 722 and 723), as well as the call to get_footer().
In the newly created selena_network_signup_main()at the very beginning, we will declare a global variable active_signupthat is used by all other methods from this file. And add an event call before_signup_formthat we removed from the very beginning of the file.
function selena_network_signup_main() { global $active_signup; do_action( 'before_signup_form' ); // ... }
Now it remains only to change the layout in all places where it is necessary and the registration page is ready.
Registration form output
There are at least two options here. A more convenient way is to create a shortcode [network_signup]and place it on the page through a regular editor.
// Create shortcode network_signup add_shortcode( 'network_signup', 'selena_network_signup_main' );
The second option is to create a page template in your child theme folder page-signup.php. Instead of the word “signup”, you can use a unique ID assigned to the page. Inside the template, add the necessary layout and make a call selena_network_signup_main()in the right place.
As a result, my registration page looks much better and cleaner.
Activation page
By default, WordPress conditionally divides the registration process in Multisite into two steps – filling out a form on the site and activating an account when clicking on a link sent in an email. After you fill out the form created in the previous section, WordPress sends an email with some instructions and a link to activate your account.
The file wp-activate.PHP located in the WordPress root directory is responsible for displaying the activation page. wp-activate.PHP can also be completely changed. The process is similar to what we already did for wp-signup.php.
Let’s create a page through the usual interface. For the address, use any URL that seems appropriate to you.example.org/activate/
Copy the file wp-activate.php to our MU plugins and include it in mu-plugins/selena-network/signup/plugin.php.
require WPMU_PLUGIN_DIR . '/selena-network/signup/wp-activate.php';
There is not much content inside, unlike wp-signup.php. The file performs a single operation – it activates the account if the correct key is received and displays an error or success message.
Let’s remove all unnecessary checks and require- from lines 1 to 69 in WordPress 4.1.1. At the very end, we will remove the call get_footer(). The remaining content will be transferred to the function selena_network_activate_main().
It is interesting to note that here, before loading WordPress (wp-load.php), a constant was declared WP_INSTALLING. Its presence causes WordPress not to load plugins.
As in the case of the registration page, it remains only to correct the layout where necessary. You can also change the text of displayed messages (in this case, do not forget to add the text domain of your MU plugins to all translator functions, it is not set anywhere by default).
The ready-made function can be used on a pre-created page through a shortcode or a separate template in a child theme.
Activation emails with correct links
The activation page is ready to go, but WordPress doesn’t know about it and will still send activation emails with a link to wp-activate.php. Unlike wp-signup.php here, there is no filter that would allow you to change the address. Instead, you need to write your own function that will send emails with the correct links.
At the time of filling and submitting the form on the registration page, WordPress calls or depending on the type of registration. Both functions create a new record in the table, filling it with the necessary content, among which there is an account activation key.wpmu_signup_user()wpmu_signup_blog()wp_signups
After, depending on the function, either is called . Both functions have similar functionality – they generate and send an email with an activation link, but they take different arguments. Both have filters to “capture” the event.wpmu_signup_user_notification()wpmu_signup_blog_notification()
if ( ! apply_filters( 'wpmu_signup_user_notification', $user, $user_email, $key, $meta ) ) return false; To activate accounts with the creation of a blog: if ( ! apply_filters( 'wpmu_signup_blog_notification', $domain, $path, $title, $user, $user_email, $key, $meta ) ) { return false; }
It remains only to write your own handlers, inside which send letters through wp_mail(), and at the very end, be sure to give false, so that WordPress does not send an activation letter twice – one is yours, the other is a default letter with a link to wp-activate.php.
function selena_network_wpmu_signup_user_notification( $user, $user_email, $key, $meta = array() ) { // Generate the title, text and headers of the email // ... // Send an email or add a Cron task to send an email wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers ); // Set to false so WordPress doesn't send an activation email twice return false; } add_filter( 'wpmu_signup_user_notification', 'selena_network_wpmu_signup_user_notification', 10, 4 ); If you are sending emails through an SMTP server or the number of registrations is very high, you should consider not sending emails instantly. Instead, you can add Cron jobs using WordPress Cron .
Close access to wp-signup.php and wp-activate.php
Having created your own registration and activation pages, you may need to close the “originals“. For example, if there are additional fields on the registration page that must be filled in. Also, many WordPress sites are subject to spam registrations.
To solve two problems in one action, you can ask Apache to return 404 in case of an attempt to open these pages. To do this, you just need to register a couple of additional ones RewriteRulein your configuration file or .htaccess.
Rewrite Engine On RewriteBase / # Knowing regular expressions is never superfluous :) RewriteRule ^wp-signup\.php - [R=404,L] RewriteRule ^wp-activate\.php - [R=404,L] # BEGIN WordPress # We do not touch the rules from WordPress by default :) # ... # END WordPress
Conclusion
For this and many other “problems” related to WordPress, there are many solutions on the Internet. For example, to create registration and activation pages, some suggest rewriting the original wp-signup.php and wp-activate.php. You should not do this, because if you update WordPress, you will lose all changes made to the files, and you will also not be able to check the integrity of the core using WP-CLI.
When developing any add-on, theme, or solution, spend a little time getting to grips with what’s going on inside WordPress. There are many useful debug tools for this.