Only allow specific user roles to log into WordPress site - php

I currently have a WP site setup with a unique 'multisite' plugin installed specifically to allow for a single admin area of WooCommerce products, but with 2 different front-ends based on 2 different domains, with separate themes.
One of the sites is a 'wholesale' site while the other is 'retail'. The wholesale site should only allow trade customers to make purchases. The problem lies in that both sites are sharing a single domain, and therefore user accounts.
The problem: I need to ensure if a user who is does not have the user role 'trade_customer' tries to log into the wholesale site, the role is checked and the user is logged out, redirected to login page with a notification. So far I have the following in functions.php:
function trade_customers_only() {
function get_user_role() {
global $current_user;
$user_roles = $current_user->roles;
$user_role = array_shift($user_roles);
return $user_role;
}
$the_current_role = get_user_role();
echo $the_current_role;
if( $the_current_role != 'administrator' ) {
$logout_url = wp_login_url().'?mode=tradeonly';
wp_destroy_current_session();
wp_logout();
wp_redirect( $logout_url, 302 );
exit();
}
}
add_action('wp_login', 'trade_customers_only');
// CUSTOM LOGIN MESSAGES
function my_login_message() {
if( $_GET['mode'] == 'tradeonly' ){
$message = '<p class="message"><b>You must be a Trade Customer to access this site.</b></p>';
return $message;
}
}
add_filter('login_message', 'my_login_message');
This code is currently: returning the logged in user to wp-login.php and adding the note "You must be a trade customer... etc". However, after the first login attempt with any user role, every other login attempt does the same redirect and shows message. Is my code incorrect or is there some WP session cookie in the DB or browser causing the problem whereby WP thinks I am not using an admin account?
The first time I attempted login was with admin account. it worked and went to dashboard. Next attempt was with a customer role account. The redirect and note occurred. A following attempt with admin account only did the redirect with note, but no dashboard access.

1) Change your trade_customers_only function:
function trade_customers_only($login, $user) {
if( $user->roles && !in_array('administrator',$user->roles)) {
$logout_url = wp_login_url().'?mode=tradeonly';
wp_destroy_current_session();
wp_logout();
wp_redirect( $logout_url, 302 );
exit();
}
}
And fix your action call:
add_action('wp_login', 'trade_customers_only',10,2);
2) The other solution is using authenticate filter instead of using wp_login action. The difference is that you check for the user's role before user's session sets, so you don't need to destroy it.
add_filter('authenticate',function($user,$username) {
if (!is_wp_error($user)) {
$auth_user=get_user_by('login',$username);
if ($auth_user && !in_array('administrator',$auth_user->roles)) {
return new WP_Error('authentication_failed', '<p class="message"><b>You must be a Trade Customer to access Key Essentials. Are you looking for Love Tillys?</b></p>');
}
}
return $user;
},100,2);

My new full code is now:
function trade_customers_only($login, $user) {
if( $user->roles && !in_array('administrator',$user->roles)) {
$logout_url = wp_login_url().'?mode=tradeonly';
wp_destroy_current_session();
wp_logout();
wp_redirect( $logout_url, 302 );
exit();
}
}
add_action('wp_login', 'trade_customers_only',10,2);
// CUSTOM LOGIN MESSAGES
function my_login_message() {
if( $_GET['mode'] == 'tradeonly' ){
$message = '<p class="message"><b>You must be a Trade Customer to access this site.</b></p>';
return $message;
}
}
add_filter('login_message', 'my_login_message');
This code works properly. However as Kulivov Sergey mentioned in his reply, using the authenticate filter instead of the wp_login action is better for what I need to achieve. Using:
add_filter('authenticate',function($user,$username) {
if (!is_wp_error($user)) {
$auth_user=get_user_by('login',$username);
if ($auth_user && !in_array('administrator',$auth_user->roles)) {
return new WP_Error('authentication_failed', '<p class="message"><b>You must be a Trade Customer to access this site.</b></p>');
}
}
return $user;
},100,2);
Not only checks for the user role without logging in and creating a session, it also keeps the user on their current page with no redirection, which is great.

