In multisite, there’s one set of themes shared across the whole network. On top of that, how do you build “a shared look” and “per-site differences”? There are two design options.
- Option A: a shared parent theme plus a child theme per site—when the differences are large
- Option B: branching inside a single theme—when the differences are just colors and some wording
Choose based on how many sites there are and how big the differences get.
Distributing themes (network enabling)
wp-content/themes/
├── mynet-base/ ← the shared parent theme
├── mynet-shop/ ← a child theme (Template: mynet-base)
└── mynet-school/ ← a child theme (Template: mynet-base)- Network Admin → “Themes” → “Network Enable” puts it among every site’s options
- To let only one site use it, go to “Sites” → edit that site → the “Themes” tab and enable it individually
The parent theme doesn’t need network enabling (activating a child theme uses the parent automatically). Distributing only the child themes prevents each site’s administrator from accidentally picking the parent.
TipsHow to set up WordPress multisiteHow to set up multisite itselfOption A: a parent theme plus per-site child themes
The shared skeleton lives in the parent, with each site’s look and differences in the child.
/*
Theme Name: MyNet Shop
Template: mynet-base
Version: 1.0.0
*/
:root {
--color-primary: #e8618c; /* this site's color only */
}<?php
add_action('wp_enqueue_scripts', function () {
wp_enqueue_style('parent-style', get_parent_theme_file_uri('style.css'), [], '1.0.0');
});Templates with matching names are overridden by the child, and functions.php is loaded from both. That behavior is the same under multisite.
When it fits—layouts and template structures differ between sites, five sites or fewer, different people adjusting each design.
When it hurts—more than ten sites (ten child themes, and every shared fix means checking all of them).
Option B: branching inside a single theme
When the differences amount to colors, logos and wording, keeping one theme and branching inside it is easier to maintain.
<?php
/** Hold each site's settings in one place */
function mynet_site_config() {
$path = trim(get_blog_details()->path, '/'); // e.g. 'shop'
$config = [
'shop' => ['color' => '#e8618c', 'label' => 'Online shop'],
'school' => ['color' => '#3d7ea6', 'label' => 'School'],
];
return $config[$path] ?? ['color' => '#333333', 'label' => get_bloginfo('name')];
}
/** Output the color as a CSS variable */
add_action('wp_head', function () {
$c = mynet_site_config();
echo '<style>:root{--color-primary:' . esc_attr($c['color']) . ';}</style>';
});The trick is to collect the settings into a single array. Adding a site is then one more line in that array.
TipsIdentifying the current child site by slug in multisiteHow to tell which site you’re on (slug, ID, domain)Applying per-site CSS (adding a class to body)
A handy trick under either option.
<?php
add_filter('body_class', function ($classes) {
if (is_multisite()) {
$path = trim(get_blog_details()->path, '/');
$classes[] = 'site-' . ($path !== '' ? sanitize_html_class($path) : 'main');
$classes[] = 'site-id-' . get_current_blog_id();
}
return $classes;
});.site-shop .site-header { background: var(--color-primary); }
.site-school .site-header { background: #3d7ea6; }
.site-main .hero { min-height: 70vh; }You can express per-site differences inside a single CSS file, so you can adjust things without adding child themes.
TipsWordPress conditional tags cheat sheetHow filters like body_class work is covered in the hooks articleSwapping shared parts per site
Mixing the site slug into a template part’s name lets you give one site a different part.
<?php
$slug = trim(get_blog_details()->path, '/');
// use parts/header-shop.php if it exists, otherwise parts/header.php
get_template_part('parts/header', $slug ?: null);
?>get_template_part('parts/header', 'shop') looks for parts/header-shop.php and falls back to parts/header.php when it’s missing. Using that mechanism, you swap parts without writing conditionals.
Holding network-wide settings in one place
Values like “show the same company details in every site’s footer” can live in network-wide options.
<?php
// shared across the network (the same value from any site)
update_site_option('mynet_company_tel', '+1 555-0123');
echo esc_html(get_site_option('mynet_company_tel'));
// per site (an ordinary option)
update_option('mynet_catch', 'Welcome');
echo esc_html(get_option('mynet_catch'));
?>get_site_option() is network-wide, get_option() is that site only. Choosing between those two matters a lot when building themes for multisite.
Which option should you pick?
| Option A: separate child themes | Option B: one theme with branching | |
|---|---|---|
| Suits how many sites | Up to 5 | 5 or more |
| Size of the differences | Layouts differ | Colors, logos, wording |
| Effort for a shared fix | Check every child theme | One place |
| Effort to add a site | Build a child theme | One line in an array |
| Freedom per maintainer | High | Low (but consistent) |
Summary
- Themes are one shared set across the network. Distribute them by network enabling or enabling per site
- Big differences call for a parent plus child themes; colors and wording call for one theme plus a settings array
- Adding the site slug to
body_classlets one CSS file cover per-site adjustments - Shared values go in
get_site_option(), site-specific values inget_option()
Deciding up front how much stays shared gives you a structure that holds up as sites are added.