
🔄 WordPress in una sottocartella: come spostare l'installazione dalla radice e viceversa
Una situazione familiare: imposti un sito di sviluppo, costruisci il tema, colleghi i contenuti tramite WP Migrate DB Pro e, dopo il push, scopri stili rotti, immagini mancanti e un wp-admin non funzionante. Il motivo è quasi sempre lo stesso: il sito di produzione risiede nella root mentre quello di sviluppo è in una sottodirectory (o viceversa), e un semplice search-replace degli URL nel database non corregge questa differenza.
Il problema è più profondo di quanto appaia: in un'installazione nella root, WordPress usa lo stesso dominio per tutti i link (sia alle pagine sia ai file media). In un'installazione in sottodirectory, i link ai contenuti provengono dall'indirizzo del sito, mentre i link alle risorse (css, js, immagini) provengono dall'indirizzo di WordPress. Un search-replace standard sul database sostituisce tutto in modo uniforme e rompe metà dei percorsi.
In questa guida troverai due rotte di migrazione comprovate (andata e ritorno) con impostazioni specifiche di search-replace, preparazione del file wp-config.php e la corretta sequenza di trasferimento dei file. Dopo la lettura, potrai uniformare sviluppo e produzione allo stesso schema oppure eseguire consapevolmente una migrazione tra tipi di installazione diversi senza rompere il frontend.
💡 Panoramica rapida:
- Determina il tuo tipo di installazione: verifica se "Indirizzo WordPress" e "Indirizzo sito" coincidono in Impostazioni → Generali
- Per migrare da sottodirectory a root: imposta in modo fisso WP_SITEURL in wp-config, esegui una sostituzione di
/subdir→/nel database, sposta i file al livello superiore, aggiorna il file index.php della root - Per migrare da root a sottodirectory: sostituisci solo i percorsi di
/wp-contentnel database, aggiorna l'indirizzo WordPress nelle impostazioni, crea la sottodirectory, copia index.php e .htaccess nella root - Dopo ogni migrazione, vai su Impostazioni → Permalink e clicca "Salva": questo ricostruisce la struttura degli URL e svuota la cache
Come determinare dove è installato WordPress
Se hai installato WordPress manualmente, probabilmente ricordi se era nella root del dominio o in una sottodirectory come /wp o /blog. Ma se il sito è stato ereditato da uno sviluppatore precedente, distribuito dal provider di hosting con un clic, o sono passati diversi anni, i dettagli si affievoliscono.
Il modo più rapido: vai nell'amministrazione di WordPress, apri Impostazioni → Generali e guarda i campi "Indirizzo WordPress (URL)" e "Indirizzo sito (URL)". Se i valori coincidono, hai un'installazione nella root:

Se i campi sono diversi, WordPress è installato in una sottodirectory (nell'esempio sotto, è /subdir):

Un segno aggiuntivo di un'installazione in sottodirectory: quando accedi all'amministrazione, l'URL contiene una sottodirectory, ad esempio example.com/wp/wp-admin/ invece di example.com/wp-admin/.
Perché non puoi semplicemente trasferire in modo diretto
La radice del problema sta nel doppio sistema di URL che WordPress utilizza con le installazioni in sottodirectory. Analizziamolo con esempi concreti.
Supponi di avere un'installazione nella root su example.com. Assolutamente tutti i link nel database, sia a un articolo /2025/about-page sia a un'immagine /wp-content/uploads/photo.jpg, iniziano con //example.com. Un search-replace standard //example.local → //example.com funziona perfettamente.
Ora prendi un'installazione nella sottodirectory /wp. Il link allo stesso articolo appare come //example.com/about-page (tramite l'indirizzo del sito), mentre il link alla stessa immagine è //example.com/wp/wp-content/uploads/photo.jpg (tramite l'indirizzo WordPress con la sottodirectory). Una semplice sostituzione //example.local → //example.com romperà i file media: il sistema li cercherà senza /wp nel percorso e otterrà un 404.
La tabella sotto mostra quali gruppi di URL devono essere aggiornati in ciascuna direzione di migrazione:
Direzione | URL di pagine e articoli | URL di media e risorse | Percorsi file nel database |
|---|---|---|---|
Sottodirectory → root | Sostituisci | Sostituisci | Sostituisci |
Root → sottodirectory | Lascia invariato | Sostituisci | Sostituisci |
Oltre al database, devi spostare fisicamente i file e aggiornare index.php nella root, altrimenti WordPress non troverà wp-blog-header.php. Vediamo ora entrambe le procedure passo dopo passo.
Metodo 1: spostare WordPress da una sottodirectory alla root
Questa è la direzione più semplice: rimuovi la sottodirectory dai percorsi e tutti gli URL diventano «piatti», come in un'installazione standard.
Passo 0: diagnosticare cosa andrà storto
Prima di intervenire, è utile vedere con i propri occhi la portata del problema. Lo screenshot qui sotto mostra le impostazioni di migrazione da wp-in-a-subdirectory.local (WordPress in /subdir) a wp-standard-install.local (installazione nella root). Le impostazioni di WP Migrate DB Pro sono quelle standard, più una sostituzione del titolo del sito a scopo dimostrativo:

