WordPress Multisite Não É Multi-Site: Arquitetura que Escala para 500 Localizações

WordPress Multisite soa como se você tivesse múltiplos sites. O que você realmente obtém é uma instalação WordPress que finge ser múltiplos sites adicionando um número na frente dos nomes de tabelas do banco de dados. Seu site principal usa wp_posts. Subsite 2 usa wp_2_posts. Subsite 3 usa wp_3_posts. Isso não é arquitetura multi-site. Isso é um banco de dados com cópias numeradas das mesmas tabelas. E tem consequências.

Já migrei redes com 15, 40, e uma vez 87 subsites para fora do WordPress Multisite. Todas as vezes, o cliente achava que estava recebendo sites independentes. Todas as vezes, descobriram da forma difícil que não estavam. Se você está executando uma franquia, um negócio multi-localização ou uma rede de departamentos universitários no WordPress Multisite, este artigo vai doer um pouco. Mas é melhor saber agora do que depois que o subsite #47 derruba todos os outros 46.

Índice

WordPress Multisite Não É Multi-Site: Arquitetura que Escala para 500 Localizações

O que o WordPress Multisite Realmente Faz nos Bastidores

Vamos ver o que acontece quando você habilita Multisite no WordPress. Você adiciona algumas linhas ao wp-config.php:

define('WP_ALLOW_MULTISITE', true);
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);
define('DOMAIN_CURRENT_SITE', 'example.com');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);

O WordPress então cria algumas tabelas em nível de rede (wp_blogs, wp_site, wp_sitemeta, wp_registration_log, wp_signups) e começa a duplicar sua estrutura de tabelas principais para cada novo subsite.

Aqui está o que o banco de dados parece após apenas 5 subsites:

wp_posts              (site principal)
wp_postmeta           (site principal)
wp_options            (site principal)
wp_users              (compartilhado - todos os sites)
wp_usermeta           (compartilhado - todos os sites)
wp_2_posts            (subsite 2)
wp_2_postmeta         (subsite 2)
wp_2_options          (subsite 2)
wp_3_posts            (subsite 3)
wp_3_postmeta         (subsite 3)
wp_3_options          (subsite 3)
...
wp_5_posts            (subsite 5)
wp_5_postmeta         (subsite 5)
wp_5_options          (subsite 5)

Cinco subsites e você já tem ~55 tabelas. Cinquenta subsites? Você está procurando por mais de 500 tabelas em um único banco de dados MySQL. Quinhentas localizações? Mais de 5.000 tabelas. Em um banco de dados. Compartilhando um pool de conexões.

Cada tabela tem seus próprios índices. Cada consulta visa uma tabela específica com prefixo. O planejador de consultas tem que lidar com tudo isso. E cada uma dessas tabelas é acessível para qualquer processo PHP executado nesse servidor, porque todas estão no mesmo banco de dados com as mesmas credenciais.

Isso não é arquitetura multi-site. Isso é uma convenção de nomenclatura se passando por isolamento.

As 7 Consequências da Arquitetura Multi-Site Falsa

1. Superfície de Vulnerabilidade Compartilhada

Cada subsite em uma rede WordPress Multisite executa o mesmo núcleo do WordPress, os mesmos plugins e os mesmos temas. Um exploit de plugin compromete todos os subsites porque compartilham a mesma base de código.

Isso não é teórico. Em fevereiro de 2026, WPVivid — um plugin de backup com mais de 900.000 instalações ativas — teve uma vulnerabilidade RCE (Remote Code Execution) de severidade 9.8 divulgada. Severidade 9.8 de 10. Isso é território "um atacante não autenticado pode executar código arbitrário em seu servidor".

Em um site WordPress independente, esse é um site comprometido. Em uma rede Multisite com 30 subsites? Isso são 30 sites comprometidos. Mesmo servidor. Mesmo banco de dados. Mesmo sistema de arquivos. Um exploit, compromisso total da rede.

Você não pode instalar uma versão diferente de um plugin no subsite #12 do que no subsite #13. Você não pode isolar os plugins de uma localização longe de outra. Cada site recebe a mesma superfície de ataque.

2. Multiplicação de Conflitos de Plugin

