WordPress is deciding whether you are logged in or not by checking AUTH_COOKIE
and LOGGED_IN_COOKIE
. As you have noticed these cookies are set in the same, let,s say, A
domain which your site is. Adding the same cookies to your second B
domain would make your user logged in in two A
and B
domains. Of course setting cookie from domain A
for second B
domain would be an enormous security flaw so you must send cookie values from domain A
to domain B
and set these cookies in domain B
.
So this is what we have to do:
- read cookies
AUTH_COOKIE
and LOGGED_IN_COOKIE
on domain A
- send cookies
AUTH_COOKIE
and LOGGED_IN_COOKIE
from domain A
to domain B
- set cookies
AUTH_COOKIE
and LOGGED_IN_COOKIE
on domain B
To read cookies we have to use two filtes set_auth_cookie
and set_logged_in_cookie
. To set cookies on domain B
users browser must be on site B
so we need to redirect user from domain A
to domain B
with cookie values. Redirecting with GET
params is not an option, cookies are security sensitive, we must use POST
request. To redirect user and send cookies data with POST we can create simple html form with url pointed to domain B
. After user is redirected we can set cookies on domain B
and turn back user to domain A
.
I created working code for my implementation.
/**
* DOMAIN A PART PLUGIN
*/
class WPSE_287556_Send_Cookies {
/**
* Domain which user have to be redirected
*
* @var array
*/
private $domainB = 'example.com';
/**
* Array of cookies to send
*
* @var array
*/
private $cookies = array();
/**
* WPSE_287556_Send_Cookies constructor.
*/
public function __construct()
{
/**
* Define plugin related hooks
*/
$this->define_hooks();
}
/**
* Save auth and logged in cookies to array
*/
public function save_cookie( $cookie, $expire, $expiration, $user_id, $scheme, $token ) {
$this->cookies[] = $data = array(
'cookie' => $cookie,
'expire' => $expire,
'scheme' => $scheme,
);
}
/**
* Display redirect post form
*
* We should not redirect user with cookies in get parameters because this is
* no safe. We also can not redirect user with post parameters. We can create
* html post form and submit it with js.
*/
public function display_redirect_form( $redirect_to, $requested_redirect_to, $user ) {
if( is_array( $this->cookies ) && !empty( $this->cookies ) ):
$url = ( is_ssl() ) ? 'https://' : 'http://' . $this->domainB . '/';
?>
<form action="<?php echo esc_url( $url ); ?>" method="post" style="display: none;" id="post_redirect_form">
<input type="hidden" name="action" value="set_cookies" >
<?php foreach($this->cookies as $index => $cookie): ?>
<input type="hidden" name="cookies[<?php esc_attr_e( $index ); ?>][cookie]" value="<?php esc_attr_e( $cookie['cookie'] ); ?>" >
<input type="hidden" name="cookies[<?php esc_attr_e( $index ); ?>][expire]" value="<?php esc_attr_e( $cookie['expire'] ); ?>" >
<input type="hidden" name="cookies[<?php esc_attr_e( $index ); ?>][scheme]" value="<?php esc_attr_e( $cookie['scheme'] ); ?>" >
<?php endforeach; ?>
<input type="hidden" name="redirect_to" value="<?php esc_attr_e( $redirect_to ); ?>" >
</form>
<script> document.getElementById('post_redirect_form').submit(); </script>
<?php exit; ?>
<?php endif;
return $redirect_to;
}
/**
* Define plugin related hooks
*/
private function define_hooks() {
/**
* Save cookies hook
*/
add_action( 'set_auth_cookie', array($this, 'save_cookie'), 10, 6 );
add_action( 'set_logged_in_cookie', array($this, 'save_cookie'), 10, 6 );
/**
* Display redirect post form
*
* This filter is used to modify redirect url after login. There is no
* better place to modify page content after user login. Additionally
* we have access to $redirect_to url which we can use later.
*/
add_filter('login_redirect', array( $this, 'display_redirect_form' ), 10, 3);
}
}
new WPSE_287556_Send_Cookies();
/**
* END OF DOMAIN A PART PLUGIN
*/
/**
* DOMAIN B PART PLUGIN
*/
class WPSE_287556_Set_Cookies {
/**
* WPSE_287556_Set_Cookies constructor.
*/
public function __construct()
{
/**
* Define plugin related hooks
*/
$this->define_hooks();
}
/**
* Set auth and logged in cookies
*/
public function set_cookies() {
// Check if request is "set auth cookie" request
if( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['action'] ) && $_POST['action'] === 'set_cookies' ) {
$args = array(
'redirect_to' => FILTER_SANITIZE_URL,
'cookies' => array(
'filter' => FILTER_SANITIZE_STRING,
'flags' => FILTER_REQUIRE_ARRAY,
),
);
// Read and filter all post params
$post = filter_input_array(INPUT_POST, $args);
$redirect_to = $post['redirect_to'];
$cookies = $post['cookies'];
foreach( $cookies as $cookie_params ){
$scheme = $cookie_params['scheme'];
$cookie = $cookie_params['cookie'];
$expire = (int) $cookie_params['expire'];
// Decide which cookie to set
switch( $scheme ) {
case 'logged_in':
// Set logged in cookie, most of the code is from wp_set_auth_cookie function
setcookie( LOGGED_IN_COOKIE, $cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);
if ( COOKIEPATH != SITECOOKIEPATH )
setcookie(LOGGED_IN_COOKIE, $cookie, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);
break;
case 'secure_auth':
case 'auth':
// Set auth cookie, most of the code is from wp_set_auth_cookie function
if ( $scheme === 'secure_auth' ) {
$auth_cookie_name = SECURE_AUTH_COOKIE;
} else {
$auth_cookie_name = AUTH_COOKIE;
}
setcookie($auth_cookie_name, $cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, is_ssl(), true);
setcookie($auth_cookie_name, $cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, is_ssl(), true);
break;
}
}
// Redirect user to previous site
header( 'Location: ' . esc_url( $redirect_to ) );
exit;
}
}
/**
* Define plugin related hooks
*/
private function define_hooks() {
/**
* Set cookies from request
*/
add_action( 'init', array($this, 'set_cookies'));
}
}
new WPSE_287556_Set_Cookies();
/**
* END OF DOMAIN B PART PLUGIN
*/