Il risultato è prevedibilmente desolante: le pagine si aprono ma senza stili e con immagini non funzionanti:

Nell'HTML puoi vedere i link alle risorse con un percorso /subdir inesistente che sul server di destinazione non c'è più. Provando ad accedere a wp-admin si viene reindirizzati a wp-standard-install.local/subdir/wp-login.php, ma quel file non esiste. Ora sistemiamo la situazione.
Passo 1: preparazione
Per prima cosa, proteggi l'accesso all'amministrazione durante la migrazione. Aggiungi a wp-config.php delle costanti che sovrascriveranno le impostazioni del database, così WordPress continuerà a farti entrare in admin tramite il vecchio percorso con la sottodirectory, anche dopo aver pulito il database:
1 define( 'WP_SITEURL', 'http://wp-in-a-subdirectory.local/subdir' ); 2 define( 'WP_HOME', 'http://wp-in-a-subdirectory.local' );
Poi metti il sito in modalità manutenzione: modifica index.php nella root pubblica, commenta la riga require( dirname( __FILE__ )... e dopo il tag di chiusura ?> inserisci un segnaposto html con un breve messaggio di fermo temporaneo. I visitatori vedranno questo:

Nel frattempo, tu continui ad accedere all'admin su http://wp-in-a-subdirectory.local/subdir/wp-admin/ perché la costante WP_SITEURL è attiva.
Passo 2: cerca e sostituisci nel database
Ora pulisci il database. Esegui un cerca-sostituisci con queste coppie (mostrate nell'interfaccia di WP Migrate DB Pro, ma lo stesso principio vale con search-replace di WP-CLI o con query SQL via phpMyAdmin):
//wp-in-a-subdirectory.local/subdir→//wp-in-a-subdirectory.local/app/public/subdir→/app/public(percorso file sul server)

Subito dopo la migrazione, l'aspetto non cambierà (la pagina di manutenzione è ancora attiva, l'admin funziona tramite la costante hardcoded). Ma se guardi il contenuto dei post, le immagini non vengono ancora caricate e i link interni hanno «perso» la sottodirectory, che è esattamente ciò che volevamo in questa fase:

Step 3: trasferimento fisico dei file
Rimuovi (o commenta) le righe con WP_SITEURL e WP_HOME da wp-config.php. L'admin ora smetterà di funzionare, quindi sposta immediatamente i file dalla sottodirectory al livello superiore.
Via SSH o riga di comando sul server, si fa con tre comandi:
1 rm index.php && mv subdir/* . && rm -rf subdir
Via FTP o file manager dell'hosting, trascina tutto il contenuto della sottodirectory nella root pubblica, sostituendo index.php:

Fatto. Il sito si apre all'URL root; immagini e stili sono al loro posto:

Tocco finale: vai nell'admin (ora su http://wp-in-a-subdirectory.local/wp-admin senza la sottodirectory), apri Impostazioni → Permalink e clicca «Salva modifiche», anche se non hai cambiato nulla. WordPress ricostruirà la struttura degli URL e svuoterà la cache.
Metodo 2: spostare WordPress dalla root a una sottodirectory
Molti sviluppatori considerano installare WordPress in una sottodirectory una buona pratica: i file core non affollano la root, la gestione tramite Git/Composer è semplificata e il dominio stesso può essere usato per altre applicazioni. Ma migrare un sito esistente in una sottodirectory è oggettivamente più complesso del contrario, perché ora alcuni link DEVONO mantenere la sottodirectory mentre altri no.
Fase 0: diagnostica
Stesso punto di partenza: proviamo una migrazione standard dall'installazione nella root wp-standard-install.local all'installazione in sottodirectory wp-in-a-subdirectory.local (WordPress in /subdir):

Il risultato è del tutto prevedibile: le pagine si aprono ma fogli di stile e immagini si rompono perché /subdir non è stato aggiunto ai loro percorsi:

A differenza del primo scenario, i link a post e pagine funzionano correttamente (non devono contenere la sottodirectory). A rompersi sono specificamente le risorse (css, js, media), i cui percorsi ora devono includere /subdir.
Fase 1: preparazione
In questa fase, NON impostiamo le costanti WP_SITEURL e WP_HOME, perché il nostro search-replace non toccherà questi valori e aggiorneremo l'indirizzo WordPress manualmente poco dopo.
Impostate la pagina di manutenzione allo stesso modo: commentate require(...) in index.php e aggiungete un placeholder html. I visitatori vedono il messaggio di manutenzione mentre voi continuate ad accedere all'admin su http://wp-standard-install.local/wp-admin/.
Fase 2: search-replace selettivo nel database
La differenza chiave rispetto al primo metodo: sostituiamo SOLO i percorsi di file e risorse, SENZA toccare gli URL delle pagine. Per farlo, mirate la sostituzione usando il pattern /wp-content:
//wp-standard-install.local/wp-content→//wp-standard-install.local/subdir/wp-content/app/public→/app/public/subdir(percorso sul server)

Dopo la migrazione, verificate il contenuto dei post: i link ad altre pagine del sito NON contengono la sottodirectory (corretto), mentre le immagini incorporate la contengono (anch'esso corretto):

Fase 3: aggiornamento dell'indirizzo WordPress e spostamento dei file
Ora andate su Impostazioni → Generali e aggiungete la sottodirectory in fondo a "Indirizzo WordPress (URL)", ad esempio http://wp-standard-install.local/subdir. Subito dopo aver salvato, l'admin si romperà perché WordPress cercherà i file nel nuovo percorso, ma non sono ancora lì:

Create la sottodirectory subdir nella root pubblica e spostateci dentro TUTTI i file di WordPress. Poi copiate index.php e .htaccess INDIETRO nella root, così la pagina di manutenzione continua a essere visualizzata mentre finite:

Ripristinate index.php ALL'INTERNO della sottodirectory al suo stato originale: rimuovete il placeholder html e decommentate la riga require:
1 <?php 2 define( 'WP_USE_THEMES', true ); 3 require( dirname( __FILE__ ) . '/wp-blog-header.php' );
Ora l'admin è di nuovo accessibile su http://wp-standard-install.local/subdir/wp-admin/:

Verificate i contenuti: le immagini sono al loro posto, gli stili vengono caricati:

Tocco finale: index.php nella root
Non resta che aggiornare index.php nella root pubblica. Rimuovete la pagina di manutenzione e specificate il percorso corretto di wp-blog-header.php tenendo conto della sottodirectory:
1 <?php 2 define( 'WP_USE_THEMES', true ); 3 require( dirname( __FILE__ ) . '/subdir/wp-blog-header.php' );
Il sito si apre all'URL root con tutte le risorse caricate dalla sottodirectory:

Di nuovo, andate su Impostazioni → Permalink e salvate senza modifiche, così WordPress aggiorna la struttura degli URL.
Strumenti alternativi e il metodo ufficiale
L'approccio descritto sopra con WP Migrate DB Pro è comodo ma non è l'unica opzione. Ecco altri strumenti con cui potete lavorare:
*WP-CLI
search-replace.* Il comandowp search-replace '//oldsite.local/subdir' '//newsite.com'con il flag--dry-runmostrerà prima quante occorrenze verranno sostituite. Per una sostituzione selettiva (root → sottodirectory), restringete il pattern:wp search-replace '//newsite.com/wp-content' '//newsite.com/subdir/wp-content'.Metodo ufficiale di WordPress. La documentazione su developer.wordpress.org descrive la procedura "Dare a WordPress una propria directory", con configurazioni dettagliate per Apache (.htaccess), nginx (server block) e IIS (web.config). Il metodo non richiede plugin e funziona su qualsiasi hosting.
SQL manuale. Se il volume delle modifiche è ridotto, potete eseguire
UPDATE wp_posts SET post_content = REPLACE(post_content, '/subdir/', '/')direttamente in phpMyAdmin, ma sempre con un backup preventivo, perché una sostituzione del genere distruggerà i dati serializzati in wp_options e wp_postmeta.
Qualunque strumento scegliate, la regola è la stessa: quando migrate ROOT → SOTTODIRECTORY, sostituite solo /wp-content e i percorsi dei file; quando migrate SOTTODIRECTORY → ROOT, sostituite tutto ciò che fa riferimento alla sottodirectory.
⁉️🤔 Domande frequenti
WP Migrate DB Pro è obbligatorio per questo tipo di migrazione?
No. WP Migrate DB Pro offre semplicemente un'interfaccia comoda per il search-replace con comprensione dei dati serializzati PHP. Tecnicamente, potete eseguire le stesse sostituzioni via WP-CLI (anche il comando
wp search-replacegestisce correttamente le stringhe serializzate) o usare il metodo ufficiale di WordPress con trasferimento manuale dei file e modifica di index.php. Il plugin fa risparmiare tempo su progetti medio-grandi con molte occorrenze.
Cosa fare se alcune immagini ancora non vengono caricate dopo la migrazione?
La causa più comune: nel database sono rimasti URL cablati con percorsi assoluti del vecchio server che non corrispondevano al pattern di sostituzione. Verificate il contenuto dei post via phpMyAdmin:
SELECT ID, post_content FROM wp_posts WHERE post_content LIKE '%/subdir/%'(o il vecchio dominio). Il secondo indiziato è la cache del browser e della CDN: svuotate entrambe e verificate in modalità incognito.
Devo aggiornare.htaccess dopo il trasferimento?
Se usate i permalink avanzati, sì, ma WordPress lo fa automaticamente quando cliccate "Salva" nella pagina Impostazioni → Permalink. Se il server non ha i permessi di scrittura, WordPress mostrerà il contenuto pronto del file.htaccess da copiare manualmente. Quando migrate verso una sottodirectory, assicuratevi che il file.htaccess della root (non quello dentro la sottodirectory) non contenga regole in conflitto con la nuova struttura.
È possibile eseguire la migrazione con zero downtime?
Tecnicamente sì, se usate il metodo con i redirect.htaccess (Metodo I della documentazione ufficiale di WordPress, "Senza cambiare gli URL"). Con questo approccio, i file vengono spostati nella sottodirectory mentre il file.htaccess della root dirige tutte le richieste in modo trasparente verso la nuova posizione. I visitatori non si accorgono dello spostamento. Lo svantaggio: restate sullo stesso dominio e l'URL del sito formalmente non cambia (la sottodirectory non è visibile nella barra degli indirizzi).
Perché WP Migrate DB Pro non supporta nativamente la migrazione tra diversi tipi di installazione?
Gli sviluppatori di Delicious Brains hanno discusso la questione su GitHub per quasi tre anni. La radice del problema: il plugin applica UNA coppia search-replace all'INTERO database, ma la migrazione tra root e sottodirectory richiede sostituzioni DIVERSE per gruppi di URL differenti (pagine vs risorse). Determinare automaticamente a quale gruppo appartiene un URL richiederebbe l'analisi della struttura del contenuto, andando oltre il semplice search-replace. Pertanto, la raccomandazione attuale è: portate i siti a uno schema di installazione unificato PRIMA della migrazione.

In conclusione: root o sottodirectory?
La scelta tra installazione WordPress in root o in sottodirectory si riduce essenzialmente a un compromesso. L'installazione in root è più semplice: meno elementi in gioco, compatibilità diretta tra sviluppo e produzione, nessuna sorpresa con URL doppi. L'installazione in sottodirectory è architetturalmente più pulita: i file core sono isolati, nella root risiede solo index.php, aggiornare WordPress via Git/Composer è più facile e ospitare più applicazioni sullo stesso dominio è più sicuro.
Se hai un sito di produzione e un sito di sviluppo, porta entrambi a uno schema unificato (uno qualsiasi dei due) e dimentica il problema. Se lavori in un team dove alcuni progetti sono storicamente in root mentre altri sono in sottodirectory, ora conosci gli esatti pattern di search-replace per ciascuna direzione.
La regola principale da tenere a portata di mano: quando migri ROOT → SOTTODIRECTORY, tocca solo /wp-content e i percorsi dei file; quando migri SOTTODIRECTORY → ROOT, sostituisci tutto ciò che contiene la sottodirectory. E ricorda sempre, sempre di cliccare «Salva» nei Permalink dopo lo spostamento.



