This is my experience.
I had to add role for each site in WordPress, I developed an add page in dashboard so the site administrator can add the self-defined role/capabilities.
But I found the $wp_roles->add_role
, add_cap
only works the subsite. So I did some fix,
I’ve made a plugin, the super-admin(not site administrator but the “admin”) can “Network Activate” in dashboard
xxx/wp-admin/network/plugins.php
the self-defined role/capabilities was saved in role.ini
file, the plugin can create two table named wp_s_role
and wp_s_cap
, The pre-self-defined role/capabilities will insert into the table.
Then the $wp_roles->add_rol
e and add_cap
can across the network and insert the role/capabilities to all subsites.
But the subsite administrator must add the self-defined role/capabilities and make it works in all subsites, so I create a trigger for
register_activation_hook(__FILE__, array($s_role, 'install'));
register_deactivation_hook(__FILE__, array($s_role, 'uninstall'));
Then the uninstall function works, all the two tables data will be saved into the role.ini
file again, after that, the install function will works again. and all self-defined role/capabilities was added into all subsites.
As you see, I made a trigger in order to add the self-defined role into all subsites, but the effectivity is very low, the plugin restart will take more than 5 seconds. So I’ve improve the methods, This time, when the add_role function is done, I copied the subsite role/capabilities into the others subsites.
Some steps:
-
In subsites, when the administrator add the role, I use
$blog_id
and$table_prefix
to get a subsite tablewp_2_options
contents. (We assumed the blog_id is2
and the table_prefix iswp
). -
I select the
option_name=wp_2_user_roles
result($wpdb->get_row("select `option_value` from `wp_2_options` where `option_name`='wp_2_user_roles'", ARRAY_A);),
then I foreach
the blogs and get the subsite table. So I insert the select result into each subsite table(wp_n_options
) and the main table(wp_options
), muhaha, am I smart enough? : )
The below function is how to remove the self-defined roles in all subsites. I think it’s would helpful with you.
public function reset_subsite_role_cap()
{
//select * from `wp_options` where `option_name` = 'wp_user_roles';
//select * from `wp_options` where `option_name` = 'wp_backup_user_roles';
//select * from `wp_3_options` where `option_name` = 'wp_3_user_roles';
//select * from `wp_4_options` where `option_name` = 'wp_4_user_roles';
//select * from `wp_5_options` where `option_name` = 'wp_5_user_roles';
global $wpdb;
$sql = "select * from ".$wpdb->blogs;
$multisite_info = $wpdb->get_results($sql, ARRAY_A);
$site_result = array();
if (!empty($multisite_info) && is_array($multisite_info)) {
foreach ($multisite_info as $k => $v) {
$site_result[$v['blog_id']] = trim($v['path'], "https://wordpress.stackexchange.com/");
}
}
global $table_prefix;
$tp_arr = explode('_', $table_prefix);
$table_arr = array();
foreach ($site_result as $blog_id => $site_name) {
if ($blog_id !== 1) {
$table_arr[$tp_arr[0].'_'.$blog_id.'_options'] = $tp_arr[0].'_'.$blog_id.'_user_roles';
} else {
$table_arr[$tp_arr[0].'_options'] = $tp_arr[0].'_user_roles';
}
}
// get the backup user roles.
$backup_roles_result = $wpdb->get_row("select `option_value` from `".$tp_arr[0]."_options` where `option_name`='wp_backup_user_roles'", ARRAY_A);
// clean the others role cap
if (isset($table_arr) && is_array($table_arr)) {
foreach ($table_arr as $table_role_cap_name => $table_role_cap_filed) {
$wpdb->update(
$table_role_cap_name,
array('option_value' => $backup_roles_result['option_value']),
array('option_name' => $table_role_cap_filed)
);
}
}
return true;
}
For the $site_result, I have another function to fetch all exact site info.
/**
* Get the all site info.
*
* @param integer $id BlogID.
*
* @return array array('blog_id' => 'path', '1' => 'printsolv', '2' => 'govsolv')
*/
public function s_get_multisite_info($id = null)
{
global $wpdb;
$where="1=1";
if (isset($id)) {
$sql = "select * from ".$wpdb->blogs." where `blog_id`="."'".$id."'";
} else {
$sql = "select * from ".$wpdb->blogs." where 1=1 ";
}
$multisite_info = $wpdb->get_results($sql, ARRAY_A);
$result = array();
if (!empty($multisite_info) && is_array($multisite_info)) {
// clean the path, > 1 means not http://site_name/theme.php but http://site_name/path_name/theme.php
if (isset($id)) {
$site_info = $wpdb->get_row("select * from ".$wpdb->site." where `id`="."'".$multisite_info[0]['site_id']."'", ARRAY_A);
} else {
$site_info = $wpdb->get_row("select * from ".$wpdb->site, ARRAY_A);
}
$site_path_status = false; // path= /
if (isset($site_info['path']) && strlen(trim($site_info['path'], "https://wordpress.stackexchange.com/")) > 1 ) {
// site have path./xxx/
$site_path_status = true;
}
foreach ($multisite_info as $k => $v) {
if (isset($site_info['domain']) && $site_info['domain'] == $v['domain']) {
if ($site_path_status == true) {
$result[$v['blog_id']] = trim(substr($v['path'], strlen(trim($site_info['path'], "https://wordpress.stackexchange.com/")) + 1), "https://wordpress.stackexchange.com/");
} else {
$result[$v['blog_id']] = trim($v['path'], "https://wordpress.stackexchange.com/");
}
}
}
}
return $result;
}
I have just finished the function and it works perfectly. You can use s_copy_site_role_cap() to call. The function can copy the role into others subsite roles after you add_role. Because the plugin might works in main site or subsite, there will have two ways in network(subdomain, subpath) , so i made another function to get the right current blog_name , so I can get the lastest roles contents from the blog_name information.
/**
* Copy the subsite role/caps to all subsites and main site..
*
* @param string $subsite_name SubSite Name.
*
* @return boolean.
*/
public function s_copy_site_role_cap()
{
global $wpdb;
// Get all site info
$multisite_info = $this->s_get_multisite_info();
global $table_prefix;
$tp_arr = explode('_', $table_prefix);
// Get all site wp_x_options table. and table filed.
$table_arr = array();
foreach ($multisite_info as $blog_id => $site_name) {
if ($blog_id !== 1) {
$table_arr[$tp_arr[0].'_'.$blog_id.'_options'] = $tp_arr[0].'_'.$blog_id.'_user_roles';
} else {
$table_arr[$tp_arr[0].'_options'] = $tp_arr[0].'_user_roles';
}
}
// select the blog id by blog name.
$subsite_name = $this->s_get_dashboard_site_name();
$subsite_id = array_search($subsite_name, $multisite_info);
if ($subsite_id === false) {
return false;
}
$current_site_table_pre = $tp_arr[0].'_'.$subsite_id;
// get the current subsite roles.
$subsite_roles = $wpdb->get_row("select `option_value` from `".$current_site_table_pre."_options` where `option_name`='".$current_site_table_pre."_user_roles'", ARRAY_A);
if (isset($table_arr) && is_array($table_arr)) {
foreach ($table_arr as $table_role_cap_name => $table_role_cap_filed) {
if ($table_role_cap_name != $current_site_table_pre.'_options') {
$wpdb->update(
$table_role_cap_name,
array('option_value' => $subsite_roles['option_value']),
array('option_name' => $table_role_cap_filed)
);
}
}
}
return true;
}
/**
* Get dashboard site name.
*
* @return string. SiteName
*/
public function s_get_dashboard_site_name()
{
$dashboard_url = admin_url();
//$dashboard_url = "http://xxx/wp-admin/";
//$dashboard_url = "http://subsite_name.xxx/wp-admin/";
//$dashboard_url = "http://xxx/subsite_name/wp-admin/";
// get main site name.
$site_name = get_current_site()->domain;
$parse_url = parse_url($dashboard_url);
if (!is_subdomain_install()) {
// base path http://xxx/wp-admin/
// subsite path http://xxx/subsite_name/wp-admin/
if ($parse_url['path'] == "/wp-admin/") {
return $site_name;
} else {
$tmp_url = explode("https://wordpress.stackexchange.com/", trim($parse_url['path'], "https://wordpress.stackexchange.com/"));
return $tmp_url[0];
}
} else {
// base domain http://xxx/wp-admin/
// subsite domain http://subsite_name.xxx/wp-admin/
if ($parse_url['host'] == $site_name) {
return $site_name;
} else {
$tmp_url = explode(".", $parse_url['host']);
return $tmp_url[0];
}
}
}
Thanks.