WordPress admin bar tweaks for extremely large networks

WordPress multisite is an awesome tool, but has its limitations and caveats, ESPECIALLY when you’re dealing with very large networks. At WebDevStudios, we use this snippet to prevent the ‘My Sites’ menu from querying every site on the network for which the user is a member. This isn’t so bad for a small network, or for users which are members of only a few blogs/sites, but if you have a Super Admin who is a member of most, if not all, the sites, you’ll definitely want this snippet.

<?php

/**
 * Loading all sites menu for large multisite
 * is inefficient and bad news
 */
function large_network_remove_wp_admin_bar_my_sites_menu() {
    remove_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );
}
add_action( 'add_admin_bar_menus', 'large_network_remove_wp_admin_bar_my_sites_menu' );

/**
 * Let's replace that menu with one that has
 * links to the network dashboard instead.
 */
function large_network_replacement_my_sites_menu( $wp_admin_bar ) {
    if ( ! current_user_can( 'manage_network' ) ) {
        // bail.. no network menu for you!
        return;
    }
    
    $wp_admin_bar->add_menu( array(
        'id'    => 'prefix-my-sites',
        'title' => __( 'My Sites' ),
        'href'  => admin_url( 'my-sites.php' ),
    ));

    $wp_admin_bar->add_menu( array(
        'id'    => 'prefix-network-admin',
        'parent' => 'prefix-my-sites',
        'title' => __( 'Network Dashboard' ),
        'href'  => network_admin_url(),
    ));

    $wp_admin_bar->add_menu( array(
        'id'    => 'prefix-network-sites',
        'parent' => 'prefix-my-sites',
        'title' => __( 'Network Sites' ),
        'href'  => network_admin_url( 'sites.php' ),
    ));

    $wp_admin_bar->add_menu( array(
        'id'    => 'prefix-network-users',
        'parent' => 'prefix-my-sites',
        'title' => __( 'Network Users' ),
        'href'  => network_admin_url( 'users.php' ),
    ));
}
add_action( 'admin_bar_menu', 'large_network_replacement_my_sites_menu', 20 );

Thanks to Brad Parbs for the replacement menu snippet.

UPDATE: There are still a few performance concerns when a WordPress user is logged in and a member of many sites (like in the thousands). I created a new ticket on WordPress trac, and hopefully it gets some momentum, but until then, Sergey Biryukov provided me with a useful snippet which helps with the issue of super-admins being a ‘member’ of thousands of sites.

<?php 
/**
 * Remove all site capability keys when retrieving user meta
 * This prevents `get_blog_details` lookups for all the sites
 * a super admin is a member or admin
 *
 * @link  https://core.trac.wordpress.org/ticket/31746#comment:1 get_blogs_of_user() can be very slow when a user is a member of thousands of sites
 */
function large_network_skip_get_blogs_of_user_with_many_sites( $null, $object_id, $meta_key ) {
    global $wpdb;

    // Don't proceed if fetching a specific meta key, or the current user is not a super admin
    if ( $meta_key || ! is_super_admin() ) {
        return $null;
    }

    // Ok, then fetch all the user meta (remove this filter to do so)
    remove_filter( 'get_user_metadata', __FUNCTION__, 10, 4 );
    $keys = get_user_meta( $object_id );
    add_filter( 'get_user_metadata', __FUNCTION__, 10, 4 );

    // And loop through them
    foreach ( $keys as $key => $value ) {
        // Ignore non-capability meta keys
        if ( 'capabilities' !== substr( $key, -12 ) ) {
            continue;
        }

        // Ignore meta keys w/o the base_prefix
        if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) ) {
            continue;
        }

        // Attempt to get the blog id from the string
        $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );

        // If it's not numeric, ignore this too
        if ( ! is_numeric( $blog_id ) ) {
            continue;
        }

        // Ok, let's black-list this capability meta from being sent back
        unset( $keys[ $key ] );
    }

    return $keys;
}
add_filter( 'get_user_metadata', 'large_network_skip_get_blogs_of_user_with_many_sites', 10, 3 );

2 Comments on “WordPress admin bar tweaks for extremely large networks

  1. Does HTML5 SlideShow Presentations support embedded HTML — such as embedding code for a YouTube video? I teach and use PowerPoint but want to get away from PPT, and like what I see in your product, But my presentations use a good amount of web content that I embed using HTML in the Text tab of WordPress. Can this be done?

Comment