TLDR
user_roles
option is broken, it can be fixed by updating the db, see the solution below.
Who & Why
I was able to recreate your issue and analyze it. As you can see in the error it is clearly a matter of permissions and capabilities, and it turns out that the whole thing is because wp_xx_user_roles option.
When avoiding the regular registration process, as you are trying to do, the globals $wpdb
and $wp_roles
are already exist, and when you use wpmu_create_blog
from within your site, the very-important option wp_xx_user_roles
(the xx is for the blog id) is written with the current viewed blog id, and not the new one just created.
My guess is that when creating a new blog from the registration page, wordpress is not considering any blog to be the current blog, so when it uses a brand new wp_roles class instance, instead of using the already-set globals $wpdb
and $wp_roles
;
I couldn’t find any civil way to address this issue, so we’ll do it ugly.
The ugly solution is to update the blog id in user_roles
option name after creating a new blog, like so:
function replace_wrong_user_roles_option( $new_blog_id ){
global $wpdb, $wp_roles;
$current_blog_id = get_current_blog_id();
if( $current_blog_id == $new_blog_id )
return true;
$prefix_length = strlen( $wpdb->prefix );
$blog_prefix_length = strlen( $new_blog_id.'_' );
$blog_prefix_position = strrpos ( $current_prefix, $new_blog_id.'_' );
// only on new wpmu, when main blog prefix is without the blog_id
if($current_blog_id == 1 && !$blog_prefix_position){
$new_blog_prefix = $wpdb->prefix.$new_blog_id.'_';
}else{
$new_blog_prefix = str_replace(get_current_blog_id(), $new_blog_id, $wpdb->prefix);
}
return $wpdb->update(
$new_blog_prefix.'options',
array( 'option_name' => $new_blog_prefix.'user_roles' ),
array( 'option_name' => $wpdb->prefix.'user_roles' )
);
}
And you can insert that function call right after you create your blog:
$new_blog_id = wpmu_create_blog( $newdomain, $path, $title, $user_id, $meta, get_current_network_id() );
replace_wrong_user_roles_option( $new_blog_id );
add_user_to_blog($new_blog_id, get_current_user_id(), 'my_custom_role');
$blog = get_blog_details($new_blog_id,true);
$blog_url = $blog->siteurl;
$redirect_url = $blog_url . '/wp-admin';
wp_redirect( add_query_arg(array(
'custom_notice' => 'a_custom_notice'
),$redirect_url));