我有两个WordPress站点,分别位于两个不同的子域,如test1.abc.com和test2.abc.com。两个站点都有wp需要激活的插件,只有登录的用户才能看到该站点。我们想建立一个系统,如果一个用户登录到一个网站,他应该自动登录到另一个网站。
我所尝试的:
经过一些搜索,我知道我需要为两个网站使用一个数据库。所以我做了以下步骤:
我已经下载了test2.abc.com站点的整个数据库,并将所有前缀wp_更改为wpmo_,将其替换为整个数据库,并将其上载到第一个站点的数据库中。
我在第二个站点的wp-config.php中添加了这两行,以定义第二个站点应该使用第一个站点的用户表,而不是它自己的用户表。
define('CUSTOM_USERMETA_TABLE', 'wp_usermeta');
define('CUSTOM_USER_TABLE', 'wp_users');
现在,第二个站点正在使用第一个站点的用户,我可以通过第一个站点的用户详细信息登录到第二个站点。
下一个问题是cookies,所以我在两个站点的wp config中添加了这些行。
define('COOKIE_DOMAIN', '.abc.com');
define('COOKIEPATH', '/');
define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');
现在我登录到test1.abc.com,当我转到test2.abc.com时,它会要求我登录。这意味着cookie不会从第一个站点传递到第二个站点。但是,我尝试打印$cookie,它给了我相同的加密值,但用户仍然没有在第二个站点上自动登录。当我回到第一个站点时,它会自动注销。我觉得这两个站点在cookies上有某种关联,我很接近,但仍然没有达到自动登录到第二个站点的目标。
有什么帮助吗?
解决方案:
在mik3lro和其他人的帮助下,我设法解决了这个问题。我将为所有面临同样问题的人发布解决方案。
您可以在这里找到这方面的分步指南:
步骤1:对两个安装使用一个数据库,在安装时间上使用两个不同的前缀安装2wp。
第2步:确保随机生成的密钥和盐在wp-config.php文件中也是相同的。
步骤3:将这两行粘贴到第二个站点的wp-config.php中。
//Share user tables
define('CUSTOM_USER_META_TABLE', 'SITE1_PREFIX_usermeta');
define('CUSTOM_USER_TABLE', 'SITE1_PREFIX_users');
步骤4:与这些行共享cookies。(同时写入wp config.php)
//Share cookies
define('COOKIE_DOMAIN', '.abc.com');
define('COOKIEHASH', 'aee53c017c29dc0d3ae37253fc8cbfd8');
步骤5:现在你可以在登录第一个站点时自动登录第二个站点。但是你会在第二个站点上出现一条错误消息“你没有访问此页面的权限”,这是一件好事。
第6步:原因是,wordpress检查用户功能(wp includes/capabilities.php),所以您可以直接在数据库中添加此功能(如果您只有很少的用户),或者为此编写一个插件。@mik3lro在评论中为此编写了一个插件,这很好。
谢谢
最佳答案
好吧-你已经很接近了,但是还有一些事情要做。
所有要求如下:
使用不同的前缀共享同一个数据库-您已经做到了。从这里我假设前缀是wp1_
,wp2_
等等。
共享wp1_users
和wp1_usermeta
表-您已经做到了这一点-实际上,如果您正确拼写常量名称,您将克服这一障碍…它是CUSTOM_USER_META_TABLE
(比您拥有的多一个下划线)
使用公共的COOKIE_DOMAIN
和COOKIEHASH
在子域之间共享cookie-您已经完成了
确保(正常情况下)随机生成的密钥和盐也是相同的-你不会写你已经这样做了,但从你的结果来看,我认为要么你有,要么你的密钥是空的(这不好,但会起作用)
确保sharedprefix_capabilities
表中每个站点的每个用户都有一个usermeta
条目-我不认为您已经这样做了,只是因为您还没有意识到这是必要的。
完整解决方案:
这进入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');
这足以让你登录这两个网站-但仍然有最后一个恼人的子弹留在名单上。
问题是,您的权限(“功能”)仅对其中一个站点有效,因为
meta_key
的前缀是站点的表前缀。如果你在google上搜索一下,你会发现很多建议修改wp-includes/capabilities.php
的解决方案,只使用一个公共前缀-我强烈建议不要这样做!(不是出于安全原因,而是因为每次更新后都需要进行此修补程序/黑客攻击…修改核心文件是非常糟糕的做法)为了解决这个问题,您需要复制
wp1_capabilities
表中的wp1_usermeta
行(对于每个用户!),给它一个新的umeta_id
并用wp1_
列中的wp2_
替换表前缀meta_key
。您需要为每个站点执行此操作,因此您有一行meta_key
wp1_capabilities
,一行wp2_capabilities
等等。如果你和你的一个朋友是唯一一个登录到这些网站的用户,那么只需通过phpmyadmin或其他工具手工完成——如果你需要它动态工作,那么使用一个小插件就可以实现自动化(见下面的编辑)。
我一直讨厌这种设计-表前缀在表行中没有任何意义!我认为多站点安装需要它,尽管我相信会有其他(更好的)方法来解决它…
更新:插件以保持所有站点之间的用户角色同步
这个简单的插件将复制并在创建或编辑用户时更新
usermeta
表中所需的行。值得注意的一点是,它可能不适用于多站点安装,因为它们具有一些特殊的功能/角色。我没有测试过这个。
它可能需要针对特定的用例进行改进(请做注释),但是对于我的有限的测试用例(只包括少数用户),它做得很好。对于一个拥有数千用户的网站来说,这将是低效的,但由于它只在用户被修改时运行,而且只有在需要时才进行更新,我怀疑这将是一个主要问题。但是,它应该相对容易适应只读取和修改刚刚添加/编辑的用户。不过,这会使初始设置稍微复杂一点,因为先前存在的用户在第一次运行时不会自动获得重复。
创建文件夹
wp-content/plugins/duplicate-caps
并将以下内容放入duplicate-caps.php
-不要忘记在wordpress admin的plugins
下激活。它需要安装在所有站点上。<?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'));
}
}
}
}
}
}