Must-use plugin WordPress della Bottega del Barbieri: firma, SMTP, cache, Open Graph, feed, Umami, avviso di login, banner dei cookie. GPLv3.
Find a file
2026-10-10 21:02:09 +00:00
bottega-appuntamenti.php Add bottega-appuntamenti: events page with editor form, sidebar widget, daily cleanup 2026-10-05 23:55:28 +00:00
bottega-autore.php autore: riquadro Informazioni sull'autore in fondo agli articoli 2026-10-10 18:49:24 +00:00
bottega-cache.php mu-plugin della Bottega, prima pubblicazione GPLv3 2026-09-13 23:39:56 +01:00
bottega-condividi.php condividi: riquadro Condividi in fondo agli articoli, verso un'istanza Mastodon 2026-10-10 20:59:37 +00:00
bottega-consenso.php bottega-consenso: banner dei cookie in italiano e blocco dei contenuti esterni fino alla scelta del lettore 2026-09-29 21:19:36 +00:00
bottega-feed-images.php mu-plugin della Bottega, prima pubblicazione GPLv3 2026-09-13 23:39:56 +01:00
bottega-feeds.php mu-plugin della Bottega, prima pubblicazione GPLv3 2026-09-13 23:39:56 +01:00
bottega-firma.php mu-plugin della Bottega, prima pubblicazione GPLv3 2026-09-13 23:39:56 +01:00
bottega-login-alert.php bottega-login-alert: IP da REMOTE_ADDR (già corretto da nginx real_ip), non dal primo valore di X-Forwarded-For 2026-09-29 21:53:18 +00:00
bottega-opengraph.php mu-plugin della Bottega, prima pubblicazione GPLv3 2026-09-13 23:39:56 +01:00
bottega-smtp.php smtp: relay senza autenticazione, TLS non verificato opzionale, Hostname dal mittente; README: nove plugin 2026-09-30 19:42:43 +00:00
bottega-stile.php stile: bordo dei riquadri del tema più scuro 2026-10-10 20:59:41 +00:00
bottega-umami.php Umami: contatore Visitatori con i lettori che sono rimasti a leggere 2026-10-10 18:48:52 +00:00
LICENSE mu-plugin della Bottega, prima pubblicazione GPLv3 2026-09-13 23:39:56 +01:00
README.md readme: voci per bottega-condividi e bottega-stile 2026-10-10 21:02:09 +00:00

bottega-mu-plugins

Nove must-use plugin per WordPress, scritti per La Bottega del Barbieri durante la migrazione del blog da un hosting condiviso a un server proprio. Ognuno fa una cosa sola, in poche righe, e sostituisce un plugin che ne faceva venti.

Sono pubblicati con licenza GPLv3 nella speranza che servano ad altri blog collettivi.

Cosa sono i mu-plugin

I file in wp-content/mu-plugins/ vengono caricati sempre, prima dei plugin normali, senza attivazione e senza pannello. Si installano copiando il file, si disinstallano cancellandolo. Non si aggiornano da WordPress: sono codice vostro, da tenere in git.

Attenzione: un errore di sintassi in un mu-plugin manda in errore tutto il sito. Prima di copiare un file modificato, php -l file.php.

Installazione

Copiate i file che vi servono in wp-content/mu-plugins/ (create la cartella se non esiste). Le costanti di configurazione vanno in wp-config.php, prima della riga /* That's all, stop editing! */.

Requisiti: WordPress 6.x, PHP 8.0 o successivo.

I plugin

bottega-firma.php — Firma

Aggiunge una casella Firma nell'editor degli articoli. Se compilata, il valore sostituisce il nome dell'utente nella riga dell'autore sul sito (filtro the_author), e quindi ovunque quella riga venga letta: feed, anteprime, newsletter. Serve ad attribuire un articolo a chi l'ha scritto davvero — un autore esterno, un'associazione, una fonte — senza creare un utente WordPress per ognuno.

Il campo è esposto nelle API REST (meta.firma). Vuoto = comportamento normale. Il link della firma continua a puntare all'archivio dell'utente che ha pubblicato.

