sharing user on 2 WordPress installs in 2 sub domains on same server

I have 2 WordPress sites in 2 different sub-domains like test1.abc.com and test2.abc.com . Both sites have wp-require plugin activated and only logged-in users can see the site. We want to make a system where if a user logged into one site, he should be auto-login into the other one.

What i try :

Read More

After some searching I know I need to use one database for both sites. So I have done these steps:

I have download the whole database of test2.abc.com site and change all prefix wp_ to wpmo_, replaced it in whole database and upload it into first site’s database.
I added these 2 lines in wp-config.php of the second site, to define that second site should use first site’s user table not its own.

define('CUSTOM_USERMETA_TABLE', 'wp_usermeta');
define('CUSTOM_USER_TABLE', 'wp_users');

Now, the second site is using the first site’s users and I am able to login to the second site by the user details of first site.

The next problem is cookies, so I added these lines in wp-config of both sites.

define('COOKIE_DOMAIN', '.abc.com');
define('COOKIEPATH', '/');
define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');

Now I logged in into test1.abc.com and when I go to test2.abc.com , it asks me to login. That means cookies are not passing from the first site to the second one. However, i tried to be print $_COOKIE and it gives me same encrypt values, but user still not auto login on second site. also when i came back to first site , it automatic logout. i feel like both sites are related somehow on cookies and i am close but still not reached to my goal of auto login into second site.

Any help?

Solution :

After some help from Mikk3lRo and others, i have managed to solve this issue. i am posting the solution for anyone who faces the same problem.
here you can find step by step guide for this :

step 1: use one database for both installations, install 2 wp by using 2 different prefix on installation time.

step 2: Make sure that the randomly generated secret keys and salts are also identical in both wp-config.php files.

step 3: paste these 2 lines in wp-config.php of second site.

//Share user tables
define('CUSTOM_USER_META_TABLE', 'SITE1_PREFIX_usermeta');
define('CUSTOM_USER_TABLE', 'SITE1_PREFIX_users');

step 4: share cookies with these lines . (write in both wp-config.php)

//Share cookies
define('COOKIE_DOMAIN', '.abc.com');
define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');

step 5: now you will be able to auto login in second site when logged into first site. but your will an error message on second site “you do not have permission to access this page”, which is a good thing.

step 6: The reason is, WordPress checks the user capability (wp-includes/capabilities.php) so either you have directly add this capability in database (in case you only have few users) or to write a plugin for this. @Mikk3lRo writes a plugin for this in comments, which is Good.

Thanks

Related posts