Em um site WordPress único, um conflito de plugin quebra um site. Você desativa o plugin, diagnostica, segue em frente. Irritante mas gerenciável.

No Multisite, um conflito de plugin ativado na rede quebra todos os sites simultaneamente. Já vi uma atualização WooCommerce em uma rede Multisite derrubar 23 páginas de localização ao mesmo tempo porque um plugin de cache ativado na rede não havia sido atualizado para os novos hooks do WooCommerce. Vinte e três localizações com páginas quebradas. Uma causa raiz, vinte e três gerentes de localização irritados ligando para a mesma pessoa.

E aqui está o problema — administradores de sites individuais geralmente não podem desativar plugins ativados na rede. Eles têm que esperar que o Super Admin corrija.

3. Degradação de Performance

Cinquenta subsites compartilhando uma instância MySQL. Cada carregamento de página no subsite #47 executa consultas como:

SELECT * FROM wp_47_posts WHERE post_type = 'page' AND post_status = 'publish';
SELECT option_value FROM wp_47_options WHERE option_name = 'active_plugins';
SELECT * FROM wp_47_postmeta WHERE post_id IN (142, 143, 144, 145);

Enquanto isso, o subsite #12 está executando seu próprio conjunto de consultas contra wp_12_posts, wp_12_options e wp_12_postmeta. E assim fazem todos os outros subsites, todos acessando a mesma instância MySQL.

O planejador de consultas do MySQL fica confuso. O cache de tabelas enche. Cada tabela com prefixo mantém seus próprios índices, mas o pool de buffer é compartilhado. A performance degrada não-linearmente conforme você adiciona subsites. Ir de 10 para 20 subsites não é o dobro da carga — pode ser três ou quatro vezes a carga dependendo dos padrões de tráfego, por causa da contenção de bloqueio e thrashing de pool de buffer.

Fiz benchmarks em uma rede de 40 subsites uma vez. O tempo médio de consulta no subsite #1 era 45ms. No momento em que testamos o subsite #38, o tempo médio de consulta havia subido para 380ms. Mesma estrutura de consulta. Mesmo volume de dados por site. O banco de dados estava apenas se afogando em tabelas.

4. Migração é um Pesadelo