Nessuna configurazione.

bottega-smtp.php — SMTP

Fa uscire tutte le mail di WordPress da un server SMTP, invece che dal mail() locale che in un container non esiste (e che da molti cloud non esce comunque: la porta 25 è chiusa). Funziona sia con un relay esterno autenticato, sia con un server di posta proprio sulla rete interna.

Con un relay esterno, con utente e password:

define('SMTP_HOST',      'smtp-relay.example.com');
define('SMTP_PORT',      587);
define('SMTP_USER',      'utente');
define('SMTP_PASS',      'chiave');
define('SMTP_FROM',      'blog@example.org');
define('SMTP_FROM_NAME', 'Il mio blog');

Con un server proprio sulla rete interna, che riconosce il blog dal suo indirizzo e non chiede credenziali:

define('SMTP_HOST',                 '10.0.0.25');
define('SMTP_PORT',                 25);
define('SMTP_USER',                 '');
define('SMTP_FROM',                 'blog@example.org');
define('SMTP_FROM_NAME',            'Il mio blog');
define('BOTTEGA_SMTP_INSECURE_TLS', true);

Se SMTP_HOST manca o è vuota, il plugin non fa nulla. L'autenticazione si attiva solo se SMTP_USER non è vuota. La connessione usa sempre STARTTLS: con BOTTEGA_SMTP_INSECURE_TLS a true il certificato del server non viene verificato, cosa sensata solo su una rete privata verso un server con un certificato autofirmato (la connessione resta cifrata, ma non protegge da chi si mette in mezzo). Il nome usato nel Message-ID e nel saluto al server è il dominio di SMTP_FROM, così i messaggi non escono come @localhost.

Le credenziali tenetele fuori dal repo (per esempio in un .env letto dal compose e passato a wp-config.php con getenv()).

bottega-cache.php — Cache purge

Quando cambia qualcosa di visibile — articolo pubblicato, aggiornato o ritirato, commento approvato, widget, menu, tema — crea un file vuoto in una cartella. Un processo esterno che osserva quella cartella svuota la cache di pagina.

define('BOTTEGA_PURGE_DIR', '/var/run/purge');   // default

È pensato per nginx con fastcgi_cache in un container separato da PHP: nginx scrive i file di cache con un utente suo e PHP non può cancellarli. La soluzione è un sidecar minimo che condivide il volume della cache e ascolta la cartella. Esempio con busybox (da adattare):