I have tested the below code as working correctly.
There's no need to run wp_destroy_current_session() or wp_logout(), just simply return an error instead and it will interrupt authentication and show your error message on the login page.
You might have to make sure the priority is last (100 in this case), so that existing filters wp_authenticate_username_password, wp_authenticate_email_password and wp_authenticate_spam_check all do their thing and before the user is fully logged in that you will then deny.
/* Only allow administrators to login */
add_filter( 'authenticate', 'my_admin_check', 100, 1 );
function my_admin_check( $user ) {
// Make sure this is a real login attempt, without errors
if ( !is_wp_error($user) ) {
$user_role = $user->roles[0];
// add or remove the roles you want to allow/disallow (can be a custom role or regular WordPress roles)
if ( !in_array( $user_role, array( 'trade_customer' ) ) ){
return new WP_Error( 'login_failed', __( "Only staff can use this login.", "mysite_domain" ) );
} else {
// allow the login
return $user;
}
} else {
// We're just loading the login page, not running a login.
return $user;
}
}

Related

Why does is_user_logged_in() return false after redirect from another site?

I am developing a WordPress site that redirects to an external payment gateway after a user registers for the site. After the user makes a payment the user is redirected to a page to complete their sign up.
Here is the code used for the redirect:
$login_data = array();
$login_data['user_login'] = $email;
$login_data['user_password'] = $password;
$login_data['remember'] = true;
$user = wp_signon($login_data);
if(!is_wp_error($user)){
wp_set_current_user( $user->ID, $email );
wp_set_auth_cookie( $user->ID, true, false );
wp_redirect("https://another_payment_gateway.com");
exit;
}
The user is redirected and fills out the payment form. Upon success the user is redirected to a landing page. If they are not logged in they are shown a dialog for non logged in users. Here is the code on that page:
if(is_user_logged_in()){
$user = wp_get_current_user();
//code for logged in users
}else{
//message for non logged in users
}
If I go to the account page it is shown that the user is logged in. But when redirected from a different site is_user_logged_in() returns false. Any insight into this issue would be much appreciated.
add_action( 'loop_start', 'your_function' );
function your_function() {
if ( is_user_logged_in() ) {
echo '<li id="text-2" class="hide">';
} else {
echo '<li id="text-2">';
}
}
Please check with the above hook , will that work for logged-in and non-logged-in user.

Stop user registration on wordpress websites

I have few WordPress websites with disabled registration, but still, I can see people are registering as admin, after a while, they reset the password and log in to the admin panel.. as I can see some fishy things on my server. How can I secure my websites from this kind of registration? the URL mydomain.comwp-login.php?action=register says disabled and redirecting to the login page.
Setting -> General -> uncheck "Anyone can register"
After successful registration, Wordpress immediately calls 'user_register' hook. You can perform a task there.
add_action( 'user_register', 'myplugin_registration_save', 10, 1 );
function myplugin_registration_save( $user_id ) {
/** Here You can disable user's status or change user's credentials on the behalf of '$user_id' so that it cannot be logged into your system. You can remove the user as well. */
}
If you are comfortable with editing your theme's function.php then these scripts will help:
Disable all user registrations:
If your site is not handling any memberships and you want to totally disable the user registrations, then you can add this script in your active themes function.php file:
add_filter( 'wp_pre_insert_user_data', 'disable_user_registrations', 10, 2 );
function disable_user_registrations ($data, $update) {
if( !$update ) {
return [];
}
return $data;
}
This will throw an error: 'Not enough data to create this user.'
Disable specific user roles:
For example, disable user registrations with administrator role:
add_filter( 'wp_pre_insert_user_data', 'disable_user_registrations_for_role', 10, 4 );
function disable_user_registrations_for_role ($data, $update, $userId, $userdata) {
if( !$update && !empty($userdata['role']) && $userdata['role'] == 'administrator' ) ) {
return [];
}
return $data;
}
Disable specific usernames:
If you would like to disable registrations with specific usernames such as admin, then you can use below code:
add_filter( 'illegal_user_logins', 'disable_user_registrations_with_usernames' );
function disable_user_registrations_with_usernames () {
return ['admin']; //disables anyone registering with the username admin
}