Tente extrair o subsite #23 de uma rede de 50 sites em uma instalação WordPress independente. Aqui está o que você precisa fazer:

  1. Exportar todas as tabelas com prefixo wp_23_
  2. Remapear cada tabela de prefixo wp_23_ para wp_
  3. Resserializar todos os dados de opções e widgets (WordPress armazena PHP serializado no banco de dados, e os comprimentos de string mudam quando você muda prefixos)
  4. Remapear caminhos de mídia de /uploads/sites/23/ para /uploads/
  5. Buscar e substituir todos os URLs internos
  6. Remapear capacidades do usuário de wp_23_capabilities para wp_capabilities em wp_usermeta
  7. Extrair usuários da tabela wp_users compartilhada (apenas os que pertencem ao subsite #23)
  8. Recriar relacionamentos usuário-para-site

Um erro na serialização e você obtém dados corrompidos. Configurações de widgets desaparecem. Opções de customização de tema quebram. Estruturas de menu desaparecem. Fiz esse processo de extração dezenas de vezes, e demora 4-8 horas por subsite mesmo com ferramentas como WP Migrate DB Pro. Multiplique isso por 50 subsites se você estiver descomissionando uma rede.

O ecossistema WordPress tem ferramentas para isso, claro. Mas o fato de que essas ferramentas precisam existir diz algo sobre a arquitetura.

5. Sem Isolamento de Dados Verdadeiro

Este é o que deveria aterrorizá-lo se você se importa com segurança ou conformidade.

Uma vulnerabilidade de SQL injection no subsite #2 não expõe apenas wp_2_posts. O usuário do banco de dados conectando ao MySQL tem acesso a todas as tabelas no banco de dados. Isso significa wp_posts (site principal), wp_3_posts (subsite 3), wp_users (todos os usuários em todos os sites) e todas as outras tabelas.

Não há isolamento em nível de banco de dados. Sem segurança em nível de linha. Sem separação de schema. WordPress Multisite é um banco de dados, um conjunto de credenciais e uma convenção de nomenclatura. Isso é tudo.

Para negócios tratando dados de clientes em localizações — consultórios médicos, escritórios de advocacia, serviços financeiros — isso é um problema de conformidade. HIPAA, SOC 2 e PCI DSS todas têm requisitos em torno de isolamento de dados. "Nós usamos diferentes prefixos de tabela" não vai satisfazer um auditor.

6. Gargalo de Super Admin

WordPress Multisite tem um papel chamado Super Admin. Apenas o Super Admin pode:

  • Instalar ou deletar plugins
  • Instalar ou deletar temas
  • Ativar plugins em toda a rede
  • Adicionar novos sites à rede
  • Gerenciar configurações de rede

Administradores de sites individuais têm capacidades restritas. Eles não podem instalar seus próprios plugins. Eles não podem adicionar seus próprios temas. Toda mudança que toca a infraestrutura compartilhada passa por uma pessoa (ou um pequeno time).

Para uma rede de 3 sites, isso é fine. Para uma franquia de 50 localizações onde cada gerente de localização quer adicionar seu próprio widget de agendamento ou plugin de PDF de menu? É um gargalo que gera ressentimento e TI sombra.

7. Mapeamento de Domínio Frágil

Quer que cada localização tenha seu próprio domínio? denver.yourbrand.com ou yourbrand-denver.com? WordPress Multisite não lida com isso nativamente de forma confiável. Você precisa de uma solução de mapeamento de domínio, e a abordagem sunrise.php dropin nativa é notoriamente instável.

Certificados SSL para domínios mapeados adicionam outra camada. Configuração de DNS adiciona outro. Cada domínio mapeado é outro possível ponto de falha que seu Super Admin tem que gerenciar. Uma mudança de DNS, um certificado expirado, uma entrada de mapeamento mal configurada, e o site de uma localização cai.

Quando o WordPress Multisite Funciona (Honestamente)

Não vou fingir que é inútil. WordPress Multisite funciona bem em cenários específicos:

  • Redes pequenas (menos de 10 sites) onde todos os sites são gerenciados pelo mesmo time
  • Sites de departamento universitário onde o controle centralizado é realmente desejado
  • Espelhos de dev/staging/produção para o mesmo projeto
  • Redes de blogs onde isolamento de conteúdo não é crítico

Se você tem 5-8 sites, um sysadmin competente e não precisa de isolamento de dados entre sites — Multisite é fine. Os problemas começam quando você tenta escalá-lo para dezenas ou centenas de localizações.

WordPress Multisite Não É Multi-Site: Arquitetura que Escala para 500 Localizações - arquitetura

A Arquitetura que Realmente Escala para 500 Localizações

Aqui está a abordagem alternativa que usamos na Social Animal para negócios multi-localização: uma arquitetura headless com Next.js no frontend e Supabase (PostgreSQL) no backend, usando Row-Level Security (RLS) para verdadeiro isolamento de dados.

A ideia central: em vez de duplicar tabelas para cada localização, você tem um conjunto de tabelas com uma coluna location_id. Políticas de segurança em nível de banco de dados garantem que consultas apenas retornem dados para a localização autorizada. E em vez de 500 instalações WordPress separadas se fingindo de independentes, você tem uma implantação de aplicação onde /locations/[slug] renderiza dinamicamente a página de cada localização de uma linha de banco de dados.

Como Row-Level Security Realmente Funciona

-- Criar a tabela de localizações
CREATE TABLE locations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  slug TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  address TEXT,
  phone TEXT,
  hours JSONB,
  metadata JSONB,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- Criar a tabela de páginas com isolamento de localização
CREATE TABLE pages (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  location_id UUID REFERENCES locations(id),
  title TEXT NOT NULL,
  content JSONB,
  slug TEXT NOT NULL,
  published BOOLEAN DEFAULT false,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- Habilitar RLS
ALTER TABLE pages ENABLE ROW LEVEL SECURITY;

-- Política: gerentes de localização podem ver apenas as páginas de sua própria localização
CREATE POLICY "location_isolation" ON pages
  FOR ALL
  USING (location_id = (SELECT location_id FROM user_locations WHERE user_id = auth.uid()));

-- Política: público pode ler páginas publicadas para qualquer localização
CREATE POLICY "public_read" ON pages
  FOR SELECT
  USING (published = true);

Com essa configuração, um gerente de localização em Denver que de alguma forma elabore uma consulta maliciosa fisicamente não pode acessar dados de Austin. O banco de dados o impõe. Não a camada de aplicação. Não uma convenção de nomenclatura. O próprio banco de dados.

Comparação de Arquitetura: Tabelas com Prefixo vs Segurança em Nível de Linha

Aqui está uma representação visual das duas arquiteturas:

Arquitetura do WordPress Multisite:

┌─────────────────────────────────────────────┐
│         Banco de Dados MySQL Único           │
│                                             │
│  wp_posts          (site principal)         │
│  wp_options        (site principal)         │
│  wp_2_posts        (Denver)                 │
│  wp_2_options      (Denver)                 │
│  wp_3_posts        (Austin)                 │
│  wp_3_options      (Austin)                 │
│  wp_4_posts        (Seattle)                │
│  wp_4_options      (Seattle)                │
│  ... x 500 localizações = 5.000+ tabelas   │
│                                             │
│  ⚠️  UM conjunto de credenciais de BD        │
│  ⚠️  UM processo PHP acessa TODAS tabelas   │
│  ⚠️  ZERO isolamento em nível de BD          │
└─────────────────────────────────────────────┘

Arquitetura Next.js + Supabase:

┌─────────────────────────────────────────────┐
│      Banco de Dados PostgreSQL Único        │
│                                             │
│  locations    (500 linhas, uma por local)   │
│  pages        (conteúdo por localização)    │
│  media        (imagens por localização)     │
│  staff        (time por localização)        │
│  reviews      (avaliações por localização)  │
│                                             │
│  ✅ Políticas RLS impõem isolamento          │
│  ✅ Usuário de Denver NÃO PODE consultar Austin │
│  ✅ 5 tabelas total, não 5.000              │
│  ✅ Índices padrão, planos de consulta ideal │
└─────────────────────────────────────────────┘

Um banco de dados em ambos os casos. Mas o modelo de isolamento é fundamentalmente diferente. RLS é imposto no nível do engine PostgreSQL — não é algo que a aplicação pode contornar.

Fator WordPress Multisite Next.js + Supabase
Tabelas em 500 localizações ~5.500+ ~5-15
Isolamento de dados Nenhum (apenas convenção de nomenclatura) RLS imposto pelo banco de dados
Superfície de vulnerabilidade Um exploit = todos os sites Isolamento de autenticação por localização
Conflitos de plugin Indisponibilidade em toda a rede N/A (sem arquitetura de plugin)
Adicionar uma localização Criar subsite + configurar Inserir linha de banco de dados
Remover uma localização Processo de extração complexo Deletar linhas com CASCADE
Mapeamento de domínio Plugin necessário, frágil Rewrite de middleware, nativo
Tempo de build/deploy N/A (PHP em runtime) ~30s build incremental
TTFB (média, sem cache) 800ms-2s+ 50-150ms (edge)
Hospedagem mensal (500 sites) $200-800/mês (WordPress gerenciado) $25-75/mês (Supabase + Vercel)
Recuperação de compromisso Remediação de rede completa Girar chaves, redeploy

Implementação: Next.js + Supabase para Sites Multi-Localização

Aqui está como o roteamento funciona na prática com Next.js:

// app/locations/[slug]/page.tsx
import { createClient } from '@/lib/supabase/server';
import { notFound } from 'next/navigation';

export async function generateStaticParams() {
  const supabase = createClient();
  const { data: locations } = await supabase
    .from('locations')
    .select('slug');
  
  return locations?.map(({ slug }) => ({ slug })) ?? [];
}

export default async function LocationPage({ 
  params 
}: { 
  params: { slug: string } 
}) {
  const supabase = createClient();
  
  const { data: location } = await supabase
    .from('locations')
    .select(`
      *,
      pages(*),
      staff(*),
      reviews(*, rating)
    `)
    .eq('slug', params.slug)
    .single();
  
  if (!location) notFound();
  
  return (
    <div>
      <h1>{location.name}</h1>
      <LocationHero location={location} />
      <LocationServices pages={location.pages} />
      <LocationTeam staff={location.staff} />
      <LocationReviews reviews={location.reviews} />
    </div>
  );
}

Adicionar uma nova localização? Inserir uma linha:

INSERT INTO locations (slug, name, address, phone, hours)
VALUES (
  'portland-or',
  'Portland, OR',
  '123 Burnside St, Portland, OR 97209',
  '(503) 555-0142',
  '{"mon": "9-5", "tue": "9-5", "wed": "9-5"}'
);

Isso é tudo. O próximo build a pega. Ou se você estiver usando ISR (Incremental Static Regeneration), ela aparece dentro de sua janela de revalidação sem um build.

Remover uma localização? DELETE FROM locations WHERE slug = 'portland-or'; Deletes em cascata tratam o resto. Nenhum processo de extração de 4-8 horas.

Para domínios customizados por localização, middleware Next.js o trata de forma limpa:

// middleware.ts
import { NextResponse } from 'next/server';

const DOMAIN_MAP: Record<string, string> = {
  'yourbrand-denver.com': '/locations/denver-co',
  'yourbrand-austin.com': '/locations/austin-tx',
  // ... carregado de config de edge em produção
};

export function middleware(request: Request) {
  const hostname = new URL(request.url).hostname;
  const rewritePath = DOMAIN_MAP[hostname];
  
  if (rewritePath) {
    return NextResponse.rewrite(new URL(rewritePath, request.url));
  }
  
  return NextResponse.next();
}

Nenhum plugin. Nenhum sunrise.php dropin. Nenhuma tabela de mapeamento frágil. Apenas uma regra de rewrite na edge.

Caminho de Migração: Saindo do WordPress Multisite

Se você está atualmente no WordPress Multisite com 20+ localizações, aqui está o caminho realista de migração:

Fase 1: Exportação de Dados (1-2 semanas)

Extrair conteúdo de cada subsite usando a API REST do WordPress ou WP-CLI. Não tente remapear manualmente tabelas com prefixo. Use a API — ela abstrai o pesadelo do prefixo.

# Exportar todos os posts do subsite 23
wp post list --url=example.com/location-23 --format=json > location-23-posts.json

# Exportar toda a mídia
wp media list --url=example.com/location-23 --format=json > location-23-media.json

Fase 2: Design de Schema (1 semana)

Design seu schema Supabase em torno de seu modelo de conteúdo real, não do modelo post/postmeta do WordPress. Este é o momento para corrigir anos de débito de modelo de dados acumulado.

Fase 3: Migração de Conteúdo (1-2 semanas)

Escrever scripts de migração que transformam conteúdo WordPress em seu novo schema. Lidar com dados serializados, shortcodes e blocos Gutenberg.

Fase 4: Build do Frontend (3-4 semanas)

Construir o frontend Next.js. É aqui que você vê os ganhos reais de performance. Páginas que demoravam 1.5 segundos no WordPress agora carregam em menos de 200ms.

Fase 5: Cutover de DNS (1 dia)

Apontar seus domínios para a nova infraestrutura. Manter a rede antiga em execução como backup somente leitura por 30 dias.

Para negócios que precisam de ajuda com esse processo de migração, documentamos nossa abordagem na página headless CMS development. Fizemos migrações suficientes para saber onde os cadáveres estão enterrados.

Números Reais: Comparação de Performance e Custo

Aqui estão dados de uma migração real que completamos em Q1 2025 — uma rede de consultório dentário com 34 localizações:

Métrica WordPress Multisite (Antes) Next.js + Supabase (Depois)
TTFB médio 1.240ms 89ms
Largest Contentful Paint 3.8s 1.1s
Custo mensal de hospedagem $347/mês (WP Engine) $45/mês (Vercel Pro + Supabase Pro)
Tempo para adicionar nova localização 2-3 horas (setup manual) 15 minutos (inserir linha + conteúdo)
Tempo para atualizar todas as localizações Atualização de plugin + esperança git push
Taxa de aprovação de Core Web Vitals 12 de 34 localizações 34 de 34 localizações
Incidentes de segurança (12 meses) 3 0

A redução de custo de hospedagem sozinha pagou pela migração em 8 meses. As melhorias de performance levaram a aumentos mensuráveis em rankings de busca local para 28 das 34 localizações dentro de 90 dias.

Se você está avaliando custos para sua própria rede, nossa página pricing tem breakdowns transparentes para projetos multi-localização.

Perguntas Frequentes

WordPress Multisite é bom para gerenciar múltiplas localizações? Para um pequeno número de localizações (menos de 10) com gerenciamento centralizado, WordPress Multisite pode funcionar. Mas não foi designed para negócios multi-localização que precisam de operação independente, isolamento de dados ou alta performance em escala. A arquitetura de banco de dados compartilhado cria problemas de segurança, performance e operacionais que pioram com cada localização que você adiciona.

Quais são os maiores problemas com WordPress Multisite? Os sete grandes problemas são: superfície de vulnerabilidade compartilhada (um exploit atinge todos os sites), multiplicação de conflitos de plugin (um conflito derruba cada site), degradação de performance não-linear, processos de migração/extração pesadelos, zero isolamento de dados em nível de banco de dados, gargalo de Super Admin para todas as mudanças administrativas e mapeamento de domínio frágil. Esses problemas são arquiteturais — não podem ser corrigidos com plugins ou melhor hospedagem.

WordPress Multisite pode lidar com 100+ sites? Tecnicamente, sim. Praticamente, fica muito doloroso após 30-50 sites. Em 100 sites você está lidando com 1.100+ tabelas de banco de dados em uma única instância MySQL, severa degradação de planejador de consultas e complexidade operacional que requer staff dedicado de DevOps. Em 500 sites, é um não-iniciador para a maioria dos ambientes de hospedagem.

Qual é a melhor alternativa ao WordPress Multisite para múltiplas localizações? Uma arquitetura headless usando Next.js ou Astro para o frontend com um banco de dados PostgreSQL (como Supabase) usando Row-Level Security fornece verdadeiro isolamento de dados, performance dramaticamente melhor, custos de hospedagem mais baixos e gerenciamento trivial de localização. Cada localização é uma linha de banco de dados, não uma instalação WordPress inteira.

Como você migra do WordPress Multisite para uma arquitetura headless? A abordagem mais segura é extrair conteúdo via API REST do WordPress ou WP-CLI em vez de tentar remapear manualmente tabelas de banco de dados com prefixo. Exportar conteúdo por subsite, design um schema limpo em seu banco de dados alvo, escrever scripts de transformação, construir o novo frontend e cortar DNS. Planejar por 6-10 semanas total para uma rede com 20+ sites.

WordPress Multisite afeta SEO? Indiretamente, sim. A degradação de performance do WordPress Multisite leva a carregamento mais lento de páginas, o que prejudica scores de Core Web Vitals. Google confirmou que sinais de page experience influenciam rankings. Em nossos dados de migração, 82% das localizações viram melhoria em rankings de busca local dentro de 90 dias de mudança para uma arquitetura headless com TTFB sub-200ms.

WordPress Multisite é seguro para dados de negócio? Não, se você define segurança como incluindo isolamento de dados entre localizações. WordPress Multisite usa um banco de dados com um conjunto de credenciais. Um SQL injection em qualquer subsite pode acessar dados de cada outro subsite. Para negócios sujeitos a HIPAA, SOC 2, PCI DSS ou requerimentos de conformidade similares, a falta de isolamento em nível de banco de dados é uma responsabilidade significativa.

Quanto custa executar WordPress Multisite vs uma alternativa headless? Hospedagem WordPress gerenciada para Multisite típicamente custa $200-800/mês dependendo do número de sites e níveis de tráfego (os planos Multisite da WP Engine começam em $240/mês para seu tier Growth em 2025). Uma configuração headless comparável em Vercel Pro ($20/mês) mais Supabase Pro ($25/mês) lida com o mesmo tráfego por uma fração do custo. O investimento inicial de build é maior para a abordagem headless, mas custos operacionais mensais são significativamente mais baixos. Sinta-se livre para contact se você quer uma comparação de custo específico para seu tamanho de rede.