3 comments

  1. Alright – you are very close, but there are a few more things to be done.

    All requirements are as follows:

    • Share the same database, using different prefixes – you’ve done this. From here I assume the prefixes are wp1_, wp2_ and so on.
    • Share the wp1_users and wp1_usermeta tables – you’ve done this – and actually you would have overcome this obstacle if only you had spelled the constants name correctly… it’s CUSTOM_USER_META_TABLE (one more underscore than what you have)
    • Share cookies between the subdomains using a common COOKIE_DOMAIN and COOKIEHASH – you’ve done this
    • Make sure that the (normally) randomly generated secret keys and salts are also identical – you don’t write that you’ve done this, but judging by your results I think either you have or your keys are empty (which is not good, but will work)
    • Make sure there’s a prefix_capabilities entry for each user for each site in the shared usermeta table – I don’t think you’ve done this, simply because you haven’t yet reached the point where you realize it’s necessary.

    Complete solution:

    This goes in wp-config.php:

    //Share user tables
    define('CUSTOM_USER_META_TABLE', 'wp1_usermeta');
    define('CUSTOM_USER_TABLE', 'wp1_users');
    
    //Share cookies
    define('COOKIE_DOMAIN', '.abc.com');
    define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');
    
    /**
     * In my case these are not needed - but they may well be if one
     * of the installs is located in a sub-folder. I have not tested
     * this theory though.
     */
    //define('COOKIEPATH', '/');
    //define('SITECOOKIEPATH', '/');
    //define('ADMIN_COOKIE_PATH', '/wp-admin');
    
    //These all need to be identical
    define('AUTH_KEY', 'this should be random');
    define('SECURE_AUTH_KEY', 'this should also be a random string');
    define('LOGGED_IN_KEY', 'one more random string');
    define('AUTH_SALT', 'oh my - so many random strings');
    define('SECURE_AUTH_SALT', 'salt, salt, salt and no eggs');
    define('LOGGED_IN_SALT', 'this is sooooo random');
    
    /**
     * These do not need to be shared - in fact they probably shouldn't be
     * - if they are you could (in theory) do actions on one site that was
     * intended for the other - probably not a very big concern in reality
     */
    define('NONCE_KEY', 'these should be random too, but can differ');
    define('NONCE_SALT', 'one site has one, the other another');
    

    This is enough to get you logged in on both sites – but there’s still that last annoying bullet left on the list.

    The problem is that your permissions (“capabilities”) are only good on one of the sites because the meta_key is prefixed with the table prefix of the site. If you google around a bit you will find lots of solutions recommending to modify wp-includes/capabilities.php to just use a common prefix instead – I strongly recommend against that! (not for security reasons, but because you will need to make this patch / hack after every update… and it’s just insanely bad practice to modify core files)

    Instead to remedy this obstacle you need to duplicate the wp1_capabilities row in the wp1_usermeta table (for each user!), giving it a new umeta_id and substituting the table prefix wp1_ with wp2_ in the meta_key column. You need to do this for each site, so you have one row with meta_key wp1_capabilities, one with wp2_capabilities and so on.

    If you and a friend of yours are the only users who’ll ever log in to the sites, then just do it by hand through phpMyAdmin or something – if you need it to work dynamically, then it should be quite possible to automate with a small plugin (see edit below).

    I’ve always hated this design – a table prefix has no business inside a table row! I think it is needed for multisite installs, though I’m sure there would be other (better) ways to solve it…

    Update: Plugin to keep user roles synchronized between all sites

    This simple plugin will duplicate and keep the required rows in the usermeta table updated when users are created or edited.

    One thing worth noting is that it probably won’t work with multisite installs because they have some special capabilities / roles. I have not tested this.

    It may need refinement for specific use cases (please do comment), but it does the job fine for my limited test case that only includes a few users. It will be inefficient for a site with thousands of users, but as it only runs when a user is modified, and only does updates if they are needed I doubt this will be a major concern. However it should be relatively easy to adapt to only read and modify the user that was just added / edited. It would complicate initial setup a bit though, as pre-existing users would not automatically get duplicated on the first run.

    Create the folder wp-content/plugins/duplicate-caps and inside put the following in duplicate-caps.php – and don’t forget to activate under plugins in wordpress admin. It needs to be installed on all sites.

    <?php
    /*
    Plugin Name: Duplicate Caps
    Plugin URI: 
    Description: Tiny plugin to duplicate capabilities in a setup where users (and user tables) are shared across more than one install
    Author: Mikk3lRo
    Version: 0.1
    Author URI: 
    */
    $dummy = new duplicate_caps();
    class duplicate_caps {
        function __construct() {
            add_action('updated_user_meta', array($this, 'update_prefixed_caps'), 10, 2);
            add_action('added_user_meta', array($this, 'update_prefixed_caps'), 10, 2);
            add_action('deleted_user_meta', array($this, 'update_prefixed_caps'), 10, 2);
        }
        function update_prefixed_caps($mid, $object_id) {
            /**
             * Note that $object_id contains the id of the user that was
             * just changed.
             * On a site with many users it would make sense to only
             * get and set information regarding the just-changed user
             * Currently this function corrects roles for all users
             * making sure pre-existing users are duplicated, and keeping
             * the table in sync.
             */
            global $wpdb;
            //Quick and dirty - get all *capabilities rows for all users
            $sql = "SELECT * FROM {$wpdb->usermeta} WHERE `meta_key` LIKE '%capabilities'";
            $results = $wpdb->get_results($sql) or die(mysql_error());
    
            //Will hold all prefixes (always include our own)
            $prefixes = array($wpdb->prefix);
    
            //Will grab the existing role for each prefix
            $user_roles = array();
    
            //Loop our results
            foreach ($results as $result) {
                //Make sure the meta_key looks right, and grab the prefix
                if (preg_match('#^(.*)capabilities$#', $result->meta_key, $matches)) {
                    $prefix = $matches[1];
    
                    // Collect prefixes
                    $prefixes[] = $prefix;
    
                    //Note the entire row for later use
                    $user_roles[$result->user_id][$prefix] = $result;
                }
            }
    
            //Make sure we only have one of each
            $prefixes = array_unique($prefixes);
    
            //Loop through the users we found
            foreach ($user_roles as $user_id => $existing_prefixes) {
                if (!isset($existing_prefixes[$wpdb->prefix])) {
                    //User was probably just deleted - all rows are deleted by
                    //wordpress though, so no cleanup for us :)
                } else {
                    //We want all prefixes to obey us (we just created or changed
                    //the user, so we want that to affect all sites)
                    $desired_role = $existing_prefixes[$wpdb->prefix]->meta_value;
    
                    //Loop through all prefixes
                    foreach ($prefixes as $prefix) {
                        //Data to be inserted / updated
                        $cap_data = array(
                            'user_id' => $user_id,
                            'meta_key' => $prefix . 'capabilities',
                            'meta_value' => $desired_role
                        );
    
                        //If the prefix doesn't exist for this user
                        if (!in_array($prefix, array_keys($existing_prefixes))) {
                            //Actually insert it (user was probably just created)
                            $wpdb->insert($wpdb->usermeta, $cap_data, array('%d', '%s', '%s'));
                        } else if ($desired_role !== $existing_prefixes[$prefix]->meta_value) {
                            //Update it if not already correct (user was probably just edited)
                            $cap_data['umeta_id'] = $existing_prefixes[$prefix]->umeta_id;
                            $wpdb->replace($wpdb->usermeta, $cap_data, array('%d', '%s', '%s', '%d'));
                        }
                    }
                }
            }
        }
    }
    
  2. I believe the easiest solution for you would be to make use of one of WordPress’ single-sign on (SSO) plugins.

    There’s a large amount of plugins listed here.

    You could use one of them or base your authentication on one of them.

    Alternately there’s multi-site which will let you create a network of sites, if you decide to create a multi-site, then please read this first.

  3. I think define cookies is not enough to login to wp site.

    So my solution is, Create a plugin to restrict access to those who don’t login to one of the site.
    Set a cookie when user login to one of the site.
    when user view the site. check the cookie value, and redirect or return to the site.

    Sample Code:

     add_action('wp_login','prefix_set_cookie'); //when someone logged in this call the set_cookie function
    
     function prefix_set_cookie(){
        setcookie('hashed_cookie','my_value'); //set the cookie
    
     }
    
     //call check_cookie function when wordpress site loads
     add_action('wp','check_cookie');
    
     function check_cookie(){
        //check the cookie value and view the website
        if(isset($_COOKIE['hashed_cookie'] )){
            if($_COOKIE['hashed_cookie'] == 'my_value'){
             return;            
            }else{
                die("no access please login <a href='your login link'>LINK</a>");
            }
        }
     }
    

    Main drawback with this plugin is poor security. anyone create this cookie manually. so its high security one, don’t use this. try to hash the cookie as possible so it can’t easily created manually.

    ( if you want full code for the plugin ill put somewhere )

    Update (full plugin):

    <?php
    /*
    Plugin Name: Restrict Access
    Author: Pasindu Jayawardane
    Description: This Plugin Restrict Access to the Site without login
    Author URI: https://www.facebook.com/pj.pasiya
    */
    
     $key = hash('md5','restrict_access');
     $value = hash('md5','true');
    
     add_action('wp_login','es_set_cookie');
    
     function es_set_cookie(){
        global $key, $value;
    
        setcookie($key, $value ,time()+3600);
    
     }
    
     add_action('wp_logout','es_remove_cookie');
    
     function es_remove_cookie(){
        global $key, $value;
    
        setcookie($key, $value ,time()-3600);
     }
    
     add_action('wp','es_check_cookie');
    
     function es_check_cookie(){
        global $key, $value;
    
        if(isset($_COOKIE[$key] )){
            if($_COOKIE[$key] == $value){
             return;            
            }else{
                ?>
                <h1 class="alert alert-danger">
                    This Website is Protected! <small>You Must Login to See the Website</small>
                </h1>
                <p class="ra-login"> <a href="<?php echo wp_login_url(); ?>"> Login </a> <p>
            <?php
    
                die();
            }
        }else{
            ?>
            <h1 class="alert alert-danger">
                This Website is Protected! <small>You Must Login to See the Website</small>
            </h1>
            <p class="ra-login"> <a href="<?php echo wp_login_url(); ?>"> Login </a> <p>
            <?php
    
            die();
        }
     }
    

    go to your wordpress installation plugins directory ({{wp install folder}}->wp-content->plugins and make a new file with extension .php {{file-restrict.php}} copy and paste this code

    do this for both sites

    go to wordpress plugins and activate the plugin. (both sites)

    once you login to one of the site you can view either of site. and once you logout one site it gives a message with a link to login to the site.

    (after you activate just logout and login to the site)

    i’ll email the code for you too.

Comments are closed.