I'm creating a module in Drupal to keep the users synchronised between the Drupal site (old) and a Wordpress site (new). The sites were created separately, the WP site does not has its own domain, it is installed in a subfolder and the users can only access it using a link in the Drupal site. So the task is always in the Drupal->Wordpress direcction, create a user in Drupal -> create it in Wordpress, login a user to Drupal -> Log in the user in Wordpress.
I created a Drupal hook mymodule_user_insert() which basically takes the registered $account variable and makes a POST with it to the WP site, the WP plugin that receives the object creates a WP user with the same email and password and then calls the WP function to generate the WP_logged_in_cookie (basically authenticates the user), this cookie is returned in the POST response headers.
I use the the Drupal function drupal_http_request() to make the post and capture the response and headers, as only generating the cookie in the WP site did not make the user auto login in WP I used a variation of the code in http://forumone.com/insights/proxying-cookies-drupal/ which gets the cookies from the POST response headers and sets them in the Drupal module.
// sends a newly created user information to the wordpress site to keep it up to date
function mymodule_user_insert(&$edit, $account, $category) {
// export users server url
global $base_url;
$url = $base_url.'/wpsubfolder/wp-admin/admin-ajax.php';
// collect data and set action
$data = array();
$data['action'] = 'wp_plugin_create_user';
$data['username'] = $account->name;
$data['email'] = $account->mail;
$data['password'] = $account->pass;
$data['referer'] = $base_url;
// send POST request
$response = drupal_http_request($url, array(
'method' => 'POST',
'data' => http_build_query($data),
'max_redirects' => 0,
'headers' => array('Content-Type' => 'application/x-www-form-urlencoded')
)
);
// get cookies from headers and set them here
if (200 == $response->code) {
foreach ($response->headers as $key => $value) {
if (strcasecmp($key, 'set-cookie') == 0) {
drupal_add_http_header($key, $value);
}
}
// report any errors
} elseif(isset($response->error)) {
drupal_set_message(t($response->data), 'error');
}
return $response->data;
}
This works just fine, every time you create an account in the Drupal site it creates it in both sites and if you got to WP or Drupal you are already logged in both.
I moved then to create the Drupal hook mymodule_user_login() with almost the same code, with the difference that POST to a different function in the WP plugin which does not have the create_user code it just checks if the email exists and then authenticates the user creating the same cookie as before.
// Captures login information and sends post request to wp to login user
function mymodule_user_login(&$edit, $account) {
// was login successfull
if (user_is_logged_in()) {
// export users server url
global $base_url;
$url = $base_url.'/wpsubfolder/wp-admin/admin-ajax.php';
// collect data and set action
$data = array();
$data['action'] = 'wp_plugin_login_user';
$data['username'] = $account->name;
$data['email'] = $account->mail;
$data['password'] = $account->pass;
$data['referer'] = $base_url;
// send POST request
$response = drupal_http_request($url, array(
'method' => 'POST',
'data' => http_build_query($data),
'max_redirects' => 0,
'headers' => array('Content-Type' => 'application/x-www-form-urlencoded')
)
);
// get cookies from headers
if (200 == $response->code) {
foreach ($response->headers as $key => $value) {
if ($key == 'set-cookie') {
$cookies = preg_split('/(?<=\S),(?:\S)/', $value);
// ADD WORDPRESS COOKIE BUT NOT DRUPAL TO AVOID OVERRIDING IT
foreach ($cookies as $cookie) {
// is wordpres cookie
if(strpos($cookie, 'wordpress') !== false) {
drupal_add_http_header($key, $value);
// other cookies, ignore drupal session cookie as it's already set
} elseif(strpos($cookie, 'SESS') === 0) {
// Send separately since drupal_add_http_header concatenates with commas
header($key . ': ' . $cookie, FALSE);
}
}
}
}
} elseif(isset($response->error)) {
// report any errors
drupal_set_message(t($response->data), 'error');
}
}
}
The problem comes when receiving the headers back in the drupal login hook function, for some reason I end up logged in to WP but not in Drupal, but if I don't set the WP cookie in the Drupal headers when I receive them, the user is logged in and redirected normally to his account, but again the WP user is not automatically logged in.
As you can see in the code I thought that maybe I was overwriting the Drupal session cookie so I added a condition to ignore any cookie that started with the SESS prefix, but even like that it still does not work.
Is there a step I'm missing or is there an easier way to log a user that exists in both databases in both sites at the same time?