Here's how I'd handle it (mostly you're right, and the tweak in your answer to use init
gets you closer, but — as you've discovered — doing a bunch of switch_to_blog()
/ restore_current_blog()
calls on every single page load is costly).
function add_opportunities_capability_to_admins() {
// Set up the needed capabilities.
$capabilities = array(
'edit_opportunity',
'read_opportunity',
'delete_opportunity',
'edit_opportunities',
'read_opportunities',
'delete_opportunities',
'edit_others_opportunities',
'publish_opportunities',
'read_private_opportunities',
'delete_private_opportunities',
'delete_published_opportunities',
'delete_others_opportunities',
'edit_private_opportunities',
'edit_published_opportunities',
);
$sites = get_sites();
// Gets the current state of affairs.
$current_permission_state = md5( json_encode( array( $capabilities, $sites ) ) );
$last_saved_permission_state = get_site_option( 'my_permission_state', '' );
// If things have changed, we re-run the permission updates.
if ( $current_permission_state !== $last_saved_permission_state ) {
foreach ($sites as $site) {
switch_to_blog($site->blog_id);
$admins = get_users(array('role' => 'administrator', 'exclude' => array(get_current_user_id())));
foreach ($admins as $admin) {
if (!is_super_admin($admin->ID)) {
foreach ( $capabilities as $capability ) {
$admin->add_cap( $capability );
}
}
}
restore_current_blog();
}
// Save the current state so we don't have to run this again for a while.
update_site_option( 'my_permission_state', $current_permission_state );
}
}
add_action('init', 'add_opportunities_capability_to_admins');
Note: This code is untested. Try it on a test site before putting it into production.