How to Create and Manage Multiple WordPress Subsites in Bulk

on in Blog, WordPress
Last modified on

WordPress Multisite

My latest project involved a WordPress Multisite installation and 20+ subsites. As the websites were the same, both from a functional point of view and a design point of view, I needed to automate a few tasks: creating the subsites, assigning a default theme, and assigning an admin user.

Let’s break each of the the tasks down.

Table of Contents

The function below will loop through an array of titles and create the subsites (as subfolders, not subdomains). Note that, if you use the code, you need to replace the network ID (1 in most cases) and the admin email address.

How to create multiple WordPress subsites in bulk, programmatically

Only run the code below once!

Note that the slugs of the subsites will be the sanitized site titles. For example, “Lunar Landing Properties” will be example.com/lunar-landing-properties/.

function create_subsites_in_bulk() {
    // Define an array of site titles to be used when creating subsites.
    $site_titles = [
        'Starlight Ventures',
        'Ocean Breeze Realty',
        'Lunar Landing Properties',
        'Aurora Estates',
        'Silverleaf Homes',
        'Golden Horizon Realty',
        'Skyline Abodes',
        'Whispering Pines Properties',
        'Serenity Shores Realty',
        'Majestic Peaks Estates',
        'Sunset Valley Homes',
        'Crystal Cove Realty',
        'Meadowbrook Residences',
        'Harborview Estates',
        'Crescent Moon Realty',
        'Radiant Ridge Homes',
        'Willow Creek Realty',
        'Echo Ridge Estates',
    ];

    $network_id = 1; // Network ID for the WordPress Multisite.
    
    // Get the user by their email. Replace with your super-admin email if necessary.
    $user = get_user_by( 'email', 'user@example.com' );
    $user_id = $user->ID; // Get the user ID of the retrieved user.

    // Loop through each site title in the array.
    foreach ( $site_titles as $title ) {
        $slug = sanitize_title( $title ); // Create a URL-friendly slug from the site title.
        $domain = $_SERVER['HTTP_HOST']; // Use the current domain automatically.
        $path = '/' . $slug . '/'; // Set the path for the subsite.

        // Check if the site already exists on the domain with the given path.
        if ( ! domain_exists( $domain, $path, $network_id ) ) {
            // Create the new subsite and capture the site ID.
            $site_id = wpmu_create_blog( $domain, $path, $title, $user_id, [], $network_id );

            // Check if there was an error during site creation.
            if ( is_wp_error( $site_id ) ) {
                // Output the error message if site creation failed.
                echo 'Error creating site: ' . $title . ' - ' . $site_id->get_error_message() . '<br>';
            } else {
                // Output a success message with the created site ID.
                echo 'Created site: ' . $title . ' with ID: ' . $site_id . '<br>';
            }
        } else {
            // Output a message if the site already exists.
            echo 'Site already exists: ' . $title . '<br>';
        }
    }
}

// Hook the function to run during the admin_init action.
add_action( 'admin_init', 'create_subsites_in_bulk' );

After creating all the subsites, I decided I wanted a specific theme as default.

I completely forgot about the wp-config.php constant, which allows all new subsites to inherit and enable a theme:

define( 'WP_DEFAULT_THEME', 'whiskey' );

My options were to either delete all websites, define the constant and run the function again, or, make my life harder and code something. Which I did.

How to assign a default WordPress Multisite theme and enable it

The code below can be run multiple times, although running it once will do the job.

The key elements of all WordPress Multisite ⇄ Subsite interactions are:

switch_to_blog( $site_id )

Switch the current context to a different site, basically making the code believe they are running on that specific site ID.

And:

restore_current_blog()

Restore the context to the main/network site (or wherever the code was run from).

function switch_all_multisite_themes() {
    // Retrieve an array of all sites in the multisite network.
    $sites = get_sites();

    // Loop through each site to switch themes.
    foreach ( $sites as $site ) {
        // Switch context to the current site by its blog ID.
        $switched = switch_to_blog( $site->blog_id );

        // Check if switching to the site was successful.
        if ( ! $switched ) {
            echo 'Failed to switch to site ' . $site->blog_id . '<br>';
            continue; // Skip to the next site if switching failed.
        }

        try {
            // Clear the cache for the current site to ensure fresh data.
            wp_cache_flush();

            // Check if the desired theme exists and is valid.
            $theme = wp_get_theme( 'whiskey' );

            if ( $theme->exists() ) {
                // Switch to the desired theme.
                switch_theme( 'whiskey' );
            } else {
                echo 'Theme "whiskey" does not exist on site ' . $site->blog_id . '<br>';
            }
        } catch ( Exception $e ) {
            // Handle any exceptions that occur during the theme switch process.
            echo 'Error switching theme on site ' . $site->blog_id . ': ' . $e->getMessage() . '<br>';
        }

        // Restore the original site context after processing the current site.
        restore_current_blog();
    }
}

// Call the function to switch themes on all sites.
switch_all_multisite_themes();

How to assign a WordPress admin user

Next, because I created all my subsites programmatically, they have no users. So, I wrote some code to assign myself (a super-admin) as an admin user on all websites. Again, we need to switch to each site/blog, run a function, then restore the context.

Make sure you use an existing email address in your network. I used my own.

function assign_user_to_all_subsites() {
    // Retrieve the user object by email. Replace with a generic email placeholder for privacy.
    $user = get_user_by( 'email', 'user@example.com' );
    
    // Get the user's ID.
    $user_id = $user->ID;

    // Define the role to assign to the user on all subsites.
    $role = 'administrator'; 
    
    // Retrieve an array of all sites in the multisite network.
    $sites = get_sites();

    // Loop through each site to assign the user.
    foreach ( $sites as $site ) {
        $blog_id = $site->blog_id; // Get the blog ID of the current site.

        // Switch context to the current site.
        switch_to_blog( $blog_id );

        // Add the user to the current site with the specified role.
        add_user_to_blog( $blog_id, $user_id, $role );

        // Restore the original site context after processing the current site.
        restore_current_blog();
    }

    // Output a confirmation message indicating that the user has been assigned to all subsites.
    echo '</div>User ID ' . $user_id . ' has been assigned as an administrator to all subsites.</div>';
}

// Hook the function to run during the admin_init action.
add_action( 'admin_init', 'assign_user_to_all_subsites' );

Putting these function together in a small plugin, and building a settings page, could result in a nice, useful plugin.

On a related note, Felix Arntz open-sourced his collection of useful WordPress Multisite snippets.

Related posts

Leave a Reply

Your email address will not be published. Required fields are marked *