
Nascondere una pagina in WordPress vuol dire tre cose diverse, e chi lo chiede di solito ne ha in mente una sola. Toglierla ai visitatori, toglierla a Google, oppure toglierla dal menu e dalle liste del sito senza toglierla a nessuno. WordPress ha uno strumento per ciascuna, e nessuno dei tre fa il lavoro degli altri due. Una pagina protetta da password resta indicizzabile; una pagina in noindex la legge chiunque abbia il link; una pagina tolta dal menu è ancora nella sitemap, nella REST API e nell’elenco che un tema a blocchi costruisce da solo.
Questa guida va per destinatario. Prima i tre stati che una pagina può avere (pubblica, privata, protetta da password) e cosa cambia in ciascuno; poi il noindex, con e senza Rank Math, e perché robots.txt non serve; poi menu, sitemap, ricerca e REST API; poi le pagine riservate a chi è loggato e la password messa dal server, prima ancora che WordPress venga eseguito. Chiude la parte che nelle guide per punti manca sempre, cioè i posti da cui una pagina “nascosta” spunta fuori lo stesso, con i comandi per controllare che non succeda.
Una nota sulle fonti. Tutto quello che segue l’ho verificato il 22 settembre 2026 sul codice sorgente di WordPress 7.1, di Rank Math 1.0.278 e di W3 Total Cache 2.8.12, sulla documentazione di WordPress e di Google Search e su quelle di nginx e Apache. I comportamenti del core e i blocchi PHP sono stati eseguiti, non solo riletti, in un WordPress 7.1 vero (WordPress Playground, PHP 8.5), con e senza Rank Math; i blocchi per il server su nginx 1.30.5 e su Apache 2.4.67. Dove compare una versione o un numero, accanto c’è la data.
Prima di tutto: nascosta a chi?
Sono tre domande, e vanno fatte in quest’ordine, perché la risposta alla prima decide quasi tutto il resto.
Nascosta ai visitatori? Allora serve un controllo dell’accesso, e la pagina non deve aprirsi a chi non ha il diritto di vederla. Lo fanno la visibilità privata, la password di pagina, una capability data a un ruolo, oppure il server. Il noindex qui non c’entra, perché chiede a Google di non mostrare la pagina e non impedisce a nessuno di leggerla.
Nascosta ai motori di ricerca? Allora serve il noindex, e la pagina deve restare raggiungibile dai crawler, altrimenti il noindex non viene letto. È il caso della pagina di ringraziamento dopo un modulo, della landing di una campagna, del listino che mandi via email a chi lo chiede. Chiunque può aprirle, e non devono comparire nei risultati.
Nascosta alle liste del sito? Menu, blocco Elenco pagine, sitemap, ricerca interna, REST API, il file llms.txt del plugin SEO. Una pagina pubblicata sta in tutte, e ognuna va tolta per conto suo. Questo non è nascondere ma non elencare, e chi ha il link, o lo indovina, la apre come qualunque altra.
La tabella riassume cosa fa ciascun metodo. Le ultime due righe sono i due che circolano di più nelle guide e che non nascondono niente.
| Metodo | Chi non ha il diritto la apre? | Google la può indicizzare? | Sta nelle liste del sito? | Dove si imposta |
|---|---|---|---|---|
| Privata | No: risponde 404 | No, per Google è un 404 | No | Editor, Visibilità |
| Protetta da password | Vede il titolo e il modulo, non il contenuto | Sì, salvo noindex (Rank Math ha un’opzione dedicata, spenta di default) | Sì, tranne la sitemap e il llms.txt di Rank Math | Editor, Visibilità |
| Non pubblicata (bozza, cestino) | No: risponde 404 | No | No | Editor, stato |
| Noindex | Sì | No, dalla scansione successiva | Rank Math la toglie da sitemap, mappa HTML e llms.txt; le altre liste restano | Meta box di Rank Math, o un filtro |
| Non elencata | Sì | Sì | Dipende da quali liste escludi, una per una | Menu, impostazioni della sitemap, codice |
| Riservata a un ruolo | No | No | No se è privata; sì se è solo un redirect al login | Privata più una capability, oppure un plugin |
| Password dal server | No: risponde 401 | No | Sì, se per WordPress resta pubblicata | nginx o .htaccess |
| Tolta dal menu | Sì | Sì | Sì, in tutte le altre | Non nasconde niente |
| Bloccata in robots.txt | Sì | Sì: l’indirizzo può comparire lo stesso, e un eventuale noindex non viene letto | Sì | Non nasconde niente |
Un chiarimento sul numero. Molte guide contano “sette metodi” o “otto metodi” mettendo nello stesso elenco la visibilità privata, il noindex, la voce di menu e robots.txt, come se fossero alternative fra cui scegliere. Rispondono a domande diverse, e la maggior parte delle pagine nascoste male lo è perché qualcuno ha usato lo strumento della domanda sbagliata.
I tre stati di una pagina: pubblica, privata, protetta da password
Nell’editor, nel pannello della pagina, la voce Visibilità ha tre valori, e l’interfaccia in italiano li descrive con una riga ciascuno: Pubblico, “Visibile a tutti”; Privato, “Visibile solo agli amministratori e agli editori del sito”; Protetto da password, “Visibile solo a chi conosce la password”. La documentazione ufficiale (aggiornata il 24 ottobre 2024) dice le stesse tre cose in inglese.
Le tre righe sono giuste e corte, e quello che non dicono è quello che conta.
Privata: chi la vede e dove sparisce
Una pagina privata resta pubblicata (lo stato interno è private), ma per chi non è loggato non esiste. L’indirizzo risponde 404, come se non fosse mai stata scritta; l’ho verificato su WordPress 7.1, 404 da visitatore e 200 da amministratore, con il titolo preceduto da “Privato:”. La vedono gli amministratori, gli editori e, cosa che la documentazione non dice ma il codice sì, il suo autore. In map_meta_cap() l’autore di un contenuto privato lo legge anche senza la capability read_private_pages, che di default hanno solo i due ruoli alti, come riporta la tabella della documentazione sui ruoli (aggiornata il 2 settembre 2026).
Sparisce da tutto.
Dal blocco Elenco pagine e da qualunque menu costruito con get_pages(), che interroga solo i contenuti pubblicati; dalla sitemap del core e da quella di Rank Math; dalla ricerca interna; dall’elenco della REST API, che a chi non è autenticato mostra soltanto lo stato publish; dal llms.txt. Rank Math aggiunge di suo un noindex, superfluo (Google riceve un 404) e innocuo. È lo stato giusto quando la pagina serve a chi lavora sul sito, come una bozza di listino da far vedere a un collega, una pagina di istruzioni interne, un archivio di materiali.
Il limite sta nel “chi”, perché amministratori, editori e autore sono le persone che il sito lo fanno. Per far leggere una pagina privata agli abbonati o ai clienti serve un passo in più, descritto più avanti.
Protetta da password: cosa protegge e cosa no
La pagina protetta da password resta a tutti gli effetti pubblicata e pubblica. L’indirizzo risponde 200 a chiunque; al posto del contenuto c’è un modulo con una riga sola, “Questo contenuto è protetto da password. Per visualizzarlo inserisci la password qui sotto”, e il titolo compare per intero, con “Protetto:” davanti. Chi inserisce la password giusta vede la pagina, e il contenuto vero non lascia mai il server prima di quel momento.
Come funziona, letto nel sorgente ed eseguito. Il modulo invia la password a wp-login.php?action=postpass, che non la verifica. Prende quello che è stato scritto, lo passa per la funzione di hash e lo scrive in un cookie, wp-postpass_ seguito da un identificativo del sito, con scadenza a 10 giorni (la cambia il filtro post_password_expires, e restituendo 0 il cookie dura quanto il browser). Poi rimanda alla pagina. È lì, a ogni caricamento, che post_password_required() confronta l’hash nel cookie con la password salvata sulla pagina. Con una password sbagliata succede la stessa identica cosa, cookie scritto e redirect, e sulla pagina ricompare il modulo, dalla 6.8 con la scritta “Password non valida.”
Da qui derivano tre conseguenze pratiche.
La prima è che non è un login. Non c’è un utente, non c’è una sessione, non suona nessuna delle campane che i plugin di sicurezza ascoltano; ho registrato gli hook durante le prove, e una password sbagliata sulla pagina non fa scattare wp_login_failed. Le quattro porte del login hanno un contatore dei tentativi; questa no, né nel modulo né nella REST API, che accetta la password come parametro (?password=) e risponde 403 se è sbagliata, senza contare niente. Una password di pagina va scelta come una password vera, perché chi vuole provarle tutte può farlo senza che un limite lo fermi, e gli strumenti che fermano gli attacchi brute force sul login non guardano da questa parte.
La seconda è che la password vale per tutte le pagine che hanno la stessa password, perché il cookie non sa per quale pagina è stato creato. Se dieci pagine hanno “cliente2026”, chi entra in una entra in tutte. È comodo per un’area fatta di più pagine, ed è un errore se le dieci pagine sono per dieci clienti diversi.
La terza è che la pagina è indicizzabile. Google riceve un 200 con il titolo e il modulo, e con Rank Math nella configurazione predefinita il meta robots dice index, follow; l’ho controllato. Per metterla in noindex esiste un’opzione apposita, in Titoli e Meta, scheda “Pagine varie”: “Metti in noindex le pagine protette da password”. È spenta di default, si vede solo in Modalità avanzata, e la documentazione del plugin consiglia di accenderla. Con l’opzione accesa il meta robots diventa noindex e il canonical sparisce.
Cosa resta visibile, oltre al titolo. Il riassunto viene sostituito da una riga fissa (“Non è disponibile alcun riassunto in quanto si tratta di un articolo protetto”), la meta description generata dal contenuto è vuota, l’immagine Open Graph non viene stampata. Una meta description scritta a mano nel campo di Rank Math esce invece lo stesso.
Nell’elenco della REST API la pagina compare con titolo, slug e data, con il contenuto vuoto e con la voce protected impostata a true. Dalla ricerca interna è esclusa per chi non è loggato e inclusa per chi lo è (l’ho visto da un utente abbonato, con il titolo fra i risultati). La sitemap di Rank Math e il suo llms.txt la lasciano fuori; la sitemap del core, se non hai un plugin SEO, la include.
Non pubblicata: bozza e cestino
Riportare una pagina in bozza (“Converti in bozza” nel pannello) la fa rispondere 404 a tutti tranne a chi può modificarla, e la toglie da liste, sitemap e API. È il modo giusto per una pagina che non serve più ma che potresti riprendere, e il modo sbagliato per una pagina che deve restare in uso per qualcuno; dopo un po’ Google la toglie dall’indice, perché trova un 404. Il cestino fa lo stesso con due differenze, rinomina lo slug aggiungendo __trashed e dopo trenta giorni cancella. Se la pagina aveva traffico o link, la scelta fra 404, 410 e redirect è un’altra decisione, che ho scritto in quale codice usare per una pagina rimossa; il criterio per scegliere fra cancellare, accorpare e nascondere sta in quando cancellare una pagina e quando no.
Nasconderla ai motori di ricerca: noindex, e perché robots.txt non serve
Per tenere una pagina fuori da Google senza toglierla a nessuno lo strumento è uno, il meta tag noindex (o l’intestazione HTTP X-Robots-Tag: noindex). La documentazione di Google (aggiornata il 10 dicembre 2025) mette una condizione che vale più della regola: “For the noindex rule to be effective, the page or resource must not be blocked by a robots.txt file, and it has to be otherwise accessible to the crawler“. Il noindex è un’istruzione scritta dentro la pagina, e se il crawler non può leggere la pagina non legge nemmeno l’istruzione.
Per questo robots.txt non nasconde niente. Lo dice la pagina introduttiva di Google su robots.txt, testualmente, “it is not a mechanism for keeping a web page out of Google“, e subito dopo, “To keep a web page out of Google, block indexing with noindex or password-protect the page“. Un indirizzo bloccato in robots.txt può comparire nei risultati lo stesso, se qualcuno lo linka, con l’URL e il testo dei link al posto del contenuto. Se poi sulla pagina bloccata c’è anche il noindex, Google non lo vede. I due strumenti non si sommano, si annullano.
Con Rank Math
Nel meta box di Rank Math sotto la pagina, scheda Avanzate, sezione Meta robot, si spunta Noindex (il passaggio nella documentazione del plugin; la scheda esiste solo in Modalità avanzata). Rank Math stampa noindex nel meta robots, toglie il canonical e, cosa che la documentazione non dice ma il codice sì, esclude da sola la pagina dalla sitemap XML, dalla mappa del sito in HTML se usi la sua, e dal llms.txt, perché le tre liste leggono lo stesso campo. Per il resto la pagina non cambia e sta nei menu, nell’Elenco pagine, nella ricerca interna e nell’API.
L’alternativa globale è la casella “Scoraggia i motori di ricerca dall’effettuare l’indicizzazione di questo sito”, in Impostazioni, Lettura. Vale per tutto il sito e non per una pagina, e la documentazione avverte che “it is up to search engines to honor your request“. È la prima cosa da controllare quando un sito appena installato non compare su Google, e non uno strumento per nascondere una pagina.
Senza plugin SEO, e perché con Rank Math il filtro del core non fa niente
Dalla 5.7 WordPress ha un filtro, wp_robots, che governa il meta robots del core. Senza plugin SEO bastano queste righe, in un mu-plugin o nel functions.php di un child theme:
<?php
/**
* Plugin Name: Noindex su una pagina
* Description: Aggiunge noindex al meta robots di una pagina con il filtro del core (dalla 5.7). File in wp-content/mu-plugins/. Con Rank Math attivo non ha effetto: il plugin scollega questo filtro e stampa il suo meta robots.
*/
add_filter( 'wp_robots', function ( $robots ) {
if ( is_page( 'listino-rivenditori' ) ) {
$robots['noindex'] = true;
}
return $robots;
} );Eseguito su un WordPress 7.1 senza plugin: la pagina stampa <meta name='robots' content='max-image-preview:large, noindex' />, le altre no. Il noindex però non toglie la pagina dalla sitemap del core, che non legge il meta robots; per quello serve il filtro wp_sitemaps_posts_query_args, che sta nel blocco della sezione successiva.
Con Rank Math attivo lo stesso codice non produce nulla, e nessun errore lo dice. Il plugin, quando prepara l’intestazione della pagina (sull’azione wp), chiama remove_all_filters( 'wp_robots' ) e stampa il suo meta robots, e il filtro del core resta scollegato, che stia in un plugin o nel tema. L’ho provato in entrambi i modi, e in entrambi la pagina è uscita index, follow. Se le pagine da mettere in noindex sono tante o cambiano nel tempo, e il meta box non basta, il filtro da usare è quello di Rank Math:
<?php
/**
* Plugin Name: Noindex su una pagina (Rank Math)
* Description: Con Rank Math attivo il noindex si mette dal meta box; questo filtro serve quando le pagine sono tante o cambiano. File in wp-content/mu-plugins/.
*/
add_filter( 'rank_math/frontend/robots', function ( $robots ) {
if ( is_page( 'listino-rivenditori' ) ) {
$robots['index'] = 'noindex';
}
return $robots;
} );Eseguito con Rank Math 1.0.278: noindex, follow, canonical rimosso.
Un limite da sapere.
La sitemap, la mappa HTML e il llms.txt di Rank Math leggono il campo del meta box e non questo filtro, quindi una pagina messa in noindex così resta nella sitemap finché non la escludi anche lì, in Impostazione della sitemap, scheda Generale, campo “Escludi gli articoli”, con l’ID della pagina (documentazione del plugin).
Se è già indicizzata
Il noindex agisce alla scansione successiva, e Google avverte che per una pagina poco importante “it may take months for Googlebot to revisit a page“. Due strumenti in Search Console accorciano i tempi. Il Controllo URL, il cui pulsante di richiesta di indicizzazione fa rileggere la pagina. Poi lo strumento Rimozioni, che nasconde l’indirizzo dai risultati in poche ore ma per “about six months“: la documentazione lo definisce temporaneo, e per la rimozione permanente rimanda a noindex, password o rimozione vera. Le tre strade permanenti sono elencate nella pagina di Google sulla rimozione dei contenuti, e sono le stesse di questa guida.
Prima di mettere un noindex conviene rileggere il controllo 9 della checklist SEO on-page, quello sul noindex accidentale. È la stessa casella, e quando è spuntata per sbaglio annulla tutto il resto.
Nasconderla alle liste del sito: menu, elenco pagine, sitemap, ricerca, API
È il caso della pagina che deve restare aperta a chi ha il link e non deve essere proposta a nessuno, come la landing di una campagna, la pagina di ringraziamento, il listino che mandi ai rivenditori. WordPress non ha un’impostazione “non elencare”. Ha sei liste, e ognuna si gestisce a modo suo.
Menu e blocco Elenco pagine
Un menu classico (Aspetto, Menu) contiene solo le voci che ci metti, e la pagina nuova non ci finisce da sola. C’è un’eccezione, che vale per i temi classici. Se al tema non è assegnato nessun menu, wp_nav_menu() ripiega su wp_page_menu(), che elenca tutte le pagine pubblicate, protette da password comprese. Nei temi a blocchi il meccanismo è esplicito. Il blocco Elenco pagine, che il blocco Navigazione usa di default, mostra “your website’s published pages” (documentazione del blocco, aggiornata il 23 luglio 2026) e non ha un’opzione per escluderne una; ha solo il filtro per pagina madre. L’ho verificato, la pagina protetta da password compare e la privata no.
Per togliere una pagina si seleziona il blocco dentro Navigazione, si preme Modifica e si accetta l’avviso, “Questo menu di navigazione visualizza le pagine del tuo sito web. Modificarlo ti consentirà di aggiungere, eliminare e riordinare le pagine. Tuttavia, le nuove pagine non saranno più aggiunte automaticamente”. L’elenco diventa una serie di link singoli, e da lì si cancella quello che non deve vedersi.
Sitemap XML, sitemap HTML e llms.txt
Con Rank Math le tre liste si governano insieme. Una pagina in noindex (dal meta box) o protetta da password esce da tutte e tre, e per una pagina che deve restare indicizzabile ma fuori dalla sitemap c’è “Escludi gli articoli” nelle impostazioni della sitemap, che vale anche per la mappa del sito in HTML generata dal plugin. Il llms.txt merita un’occhiata a parte, perché elenca le pagine con una descrizione presa dal riassunto o, se manca, dalle prime parole del contenuto (documentazione del modulo). Cosa c’era nel llms.txt del mio sito l’ho raccontato altrove, e la regola è la stessa della sitemap (con il solo core, senza plugin SEO, il llms.txt non esiste e non c’è niente da allineare). A cosa serve la sitemap, e quando una pagina che sta solo lì è un problema, è in a cosa serve la sitemap XML e quando non serve.
Senza plugin SEO la sitemap la genera il core (wp-sitemap.xml, dalla 5.5), e la sua lista delle pagine include tutte quelle pubblicate, protette da password e in noindex comprese; l’ho verificato. Si esclude con il filtro wp_sitemaps_posts_query_args, che sta nel blocco della sezione seguente insieme agli altri due.
Ricerca interna e REST API
La ricerca interna (?s=) cerca fra articoli e pagine pubblicati. Le pagine protette da password le lascia fuori per chi non è loggato e le mostra, con il solo titolo, a chi lo è; una pagina normale che non vuoi far trovare si esclude con pre_get_posts.
La REST API è la lista che quasi nessuno guarda. /wp-json/wp/v2/pages elenca a chiunque, senza autenticazione, tutte le pagine pubblicate con titolo, slug, data e contenuto renderizzato; per quelle protette da password il contenuto è vuoto e la voce protected vale true, mentre private e bozze non ci sono. È la stessa lista da cui un frontend headless legge il sito, e da cui lo legge chiunque altro. L’esclusione passa da due filtri, perché l’API ha due strade, l’elenco (rest_page_query) e la ricerca, /wp-json/wp/v2/search, che usa una query propria (rest_post_search_query). Nella prima prova avevo filtrato solo l’elenco, e la pagina è ricomparsa nella ricerca.
Il mu-plugin che segue mette insieme le tre esclusioni, ricerca interna, API e sitemap del core, per una lista di ID:
<?php
/**
* Plugin Name: Pagina non elencata
* Description: Tiene una pagina pubblicata fuori dalla ricerca interna, dall'elenco e dalla ricerca della REST API e dalla sitemap del core. Non la nasconde a chi ha il link. File in wp-content/mu-plugins/.
*/
// Gli ID delle pagine da non elencare.
const AA_PAGINE_NON_ELENCATE = array( 123 );
// Ricerca interna (?s=).
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || ! $query->is_main_query() || ! $query->is_search() ) {
return;
}
$query->set( 'post__not_in', array_merge( (array) $query->get( 'post__not_in' ), AA_PAGINE_NON_ELENCATE ) );
} );
// Elenco /wp-json/wp/v2/pages e ricerca /wp-json/wp/v2/search.
function aa_escludi_da_rest( $args ) {
$args['post__not_in'] = array_merge( (array) ( $args['post__not_in'] ?? array() ), AA_PAGINE_NON_ELENCATE );
return $args;
}
add_filter( 'rest_page_query', 'aa_escludi_da_rest' );
add_filter( 'rest_post_search_query', 'aa_escludi_da_rest' );
// Sitemap del core (wp-sitemap.xml). Con un plugin SEO si usa la sua esclusione.
add_filter( 'wp_sitemaps_posts_query_args', function ( $args, $post_type ) {
if ( 'page' === $post_type ) {
$args['post__not_in'] = array_merge( (array) ( $args['post__not_in'] ?? array() ), AA_PAGINE_NON_ELENCATE );
}
return $args;
}, 10, 2 );Eseguito su WordPress 7.1. Con l’ID della pagina nell’elenco, ?s=, /wp/v2/pages, /wp/v2/search e wp-sitemap-posts-page-1.xml non la contengono più, e una pagina di controllo compare in tutti e quattro. Con Rank Math la sitemap si esclude dal suo pannello, come detto sopra, e l’ultimo filtro non serve. Il feed RSS non va toccato, perché elenca solo gli articoli e non le pagine.
Nasconderla a chi non è loggato, o a un ruolo
La visibilità privata risponde alla domanda “solo chi lavora sul sito”. Per rispondere a “solo i miei clienti” o “solo gli iscritti” bisogna dare a quel ruolo il diritto di leggere le pagine private, oppure affidare le regole a un plugin.
Privata, più una capability per il ruolo
Chi ha la capability read_private_pages legge le pagine private. Di default l’hanno amministratori ed editori; si può dare a qualunque ruolo, e il ruolo Abbonato è il candidato naturale, perché è quello che WordPress assegna a chi si registra. Le capability dei ruoli stanno nel database, quindi il codice fa una scrittura sola e da lì in poi non fa più niente:
<?php
/**
* Plugin Name: Pagine private per gli abbonati
* Description: Dà al ruolo Abbonato la capability read_private_pages, così chi è loggato legge le pagine private. La capability si salva nel database: dopo il primo caricamento il file può anche essere tolto (per revocarla: remove_cap). File in wp-content/mu-plugins/.
*/
add_action( 'init', function () {
$ruolo = get_role( 'subscriber' );
if ( $ruolo && ! $ruolo->has_cap( 'read_private_pages' ) ) {
$ruolo->add_cap( 'read_private_pages' );
}
} );Eseguito. Prima del mu-plugin un abbonato loggato riceve 404 sulla pagina privata, dopo la vede (200, titolo “Privato: …”). Siccome la pagina resta privata, tutto il resto è coerente senza altro codice. Non è nell’API, non è nella sitemap, non è nell’Elenco pagine, non è nella ricerca, e per Google è un 404. Chi ha WP-CLI ottiene lo stesso con wp cap add subscriber read_private_pages; per revocare, remove_cap() o wp cap remove.
Un’avvertenza della documentazione, che vale per le pagine private e per quelle protette da password. Gli altri amministratori ed editori le vedono nella bacheca, possono modificarle e renderle pubbliche. La visibilità decide cosa vede il pubblico, e chi ha i permessi vede tutto.
Il modulo di login al posto del 404
Chi arriva su una pagina privata senza essere loggato riceve un 404, che per un cliente è un vicolo cieco. Bastano poche righe per mandarlo al modulo di login e riportarlo alla pagina subito dopo:
<?php
/**
* Plugin Name: Login al posto del 404
* Description: Chi apre una pagina privata senza essere loggato viene mandato al modulo di login e poi riportato alla pagina, invece di ricevere un 404. File in wp-content/mu-plugins/.
*/
add_action( 'template_redirect', function () {
if ( is_404() && 'area-clienti' === get_query_var( 'pagename' ) && ! is_user_logged_in() ) {
auth_redirect();
}
} );auth_redirect() è la funzione che il core usa per la bacheca, e manda a wp-login.php con l’indirizzo di ritorno in redirect_to. Eseguito. Da visitatore la pagina privata risponde 302 verso il login con il ritorno alla pagina; da abbonato con la capability, 200; un 404 qualunque resta un 404. Il controllo su get_query_var( 'pagename' ) serve perché per il visitatore la pagina è un 404 e is_page() è falso.
Il redirect senza pagina privata, e il buco nell’API
In rete circola la versione corta, “se non sei loggato ti mando al login”, applicata a una pagina pubblicata. Funziona nel browser e apre un buco. La pagina resta publish, quindi la REST API la serve intera, con il contenuto renderizzato, a chiunque chieda /wp-json/wp/v2/pages; l’ho verificato con una pagina protetta solo da quel redirect, 302 al login nel browser e tutto il testo nell’API. Sta anche nella sitemap e nell’Elenco pagine. La protezione va messa sul contenuto, con lo stato privato, e non davanti al template.
Con un plugin
Se i ruoli sono più di uno, o le regole cambiano pagina per pagina, un plugin di gestione dei ruoli fa questo lavoro con un’interfaccia. Members (3.2.26 del 25 agosto 2026, oltre 300.000 installazioni attive) permette di scegliere per ogni pagina quali ruoli possono vederla e mostra agli altri un messaggio al posto del contenuto. Prima di installarne uno, due controlli.
Che sia mantenuto. Un plugin che le guide in rete consigliano ancora per “nascondere” le pagine dalle liste, WP Hide Post, è chiuso su WordPress.org dal 27 luglio 2023 per un problema di sicurezza, e le guide che lo raccomandano sono di due anni dopo. Poi che protegga anche l’API. Un plugin che nasconde la pagina nel template e la lascia publish ha lo stesso buco del paragrafo precedente, e si verifica in un minuto con il comando della sezione finale.
Dal server: la password prima di WordPress
Quando la pagina non deve nemmeno arrivare a PHP, la password la chiede il web server con l’autenticazione HTTP Basic. Il browser mostra la finestra di nome utente e password, e finché non sono giusti WordPress non viene eseguito. È il metodo che Google indica per i contenuti riservati, “you need to password protect it to ensure only authorized users can access it” (documentazione su cosa condividere con Google, 10 dicembre 2025), ed è quello che consiglio per gli ambienti di staging, compreso un sito che sta passando a WordPress mentre quello vecchio è ancora online. Non ha finezze, niente ruoli, niente modulo del tema, un solo elenco di utenti in un file.
Il file delle password si crea con htpasswd, dalla distribuzione di Apache, e va messo fuori dalla webroot:
htpasswd -c -B /percorso/fuori/dalla/webroot/.htpasswd cliente
-B usa bcrypt, che la documentazione di htpasswd definisce “currently considered to be very secure“; le vecchie forme SHA-1 e crypt() sono, secondo la stessa pagina, insicure. nginx legge lo stesso file. La documentazione del modulo elenca fra i formati accettati quelli generati da htpasswd e da openssl passwd, e nelle mie prove ha accettato sia bcrypt sia apr1.
Su nginx, nel blocco server del sito, prima del location /:
# La pagina riservata e le sue figlie: il server chiede la password prima che WordPress esista.
location ^~ /riservata/ {
auth_basic "Area riservata";
auth_basic_user_file /percorso/fuori/dalla/webroot/.htpasswd;
try_files $uri $uri/ /index.php?$args;
}Il modificatore ^~ fa vincere questa location sulle espressioni regolari (quella che passa i file a PHP) e copre la pagina e le sue figlie; il try_files ripete quello del sito, perché la pagina non esiste su disco e la richiesta deve arrivare a index.php. Eseguito su nginx 1.30.5 con PHP-FPM dietro: /riservata/ e /riservata/sotto/ rispondono 401 senza credenziali e 200 con; /riservatezza/ non è toccata. L’indirizzo senza barra finale, /riservata, passa a WordPress, che di norma lo reindirizza alla versione con la barra (è uno dei redirect automatici del core), dove la password viene chiesta.
Su Apache, nel file .htaccess della radice, sopra il blocco di WordPress:
# BEGIN Area riservata
<If "%{REQUEST_URI} =~ m#^/riservata/#">
AuthType Basic
AuthName "Area riservata"
AuthUserFile "/percorso/fuori/dalla/webroot/.htpasswd"
Require valid-user
</If>
# END Area riservataServe il contenitore <If> perché <Location> non è ammesso in .htaccess e <Files> non vede un indirizzo che non corrisponde a un file. Eseguito su Apache 2.4.67 con le regole di WordPress sotto. Stessi risultati di nginx, 401 sulla pagina e sulle figlie, 200 con le credenziali, il resto del sito intatto.
Due cose da sapere.
La pagina resta pubblicata per WordPress, quindi sta nelle liste (sitemap, Elenco pagine, API), e l’API risponde con il contenuto, perché la richiesta a /wp-json/ non passa per quel percorso. Se il contenuto è riservato, la pagina va anche messa privata, e il server diventa il secondo lucchetto. Il lucchetto sull’indirizzo di login, poi, che è la stessa tecnica applicata a wp-login.php, ha regole sue (non si chiude tutta wp-admin): sarà una guida a parte.
Da dove spunta fuori lo stesso
Sono i posti che ho trovato eseguendo le prove, e sono quelli che una guida per punti non elenca.
I file caricati. Le immagini e i PDF di una pagina privata o protetta stanno in wp-content/uploads/, e il web server li serve senza chiedere niente a WordPress, perché le regole di riscrittura del core passano a index.php solo gli indirizzi che non corrispondono a un file. L’ho verificato, e l’allegato di una pagina privata risponde 401 nell’API dei media e 200 al suo indirizzo diretto. Se il PDF è il motivo per cui la pagina è nascosta, la pagina non basta; serve una regola sul server anche per il file, oppure il file va tolto da uploads. È il controllo 15 della checklist di sicurezza, quello sui file che nessuno linka e chiunque scarica.
L’indirizzo indovinato. Una pagina non elencata è raggiungibile da chi ne indovina un pezzo. /listino/ reindirizza con un 301 a /listino-rivenditori-2026/, perché uno dei quattro redirect che WordPress fa da solo completa gli slug parziali; e ?p=ID reindirizza al permalink di qualunque contenuto pubblicato, quindi gli ID si scorrono uno per uno. Le pagine private e le bozze non vengono indovinate (404 in entrambi i casi, verificato); quelle pubblicate sì, protette da password comprese.
Il titolo e i metadati. Della pagina protetta da password escono il titolo (con “Protetto:” davanti nell’H1, senza nel <title>), lo slug, la data, e la meta description se l’hai scritta a mano. Il titolo, spesso, dice già tutto.
La cache di pagina. Il modulo della password si regge su un cookie, e una cache che ignora i cookie serve a tutti la versione salvata. Se la prima visita è di chi ha la password, il contenuto finisce in cache e lo vede chiunque. W3 Total Cache (2.8.12) non lo fa, perché nel suo codice il cookie wp-postpass_ è fra quelli che escludono la richiesta dalla cache, in lettura e in scrittura, e le regole per Apache della modalità Disk: Enhanced lo escludono allo stesso modo. Con un altro livello di cache (CDN, proxy, un plugin diverso) va verificato, con i comandi della sezione seguente, che la pagina protetta non venga servita dalla cache a chi non ha il cookie. Di cache di pagina ed esclusioni ho scritto in W3 Total Cache e WP Rocket a confronto.
Il noindex che non c’è più. Un plugin SEO sostituito, una pagina duplicata per riusarne l’impostazione, un’importazione. Il meta robots vive nel plugin SEO, e cambiando plugin la pagina torna indicizzabile senza che nessuno se ne accorga. Va nel controllo trimestrale della manutenzione, insieme al rapporto sull’indicizzazione di Search Console.
Come verificare che sia nascosta davvero
Non con la finestra privata del browser, che ha cookie e cache propri e mostra quello che sa. Con curl, da fuori, come farebbe un visitatore o un crawler; ogni riga risponde a una domanda.
SITO="https://www.tuosito.it"; PAGINA="/riservata/"
# 1. Codice di stato e meta robots, come li vede un visitatore senza cookie
curl -s -o /dev/null -w "%{http_code}\n" "$SITO$PAGINA"
curl -s "$SITO$PAGINA" | grep -io '<meta name=.robots.[^>]*>'
# 2. Una pagina protetta da password non deve contenere il testo riservato
curl -s "$SITO$PAGINA" | grep -c "una frase presa dal contenuto"
# 3. Sitemap (page-sitemap.xml con Rank Math, wp-sitemap-posts-page-1.xml con il core) e llms.txt
curl -s "$SITO/page-sitemap.xml" | grep -c "$PAGINA"
curl -s "$SITO/llms.txt" | grep -c "$PAGINA"
# 4. REST API: l'elenco delle pagine e la ricerca
curl -s "$SITO/wp-json/wp/v2/pages?per_page=100&_fields=slug" | grep -c "riservata"
curl -s "$SITO/wp-json/wp/v2/search?search=riservata" | grep -c "riservata"
# 5. L'indirizzo indovinato da uno slug parziale
curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" "$SITO/riserv/"Cosa aspettarsi da ogni riga.
404 per una pagina privata o in bozza, 200 con il modulo per una protetta da password, 401 dietro il server; noindex nel meta robots, se l’hai messo; zero righe dalla sitemap, dal llms.txt, dall’elenco e dalla ricerca dell’API se la pagina non deve essere elencata; per la pagina protetta, nessuna traccia del contenuto nella risposta senza cookie; e un 404, non un 301, dallo slug parziale, se la pagina è privata. Se una pagina “nascosta” compare in uno di questi punti, quella lista va sistemata con la sezione corrispondente. Chiudono il giro il rapporto Pagine di Search Console e il Controllo URL, che dicono cosa ha visto Google l’ultima volta che è passato.
Domande frequenti
Una pagina protetta da password è nascosta a Google?
Di default no. La pagina resta pubblicata, risponde 200 con il titolo e il modulo della password, e con Rank Math nella configurazione predefinita il meta robots dice index, follow. Google può indicizzare titolo e indirizzo, non il contenuto, che non viene mai inviato senza la password giusta. Per tenerla fuori dai risultati serve il noindex, e in Rank Math c’è l’opzione “Metti in noindex le pagine protette da password”, in Titoli e Meta, scheda Pagine varie, spenta di default e consigliata dal plugin stesso.
Chi vede una pagina privata in WordPress?
Gli amministratori, gli editori e l’autore della pagina, quando sono loggati. Per tutti gli altri, loggati o no, l’indirizzo risponde 404, e la pagina non compare in menu, sitemap, ricerca interna e REST API. Per farla leggere a un altro ruolo, per esempio agli abbonati, si dà a quel ruolo la capability read_private_pages, con poche righe di codice o con WP-CLI, e la pagina resta privata e tutte le esclusioni restano valide.
Come nascondo una pagina dal menu senza nasconderla dal sito?
In un menu classico basta non inserirla, o togliere la voce da Aspetto, Menu. Nei temi a blocchi il blocco Elenco pagine mostra tutte le pagine pubblicate e non ha esclusioni. Si preme Modifica sul blocco dentro Navigazione, l’elenco diventa una serie di link singoli e si cancella quello che non serve, sapendo che da quel momento le pagine nuove non si aggiungono più da sole. La pagina resta comunque raggiungibile dal suo indirizzo, dalla sitemap, dalla ricerca interna e dalla REST API.
Se metto una pagina in bozza, Google la toglie dai risultati?
Con i suoi tempi, sì. In bozza l’indirizzo risponde 404, e Google elimina dall’indice le pagine che trova in 404 alla scansione successiva, che per una pagina poco visitata può arrivare dopo settimane o mesi. Per accelerare si usa lo strumento Rimozioni di Search Console, che però vale circa sei mesi. Se la pagina è stata rimossa per sempre, il 410 dice la stessa cosa in modo esplicito; se esiste un’altra pagina che risponde alla stessa domanda, la scelta giusta è un redirect 301.
Il file robots.txt serve a nascondere una pagina?
Secondo la documentazione di Google, no. Il file robots.txt serve a limitare la scansione e non tiene nessuna pagina fuori dai risultati. Un indirizzo bloccato può comparire lo stesso se altri siti lo linkano, con l’URL e il testo dei link al posto del contenuto, e se sulla pagina bloccata c’è anche il noindex, Google non riesce a leggerlo. Per tenere una pagina fuori dall’indice si usa il noindex; per tenerla lontana dalle persone, una password o la visibilità privata.
Quanto dura la password di una pagina protetta?
Dieci giorni, per impostazione predefinita. La password viene salvata in un cookie del browser che scade dopo 10 giorni, e il filtro post_password_expires permette di cambiare la durata o di farla valere per la sola sessione. Il cookie vale per tutte le pagine del sito che hanno la stessa password, e nessun limite conta i tentativi sbagliati, né nel modulo né nella REST API, quindi la password va scelta come una password vera.
Da qui in avanti
Se devi ricordare una cosa sola: prima di toccare qualunque impostazione, decidi a chi la pagina deve essere nascosta. Ai visitatori, e allora è privata, con password o dietro il server; a Google, e allora è noindex, con la pagina lasciata raggiungibile; alle liste del sito, e allora ogni lista va tolta per conto suo, sapendo che la pagina resta aperta a chi ha il link. Nessuno dei tre strumenti fa il lavoro degli altri, mentre i due che si leggono più spesso, la voce di menu e robots.txt, restano fuori da tutti e tre.
Poi la verifica da fuori, con i comandi qui sopra, e una volta a trimestre il giro sulle pagine che devono restare nascoste, perché un plugin cambiato o una pagina duplicata bastano a rimetterle in circolazione. È una riga del piano di manutenzione e non un progetto.
Se preferisci che lo faccia io
Decidere lo stato giusto per ogni pagina riservata, chiudere le liste da cui spunta fuori, mettere il lucchetto sul server dove serve e verificare il risultato da fuori è parte del lavoro di hardening di un sito WordPress che faccio per i clienti. Se vuoi che me ne occupi io, scrivimi due righe con cosa deve restare riservato e a chi. Partiamo da lì, senza passare da un plugin.

Lascia un commento