Multisite - це той самий WordPress, у якому константа MULTISITE = true вмикає вибір префікса таблиць за поточним доменом і шляхом. Сайт з ID 2 працює з wp_2_posts і wp_2_options, сайт 3 - зі своїми. Спільними лишаються wp_users, wp_usermeta й мережевий шар: wp_blogs зі списком сайтів, wp_sitemeta з налаштуваннями мережі, wp_blogmeta (зʼявилась у WP 5.0). Акаунт при цьому один, а контент роздільний: той самий редактор може мати роль на трьох сайтах і не мати доступу до четвертого, бо приналежність визначає ключ wp_{id}_capabilities в usermeta.
Плагіни й теми в мережі одні фізично. Каталог wp-content/plugins спільний, і покласти туди щось може лише super admin: у Multisite map_meta_cap знімає install_plugins, edit_plugins і update_themes навіть з адміністратора сайту. Режимів активації два - network activate вмикає плагін одразу всюди, звичайна активація діє на конкретному сайті, а is_plugin_active_for_network() дозволяє коду відрізнити ці випадки. Тема стає доступною сайту лише після network enable. Заради цього мережі здебільшого й будують: 40 сайтів обласних філій оновлюються одним wp plugin update --all, а не сорока.
Тип доменів обирають один раз. SUBDOMAIN_INSTALL фіксується під час Network Setup: піддомени вимагають wildcard у DNS, у vhost і в сертифікаті, підтеки не вимагають нічого, зате конфліктують зі слагами вже наявних сторінок. Змінити тип пізніше означає правку констант плюс масовий апдейт domain і path у wp_blogs з редиректами, тобто повноцінну міграцію. Власні домени ядро підтримує з WP 4.5 без сторонніх плагінів: у wp_blogs.domain пишеться будь-який домен, і мережа на нього відповідає; sunrise.php лишився для нестандартної логіки резолву. Наскрізний логін діє в межах одного COOKIE_DOMAIN, тож для мережі з різних доменів SSO доводиться робити окремо.
Зворотний бік мережі - спільна доля. Версія ядра одна на всіх, оновлення плагіна прилітає всім одночасно, fatal error у network-activated плагіні гасить усі сайти. RCE на одному сайті відкриває файлову систему й базу цілої мережі, тому «розділимо клієнтів по сайтах заради ізоляції» - хибна ідея. Бекап знімається цілою базою, а витягнути один сайт означає вибрати його таблиці через wp db tables --url=..., забрати wp-content/uploads/sites/{id} і розібратися зі спільною wp_users. Масштаб додає своє: кожен сайт це близько 12 таблиць, тисяча сайтів - десятки тисяч файлів на диску й повільні дампи, а wp_is_large_network() від 10 000 сайтів або користувачів вимикає підрахунок статистики на льоту.
Multisite виправданий, коли сайти однакові за стеком, належать одному власнику, обслуговуються однією командою й ділять реліз-цикл: мовні версії корпоративного сайту, кафедри університету, міські лендінги франшизи, site-per-customer у продукті, де кодом керуєте ви самі. Окремі інсталяції кращі, коли клієнт може забрати свій сайт, коли комусь потрібні свої плагіни або заморожена версія, коли трафік асиметричний і масштабувати треба один сайт, коли є вимога ізолювати дані. А якщо єдиний аргумент за мережу - спільний логін, дешевше поставити SSO над окремими сайтами, ніж звʼязати їх однією базою назавжди.
// Мережеві налаштування живуть у wp_sitemeta, а не в опціях сайту
update_site_option('acme_license_key', $key); // одна на всю мережу
$key = get_site_option('acme_license_key');
update_option('acme_theme_accent', '#0a5'); // тільки поточний сайт
// Новий сайт у мережі: хук wp_initialize_site (WP 5.1+), не wpmu_new_blog
add_action('wp_initialize_site', function (WP_Site $site): void {
switch_to_blog((int) $site->blog_id);
acme_install_tables(); // dbDelta для таблиць саме цього сайту
restore_current_blog();
}, 20);
// Збір даних по мережі: get_sites(), а не прямий SELECT з wp_blogs
$latest = [];
foreach (get_sites(['number' => 100, 'archived' => 0, 'deleted' => 0]) as $site) {
switch_to_blog((int) $site->blog_id);
// кожен switch скидає кеш опцій і додає запити,
// тому такий цикл місце має в cron, а не в рендері сторінки
$latest[$site->blog_id] = get_posts(['numberposts' => 3, 'fields' => 'ids']);
restore_current_blog(); // парність обовʼязкова, інакше $wpdb лишиться чужим
}
set_site_transient('acme_network_latest', $latest, HOUR_IN_SECONDS);
// Права після switch_to_blog самі не перемикаються
$user = wp_get_current_user();
$canEditOnSite5 = $user->for_site(5)->has_cap('edit_posts'); // WP 4.9+
$user->for_site(get_current_blog_id()); // повертаємо контекст
Сформулюйте критерій одним реченням: Multisite - це один деплой, одна база й один власник. Щойно комусь із сайтів потрібен свій реліз-цикл, свій набір плагінів або своя відповідальність за дані, вигода мережі зникає, а вартість лишається.