Wordpress Disable Page if user not logged in

I have a page 'account' where I want users to be able to edit their profile.
But how do I disable the page for users who are not logged in?
Maybe with: !is_user_logged_in ?
They should not be able to access the page. Maybe get redirected to login page.
Add this code in your Function.php file.
using template_redirect action hook
function template_redirect_fn()
{
if(is_page (Page ID, title, slug of account page ) && !is_user_logged_in ())
{
$loginUrl = home_url('/login-page/');
wp_redirect($loginUrl);
exit();
}
}
add_action( 'template_redirect', 'template_redirect_fn' );
is_page() is check page is account [you can pass the account page id or page title or page slug ]
is_user_logged_in() is check user is login or not return (bool) True if user is logged in, false if not logged in.
You can do this flowing way.
if( !is_user_logged_in ) {
$loginUrl = home_url('/login-page/');
echo '<script>window.location.href = "'.$loginUrl.'";</script>';
}

Wordpress: On login send to pages list rather than dashboard

Is there a function that will allow you to change where you get redirected to once logged in?
I'm logging into the standard Wordpress login form which redirects you to the dashboard, is there a way to change it so you get redirected to the pages list?
It's important that I'm not editing core WP files (although easy, it's asking for trouble!) and doing this via a function.
This isn't any kind of front end log in, it's all backend just redirecting the standard WP login screen from the dashboard to the pages list - wp-admin/edit.php?post_type=page (as I don't like the info displayed on the dashboard).
Add this to your theme functions.php:
function my_login_redirect( $redirect_to, $request, $user ){
//is there a user to check?
global $user;
if( isset( $user->roles ) && is_array( $user->roles ) ) {
//check for admins
if( in_array( "administrator", $user->roles ) ) {
// redirect them to the default place
return home_url(); //admin redirect url
} else {
return admin_url( 'edit.php?post_type=page' ); //user redirect url
}
}
else {
return $redirect_to;
}
}
add_filter("login_redirect", "my_login_redirect", 10, 3);
This will redirect the user back to the homepage once logged in. With the above you can redirect administrators to a seperate location (dashboard if need be) and then the rest of your users to your custom url.

Wordpress re-direct if specific user is already logged in

I currently have two members areas set up within a site. If a user logs in, and then decides to browse around the general website, when they click on the 'Members Area' icon again I want that page to work out which user is logged in, and then re-direct them to the correct members area. If no user is logged in, it should display the log in form.
I currently have the following:
<?php
if ( $session->logged_in ) {
if ( $username == "user1" ) {
wp_redirect ( home_url("/members-area-1") );
exit; }
} elseif ( $username == "user2" ) {
wp_redirect ( home_url("/members-area-2") );
exit;
} else {
?>
Currently it doesnt re-direct, it just displays the login form regardless of which user I'm logged in as. Any suggestions on how to make this work correctly?
(Be gentle, I'm still fairly raw when it comes to wordpress and php dev)
Many thanks,
You may try this
if ( is_user_logged_in() )
{
global $current_user;
if( $current_user->user_login == 'user1' )
{
wp_redirect( home_url("/members-area-1") );
}
elseif( $current_user->user_login == 'user2' )
{
wp_redirect( home_url("/members-area-2") );
}
else
{
// logged in but doesn't match
}
}
See is user logged in() at codex.
Update: To solve the header sent warning issue you can add following code in your functions.php file to enable output buffering
add_action('init', 'buffer_start');
add_action('wp_footer', 'buffer_end');
function callback($buffer) { return $buffer; } // This is not necessury if you don't use callback argument in the ob_start function.
function buffer_start() { ob_start("callback"); }
function buffer_end() { ob_end_flush(); }

Categories