purger:
  image: alpine:3.20
  restart: unless-stopped
  network_mode: none
  mem_limit: 32m
  command: >
    sh -c "chmod 1777 /purge &&
    inotifyd - /purge:n | while read ev; do
      find /var/cache/nginx/wp -type f -delete; rm -f /purge/*;
      echo \"$$(date -u '+%F %T') cache svuotata\"; done"
  volumes:
    - nginx-cache:/var/cache/nginx
    - purge-flag:/purge

Il container PHP monta lo stesso volume purge-flag su /var/run/purge (o dove dice BOTTEGA_PURGE_DIR). Il chmod 1777 serve perché a scrivere nella cartella è l'utente di PHP, non root.

Senza il sidecar il plugin non fa danni: scrive file in una cartella che nessuno legge.

bottega-opengraph.php — Open Graph

Emette i tag og:* e twitter:card per le anteprime dei link su Mastodon, Telegram, Facebook, Signal: titolo, riassunto, immagine in evidenza, data. Sulla home usa l'icona del sito. Lingua da get_locale().

Nessuna configurazione. Se avete già un plugin SEO che li genera, non usate anche questo.

bottega-feeds.php — Feed esterni

Uno shortcode per mostrare un feed RSS esterno in un widget, con la funzione fetch_feed che WordPress ha già dentro:

[bottega_feed url="https://example.org/feed/" title="Titolo" n="5"]

Funziona anche dentro i widget a blocchi. Icona opzionale accanto al titolo:

define('BOTTEGA_FEED_ICON', '/wp-content/uploads/feed-icon.svg');

Il markup usa la classe widgettitle del tema Dynamic News Lite; con altri temi potrebbe servire un ritocco al CSS.

bottega-feed-images.php — Immagini nel feed

Mette l'immagine in evidenza in testa a ogni voce del feed RSS, solo se il corpo dell'articolo non contiene già un'immagine. Per i lettori di feed. Nessuna configurazione.

bottega-umami.php — Umami

Carica lo script di Umami solo per i visitatori non loggati, con un tag per tipo di pagina (home, articolo, pagina, archivio) e le Web Vitals.

Sugli articoli invia un evento lettura, una volta per pagina, quando il lettore è rimasto almeno 30 secondi con la scheda in primo piano e ha scorso metà del testo. L'evento porta con sé firma, categoria e anno di pubblicazione.

Mostra in cima alla sidebar un contatore "Visitatori": i visitatori unici di oggi, del mese e dell'anno, e sotto quanti oggi sono rimasti a leggere (le persone che hanno fatto scattare lettura). Si aggiorna ogni ora via WP-Cron leggendo le API di Umami.

define('UMAMI_URL',  'https://stats.example.org');
define('UMAMI_SITE', 'uuid-del-sito');
define('UMAMI_USER', 'utente-di-servizio');       // solo per il contatore
define('UMAMI_PASS', 'password');                 // idem
define('BOTTEGA_UMAMI_SINCE', '4 settembre 2026'); // opzionale, "dal …" nel contatore
define('BOTTEGA_UMAMI_LETTURA_SEC', 30);           // opzionale, secondi in primo piano
define('BOTTEGA_UMAMI_LETTURA_QUOTA', 50);         // opzionale, percentuale di testo scorso
define('BOTTEGA_UMAMI_CAT_JOLLY', 'articolo');     // opzionale, slug della categoria generica da ignorare

Il contatore si inserisce nella sidebar con id sidebar e usa il markup di Dynamic News Lite. L'evento lettura misura lo scorrimento sul blocco #content .entry dello stesso tema. Per il solo tracking bastano UMAMI_URL e UMAMI_SITE.

bottega-login-alert.php — Avviso login

Avvisa quando un account condiviso entra in WordPress: serve a sapere chi usa un login comune, per esempio prima di dividerlo in account personali. A ogni accesso dell'utente indicato manda una mail e/o una notifica ntfy con IP, data e ora, e user agent.

define('BOTTEGA_LOGIN_ALERT_USER', 'utente-condiviso');
define('BOTTEGA_LOGIN_ALERT_TO',   'redazione@example.org');        // opzionale, avviso via mail
define('BOTTEGA_NTFY_URL',  'https://ntfy.example.org/argomento');  // opzionale, avviso via ntfy
define('BOTTEGA_NTFY_USER', 'utente-in-sola-scrittura');            // idem
define('BOTTEGA_NTFY_PASS', 'password');                            // idem

Senza BOTTEGA_LOGIN_ALERT_USER il plugin non fa niente. Per ntfy servono tutte e tre le costanti BOTTEGA_NTFY_*; la mail parte con wp_mail, quindi passa dal plugin SMTP.

Sostituisce i plugin di consenso esterni. Mostra un banner in italiano e blocca i contenuti di altri siti finché il lettore non sceglie: gli embed automatici di WordPress (URL da solo sulla riga e [embed]) e gli iframe scritti a mano diventano un riquadro "Contenuto esterno da …", con il nome del servizio che punta all'originale.

  • Accetta tutto: i contenuti esterni si caricano subito.
  • Solo essenziali: il riquadro ha il pulsante "Carica qui", contenuto per contenuto.
  • Rifiuta: resta solo il link al sito d'origine.

La scelta resta nel browser del lettore (localStorage, nessun cookie) e il link "Preferenze cookie" in fondo alla pagina riapre il banner. Il server manda a tutti la stessa pagina e decide il browser cosa caricare, quindi la cache di nginx funziona come prima: dopo una modifica al plugin basta svuotarla. Feed, API REST e amministrazione non vengono toccati.

define('BOTTEGA_INFORMATIVA_URL', 'https://example.org/privacy/'); // opzionale, altrimenti la pagina privacy di WordPress

bottega-appuntamenti.php — Appuntamenti

Gestisce gli appuntamenti del blog (presentazioni, incontri, presidi) come un tipo di contenuto a sé, appuntamento, separato dagli articoli. Ogni appuntamento ha titolo, data, ora facoltativa, luogo, descrizione e link facoltativo.

Due shortcode:

[bottega_appuntamenti]
[bottega_appuntamenti_widget n="5" title="Appuntamenti"]

Il primo va in una pagina (sul nostro sito /appuntamenti/) e mostra l'elenco completo dei prossimi appuntamenti. Chi può scrivere articoli vede nella stessa pagina anche un modulo per aggiungerne di nuovi e i link per modificarli o eliminarli, senza passare dalla bacheca. Il secondo va in un blocco Shortcode della sidebar (un blocco Paragrafo non esegue gli shortcode nei widget) e mostra i prossimi n appuntamenti in forma compatta, con il link alla pagina. In bacheca gli stessi campi sono sotto la voce Appuntamenti.

Un appuntamento resta visibile per tutto il suo giorno. Dopo la mezzanotte esce dagli elenchi, e un evento cron giornaliero (bottega_app_pulizia, alle 00:05 ora del sito) lo sposta nel cestino, da cui WordPress lo cancella dopo 30 giorni (il default). "Oggi" dipende dal fuso orario impostato in WordPress.

Se è presente bottega-cache.php, ogni inserimento, modifica, eliminazione e pulizia svuota la cache delle pagine.

Configurazione facoltativa, solo se la pagina con l'elenco non è /appuntamenti/:

define('BOTTEGA_APP_PAGE', '/eventi/');

bottega-autore.php — Riquadro autore

Aggiunge in fondo a ogni articolo il riquadro "Informazioni sull'autore": foto, nome, biografia del profilo, link a tutti i suoi articoli e un'icona per ogni profilo che l'autore ha indicato (Mastodon, Facebook, Instagram, LinkedIn, Twitter, YouTube, sito web).

I link si compilano nella pagina del profilo utente, tra i contatti. Nella stessa pagina il campo "Foto autore" accetta l'ID di un'immagine della libreria Media, da usare al posto di Gravatar.

define('BOTTEGA_AUTORE_TITOLO', "Informazioni sull'autore"); // opzionale
define('BOTTEGA_AUTORE_TIPI',   'post');                     // opzionale, tipi di contenuto separati da virgola

Le icone sono SVG incorporati nel file (Simple Icons, CC0): nessun font e nessuna richiesta esterna. La funzione bottega_icona('mastodon') restituisce l'SVG e si può riusare in altri plugin. L'elenco delle reti si cambia con il filtro bottega_autore_reti.

bottega-condividi.php — Condividi

Aggiunge in fondo a ogni articolo, prima del riquadro autore, un riquadro "Condividi questo articolo" con un pulsante verso un'istanza Mastodon. È un link alla pagina di condivisione dell'istanza, con titolo e indirizzo dell'articolo già compilati: nessuno script e nessuna richiesta a terzi finché il lettore non clicca.

define('BOTTEGA_CONDIVIDI_ISTANZA', 'sociale.network'); // opzionale, l'istanza a cui punta il pulsante
define('BOTTEGA_CONDIVIDI_TIPI',    'post');            // opzionale, tipi di contenuto separati da virgola

Il pulsante serve a chi ha un account su quell'istanza. L'icona viene da bottega-autore.php: senza quel plugin il pulsante resta, senza icona.

bottega-stile.php — Stile

Ritocchi di stile al tema senza toccarne i file. Per ora uno solo: il colore del bordo che Dynamic News Lite disegna attorno ad articoli, pagine, widget, archivi, paginazione e commenti.

define('BOTTEGA_STILE_BORDO', '#c0c0c0'); // opzionale

Licenza

GPLv3. Vedi LICENSE.