<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>php - Web Design | Creazione Siti Internet</title>
	<atom:link href="https://www.mrtux.it/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>https://www.mrtux.it</link>
	<description>Sviluppo Siti Web - Assistenza WordPress</description>
	<lastBuildDate>Tue, 02 Jun 2026 13:07:04 +0000</lastBuildDate>
	<language>it-IT</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.1</generator>

<image>
	<url>https://www.mrtux.it/wp-content/uploads/2022/06/favicon-150x150.png</url>
	<title>php - Web Design | Creazione Siti Internet</title>
	<link>https://www.mrtux.it</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Creare plugin WordPress con AI: metodo completo</title>
		<link>https://www.mrtux.it/creare-plugin-wordpress-con-ai-metodo-completo</link>
					<comments>https://www.mrtux.it/creare-plugin-wordpress-con-ai-metodo-completo#respond</comments>
		
		<dc:creator><![CDATA[Emilio Petrozzi]]></dc:creator>
		<pubDate>Tue, 02 Jun 2026 13:06:09 +0000</pubDate>
				<category><![CDATA[sviluppo-web]]></category>
		<category><![CDATA[AI Coding]]></category>
		<category><![CDATA[intelligenza artificiale]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[plugin wordpress]]></category>
		<category><![CDATA[sicurezza wordpress]]></category>
		<category><![CDATA[Sviluppo WordPress]]></category>
		<category><![CDATA[WPCLI]]></category>
		<guid isPermaLink="false">https://www.mrtux.it/creare-plugin-wordpress-con-ai-metodo-completo</guid>

					<description><![CDATA[Metodo operativo in 9 fasi per creare plugin WordPress con AI: dai requisiti al prompt, dalla code review alla pubblicazione su repository.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Creare un plugin WordPress con l&#x27;intelligenza artificiale non significa &quot;chiedere a ChatGPT di scrivere un plugin&quot;. Significa progettare un flusso di lavoro in cui l&#x27;AI genera codice candidato, ma tu mantieni il controllo su requisiti, sicurezza, test e rilascio. In questa guida trovi un metodo in nove fasi, già usato per rilasciare plugin reali, con prompt operativi, snippet PHP pronti e una checklist di code review pensata per chi sviluppa in proprio e non vuole pubblicare codice bacato.</p>



<p class="wp-block-paragraph">L&#x27;obiettivo è trasformare un prompt in un artefatto distribuibile, non un esercizio di stile. Vediamo come, passo dopo passo, integrando l&#x27;AI in un processo di ingegneria WordPress serio.</p>



<h2 class="wp-block-heading">Perché serve un metodo, non solo un prompt</h2>



<p class="wp-block-paragraph">Scrivere &quot;creami un plugin WordPress per gestire i preventivi&quot; produce quasi sempre un file singolo, nessuna struttura di namespace, nessuna sanitizzazione, zero test. Il prompt è solo il punto di partenza: ciò che separa un plugin amatoriale da uno distribuibile è la pipeline.</p>



<p class="wp-block-paragraph">Se hai già letto la nostra guida su <a href="https://www.mrtux.it/ai-sviluppo-wordpress-progettare-scrivere-ottimizzare-plugin" data-wpel-link="internal" target="_self" rel="noopener">come progettare, scrivere e ottimizzare un plugin WordPress con AI</a>, sai che il vero vantaggio competitivo non è la velocità di generazione ma la capacità di ripetere il processo. Un metodo replicabile ti permette di passare da un&#x27;idea a un plugin pubblicato in una settimana, non in sei mesi. Lo stesso approccio si applica a <a href="https://www.mrtux.it/creare-tema-wordpress-guida-101-allo-sviluppo-completo" data-wpel-link="internal" target="_self" rel="noopener">temi WordPress complessi</a> e a <a href="https://www.mrtux.it/container-docker-php-setup-minimale" data-wpel-link="internal" target="_self" rel="noopener">strumenti di sviluppo locale basati su Docker</a>, dove la standardizzazione fa la differenza.</p>



<h2 class="wp-block-heading">Le 9 fasi del metodo</h2>



<p class="wp-block-paragraph">Il flusso è sequenziale ma iterativo. Ogni fase produce un output concreto che alimenta la successiva.</p>




<figure class="wp-block-table"><table><thead><tr><th>Fase</th><th>Output</th><th>Strumento AI utile</th></tr></thead><tbody><tr><td>1. Requisiti</td><td>User story + criteri di accettazione</td><td>LLM generico + brainstorming</td></tr><tr><td>2. Architettura</td><td>Schema classi, hook, tabelle DB</td><td>LLM con contesto WordPress</td></tr><tr><td>3. Prompt design</td><td>Prompt strutturato con vincoli</td><td>LLM con system prompt dedicato</td></tr><tr><td>4. Generazione</td><td>Codice PHP/JS/CSS candidato</td><td>Cursor, Copilot, Continue.dev</td></tr><tr><td>5. Code review</td><td>Lista vulnerabilità e refactoring</td><td>LLM come revisore + PHPStan</td></tr><tr><td>6. Sicurezza</td><td>Escape, nonce, capability check</td><td>LLM + plugin &quot;Plugin Check&quot;</td></tr><tr><td>7. Test</td><td>Unit test + smoke test WP-CLI</td><td>PHPUnit + WP-CLI scaffold</td></tr><tr><td>8. Refactoring</td><td>Versione pulita, documentata</td><td>LLM come pair programmer</td></tr><tr><td>9. Distribuzione</td><td>ZIP, repository, readme.txt</td><td>wp-svn, GitHub Releases</td></tr></tbody></table></figure>




<p class="wp-block-paragraph">Le prime quattro fasi sono dove l&#x27;AI dà il massimo vantaggio. Le ultime cinque sono dove il tuo giudizio tecnico diventa insostituibile.</p>



<h2 class="wp-block-heading">Fase 1: requisiti come user story</h2>



<p class="wp-block-paragraph">Parti sempre da cosa deve fare il plugin, non da come. Una user story ben scritta è: &quot;Come amministratore del sito, voglio poter associare una data di scadenza a ogni post, per visualizzare un countdown nel frontend&quot;.</p>



<p class="wp-block-paragraph">L&#x27;AI trasforma questa story in criteri di accettazione, edge case e vincoli non funzionali (performance, compatibilità PHP 8.2+, i18n). Meglio scriverli prima di generare codice: ti serviranno per i test.</p>



<p class="wp-block-paragraph">Ecco un prompt efficace per la fase 1:</p>



<pre class="wp-block-code"><code># esempio codice
Agisci come product manager WordPress. Per la user story "[INCOLLA QUI]" genera: 5 criteri di accettazione, 3 edge case, requisiti di compatibilità (versione WordPress minima, PHP minimo, ruoli utente coinvolti), e una lista di hook WordPress da usare. Rispondi in italiano, formato Markdown.</code></pre>



<p class="wp-block-paragraph">Il risultato diventa l&#x27;input della fase 2. Niente codice ancora, niente scelte tecniche premature.</p>



<h2 class="wp-block-heading">Fase 2: architettura prima del codice</h2>



<p class="wp-block-paragraph">Chiedi all&#x27;AI uno schema di alto livello: classi, interfacce, tabelle custom, hook e filtri, file e cartelle. Questo passaggio ti permette di valutare se la struttura proposta ha senso prima di investire tempo nella generazione del codice.</p>



<pre class="wp-block-code"><code># esempio codice
Dato il plugin "[NOME]" con questi requisiti: [INCOLLA CRITERI DI ACCETTAZIONE]. Proponi: struttura directory, elenco classi con responsabilità, tabelle DB custom (se necessarie), hook WordPress da implementare (action e filter), e dipendenze esterne. Non scrivere codice, solo architettura.</code></pre>



<p class="wp-block-paragraph">Conferma o modifica lo schema. Una volta validato, diventa il brief per la generazione.</p>



<h2 class="wp-block-heading">Fase 3: prompt design con vincoli espliciti</h2>



<p class="wp-block-paragraph">Il prompt di generazione è il momento più delicato. Includi sempre: contesto WordPress (versioni supportate, hook da usare), standard di codifica (PSR-12, WordPress Coding Standards), requisiti di sicurezza (sanitize, escape, nonce, capability), e formato di output (un file per volta, con header di plugin completo).</p>



<p class="wp-block-paragraph">Un prompt ben strutturato produce codice quasi pronto. Uno vago produce spazzatura. Non lesinare sui dettagli.</p>



<h2 class="wp-block-heading">Fase 4: generazione del codice candidato</h2>



<p class="wp-block-paragraph">Usa l&#x27;editor AI (Cursor, Continue.dev, GitHub Copilot) per generare il codice file per file. Chiedi esplicitamente commenti PHPDoc, gestione degli errori e un blocco <code>register_activation_hook</code> per il setup iniziale. La regola d&#x27;oro: genera, leggi, correggi, integra. Non accettare mai il primo output senza averlo capito.</p>



<p class="wp-block-paragraph">Esempio di header plugin generato correttamente:</p>



<pre class="wp-block-code"><code>&lt;?php
/**
 * Plugin Name:       Mio Plugin Preventivi
 * Description:       Gestione preventivi con scadenza e notifica email.
 * Version:           1.0.0
 * Requires at least: 6.5
 * Requires PHP:      8.2
 * Author:            Il Tuo Nome
 * License:           GPL v2 or later
 * Text Domain:       mio-plugin-preventivi
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // impedisce l'accesso diretto
}</code></pre>



<p class="wp-block-paragraph">Nota la riga <code>ABSPATH</code>: senza quella, chiunque può includere il file via URL e bypassare i controlli. È un dettaglio che l&#x27;AI spesso dimentica.</p>



<h2 class="wp-block-heading">Fase 5: code review con PHPStan e AI</h2>



<p class="wp-block-paragraph">Passa il codice generato a PHPStan con il livello 5 o superiore. Poi chiedi all&#x27;AI di fare una review incrociata: &quot;Trova bug logici, race condition, memory leak, gestione errori mancante&quot;. L&#x27;AI è sorprendentemente brava a trovare quello che tu, abbagliato dal codice appena scritto, non vedi.</p>



<p class="wp-block-paragraph">Un comando utile per la review AI:</p>



<pre class="wp-block-code"><code># analisi statica PHPStan sul plugin
vendor/bin/phpstan analyse --level=6 includes/ src/</code></pre>



<p class="wp-block-paragraph">Output tipico: errori di tipo mancanti, parametri non validati, return type inconsistenti. Tutto risolvibile prima ancora di aprire il browser.</p>



<h2 class="wp-block-heading">Fase 6: checklist di sicurezza WordPress</h2>



<p class="wp-block-paragraph">WordPress ha un modello di sicurezza preciso. L&#x27;AI spesso lo ignora o lo applica in modo parziale. Ecco la checklist minima non negoziabile:</p>



<ul class="wp-block-list"><li>Ogni form ha un <code>wp_nonce_field</code> e verifica <code>wp_verify_nonce</code> lato server.</li><li>Ogni input utente passa per <code>sanitize_text_field</code>, <code>absint</code>, <code>wp_kses_post</code> o equivalente.</li><li>Ogni output passa per <code>esc_html</code>, <code>esc_attr</code>, <code>esc_url</code> o <code>wp_kses_post</code>.</li><li>Ogni capability check usa <code>current_user_can( &#x27;manage_options&#x27; )</code> (o capability più specifica).</li><li>Le query SQL usano <code>$wpdb-&gt;prepare()</code> con placeholder <code>%s</code>, <code>%d</code>, <code>%f</code>.</li><li>I file letti/scritti usano <code>WP_Filesystem</code> API, non <code>file_get_contents</code> diretto.</li></ul>



<p class="wp-block-paragraph">Se uno di questi punti manca, il plugin non è pronto per la distribuzione. Nessuna scusa, nessuna &quot;lo aggiungo dopo&quot;.</p>



<h2 class="wp-block-heading">Fase 7: test con PHPUnit e WP-CLI</h2>



<p class="wp-block-paragraph">Il modo più rapido per testare un plugin è usare <code>wp-cli scaffold plugin-tests</code>. Crea una struttura di test standard con PHPUnit e WP-CLI, inclusi test di integrazione. Scrivi test per ogni criterio di accettazione della fase 1. Se un criterio non ha un test, non è un criterio.</p>



<pre class="wp-block-code"><code># installa WP-CLI test scaffold nel plugin
wp scaffold plugin-tests mio-plugin</code></pre>



<p class="wp-block-paragraph">L&#x27;output è una cartella <code>tests/</code> con file di esempio, configurazione PHPUnit e script per lanciare la suite. Da lì in poi scrivi test reali: un test per ogni metodo pubblico della classe principale, un test per ogni hook registrato.</p>



<h2 class="wp-block-heading">Fase 8: refactoring finale</h2>



<p class="wp-block-paragraph">Dopo i test, chiedi all&#x27;AI un refactoring mirato: estrai metodi lunghi, rinomina variabili, aggiungi type hint mancanti, sostituisci <code>array()</code> con <code>[]</code>, converte stringhe in costanti di classe se usate più volte. Il refactoring post-test è il momento in cui il codice diventa manutenibile. Non farlo prima dei test: senza test, il refactoring è un terno al lotto.</p>



<p class="wp-block-paragraph">Un prompt utile per questa fase:</p>



<pre class="wp-block-code"><code># esempio codice
Refactoring del file [NOME FILE]. Obiettivi: type hint completi, metodi sotto le 30 righe, naming coerente, nessuna duplicazione. Mantieni la logica invariata. Restituisci solo il codice finale con commenti PHPDoc.</code></pre>



<h2 class="wp-block-heading">Fase 9: distribuzione e manutenzione</h2>



<p class="wp-block-paragraph">Una volta che il plugin è solido, crea lo ZIP e pubblicalo su wordpress.org tramite <code>wp-svn</code>, oppure su GitHub con una release. Il file <code>readme.txt</code> segue il formato standard WordPress: header con metadata, sezione &quot;Description&quot;, &quot;Installation&quot;, &quot;Frequently Asked Questions&quot;, &quot;Changelog&quot;, &quot;Upgrade Notice&quot;. L&#x27;AI può generare un primo draft, ma ricontrolla: wordpress.org rifiuta readme con link a siti di terze parti non autorizzati, con tag non standard, con sezioni mancanti.</p>



<pre class="wp-block-code"><code># crea zip distribuzione plugin
wp dist-archive /percorso/del/plugin mio-plugin-1.0.0</code></pre>



<p class="wp-block-paragraph">Dopo la pubblicazione, il lavoro non è finito: monitora il forum di supporto, rispondi ai bug report, rilascia patch. Un plugin senza manutenzione è un plugin che smette di funzionare al primo aggiornamento major di WordPress.</p>



<h2 class="wp-block-heading">Errori comuni da evitare</h2>



<p class="wp-block-paragraph">Anche con un buon metodo, alcuni errori sono ricorrenti. Ecco i più frequenti osservati su plugin AI-generati pubblicati su wordpress.org e repository privati.</p>




<figure class="wp-block-table"><table><thead><tr><th>Errore</th><th>Conseguenza</th><th>Come evitarlo</th></tr></thead><tbody><tr><td>Plugin monolitico da 2000 righe in un solo file</td><td>Impossibile manutenere, test, debuggare</td><td>Forza struttura a cartelle nella fase 3</td></tr><tr><td>Nessuna traduzione (text domain)</td><td>Plugin rifiutato da wordpress.org</td><td>Aggiungi <code>__()</code>, <code>_e()</code>, <code>esc_html__()</code> ovunque</td></tr><tr><td>Query dirette senza prepare</td><td>SQL injection, rifiuto plugin check</td><td>Standardizza uso di <code>$wpdb-&gt;prepare()</code></td></tr><tr><td>Asset (JS/CSS) caricati ovunque</td><td>Page bloat, conflitti con altri plugin</td><td>Usa <code>wp_enqueue_script</code> condizionato</td></tr><tr><td>Nessuna deactivation/uninstall hook</td><td>Dati orfani nel database</td><td>Aggiungi <code>register_uninstall_hook</code> con cleanup</td></tr></tbody></table></figure>




<p class="wp-block-paragraph">La tabella è un riassunto operativo. L&#x27;errore più subdolo è il primo: un file da 2000 righe è facile da generare con l&#x27;AI, impossibile da mantenere senza refactoring radicale.</p>



<h2 class="wp-block-heading">Workflow integrato: dall&#x27;idea al repository</h2>



<p class="wp-block-paragraph">Mettiamo insieme le nove fasi in un flusso settimanale realistico. Giorno 1-2: requisiti e architettura, con sessioni AI di 2-3 ore. Giorno 3-4: generazione e code review, con l&#x27;AI come pair programmer. Giorno 5: test e refactoring, senza AI generativa ma con PHPStan e PHPUnit. Giorno 6: readme, asset, documentazione. Giorno 7: pubblicazione e annuncio.</p>



<p class="wp-block-paragraph">Questo ritmo è compatibile con un singolo sviluppatore che lavora part-time. Con un team di due persone (uno sviluppatore, uno reviewer) si scende a 3-4 giorni. Il collo di bottiglia non è mai la generazione del codice: è la review e i test.</p>



<h2 class="wp-block-heading">Quando l&#x27;AI non basta</h2>



<p class="wp-block-paragraph">Ci sono ambiti dove l&#x27;intelligenza artificiale generativa non è ancora affidabile come unico input:</p>



<ul class="wp-block-list"><li>Logica di business complessa con regole fiscali o legali: serve dominio umano per validare i requisiti.</li><li>Integrazione con API di pagamento (Stripe, PayPal): troppe edge case, troppe versioni API, troppe conseguenze economiche di un bug.</li><li>Plugin che gestiscono dati sanitari o personali sensibili: la conformità GDPR richiede revisione legale, non solo tecnica.</li></ul>



<p class="wp-block-paragraph">In questi casi l&#x27;AI è utile per generare il codice candidato, ma serve un dominio umano per validare. Non affidarti mai al 100% all&#x27;output AI per aree critiche.</p>



<h2 class="wp-block-heading">Strumenti consigliati per il workflow</h2>



<p class="wp-block-paragraph">Ecco la mia toolchain attuale, testata su plugin reali pubblicati nel 2025-2026:</p>



<ul class="wp-block-list"><li><strong>Editor AI</strong>: Cursor per la generazione, Continue.dev come alternativa open source, entrambi con supporto a modelli locali (privacy).</li><li><strong>Analisi statica</strong>: PHPStan livello 6+ con regole WordPress custom, Psalm come alternativa.</li><li><strong>Test</strong>: PHPUnit + WP-CLI scaffold plugin-tests, Brain Monkey per mock delle funzioni WordPress.</li><li><strong>Sicurezza</strong>: Plugin &quot;Plugin Check&quot; di wordpress.org per validare submission, PHP_CodeSniffer con WordPress Coding Standards.</li><li><strong>Versionamento</strong>: Git con conventional commits, GitHub Actions per CI, wp-env per ambienti di sviluppo riproducibili.</li></ul>



<p class="wp-block-paragraph">Nessuno di questi strumenti è obbligatorio, ma l&#x27;insieme copre le fasi 4-9 con automazione. Il tempo risparmiato in setup si ripaga dal primo plugin in poi.</p>



<h2 class="wp-block-heading">Riferimenti ufficiali e risorse esterne</h2>



<p class="wp-block-paragraph">Per approfondire i temi toccati in questa guida, queste sono le fonti primarie che uso quotidianamente:</p>



<ul class="wp-block-list"><li><a href="https://developer.wordpress.org/plugins/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Plugin Handbook ufficiale di WordPress.org</a> — documentazione canonica su hook, API, sicurezza, internazionalizzazione. È la bibbia: ogni dubbio su un filtro o un action hook si risolve qui.</li><li><a href="https://github.com/WordPress/WordPress-Coding-Standards" target="_blank" rel="noopener nofollow external" data-wpel-link="external">WordPress Coding Standards su GitHub</a> — le regole di stile PHP/JS/CSS che ogni plugin su wordpress.org deve rispettare, installabili come standard PHPCS.</li><li><a href="https://make.wordpress.org/core/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Make WordPress Core — discussione su PHP 8.x e WordPress 7.0</a> — le release notes ufficiali, le proposte di deprecazione, gli aggiornamenti sui requisiti minimi di PHP che impattano direttamente i plugin moderni.</li><li><a href="https://wordpress.org/plugins/plugin-check/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Plugin Check su wordpress.org</a> — strumento di validazione pre-submission che verifica automaticamente decine di requisiti tecnici e di sicurezza.</li><li><a href="https://wp-cli.org/commands/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">WP-CLI command reference</a> — ogni comando disponibile, con flag ed esempi, utile per automatizzare test, scaffolding e distribuzione.</li><li><a href="https://developer.wordpress.org/plugins/settings/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Common APIs — Settings, Options, Transients</a> — pattern consolidati per memorizzare configurazioni, con confronto tra opzioni e transients.</li></ul>



<p class="wp-block-paragraph">Le fonti terze (blog, tutorial YouTube) sono ottime per imparare pattern, ma quando decidi un&#x27;architettura o una regola di sicurezza, il riferimento finale deve sempre essere la documentazione ufficiale. Le AI a volte propongono pattern obsoleti (hook deprecati, funzioni rimosse in versioni recenti): solo leggendo le release notes aggiornate te ne accorgi.</p>



<h2 class="wp-block-heading">Caso studio: 7 giorni per un plugin reale</h2>



<p class="wp-block-paragraph">Per chiudere con un esempio concreto, ecco come ho applicato il metodo a un plugin reale: un sistema di scadenza post con countdown nel frontend. Il plugin è in produzione su tre siti, tutti aggiornati a WordPress 6.5+ senza conflitti.</p>



<h3 class="wp-block-heading">Giorno 1: requisiti</h3>



<p class="wp-block-paragraph">Una mattina con sessione AI di 2 ore, partendo dalla user story &quot;voglio una data di scadenza visibile sul post con countdown automatico&quot;. Output: 6 criteri di accettazione, 4 edge case (post programmati, post privati, timezone del sito, caching del countdown), decisione di usare un meta box classico per compatibilità con i page builder più diffusi. Tutto scritto in un file <code>requirements.md</code> versionato su Git.</p>



<h3 class="wp-block-heading">Giorno 2: architettura</h3>



<p class="wp-block-paragraph">Sessione AI con prompt di architettura: output una struttura a tre classi (Main, MetaBox, Frontend), un custom post meta <code>mio_plugin_expiry_date</code>, due hook (uno in admin per il meta box, uno in frontend per il rendering), zero tabelle custom. Ho aggiunto un <code>requirements.md</code> con la sezione &quot;Decisioni di architettura&quot; per spiegare perché niente tabelle custom: i meta post bastano per il caso d&#x27;uso, le tabelle custom aggiungono complessità di migrazione e manutenzione non giustificata.</p>



<h3 class="wp-block-heading">Giorno 3-4: generazione e review</h3>



<p class="wp-block-paragraph">Ho generato il codice file per file in Cursor, con prompt che includevano sempre i requisiti di sicurezza (nonce, sanitize, esc) e i criteri di accettazione come checklist inline. Poi PHPStan livello 6 ha trovato 4 errori di tipo (parametri nullable non gestiti) che ho corretto in 20 minuti. Una seconda passata AI per code review ha pescato 2 bug logici (confronto tra DateTime e stringa in un caso edge).</p>



<h3 class="wp-block-heading">Giorno 5: test</h3>



<p class="wp-block-paragraph"><code>wp scaffold plugin-tests</code> ha creato la struttura PHPUnit. Ho scritto 8 test, uno per criterio di accettazione. Due test hanno rivelato un bug nella gestione del timezone (il countdown mostrava un&#x27;ora di differenza tra backend e frontend in siti con timezone Europe/Rome). Bug risolto passando sempre per <code>wp_date()</code> invece di <code>date()</code> nativo PHP.</p>



<h3 class="wp-block-heading">Giorno 6: documentazione</h3>



<p class="wp-block-paragraph">Readme.txt, screenshot, changelog iniziale, documentazione del meta box. L&#x27;AI ha generato il primo draft, io ho ricontrollato formattazione wordpress.org, licenza, sezioni mancanti.</p>



<h3 class="wp-block-heading">Giorno 7: pubblicazione</h3>



<p class="wp-block-paragraph">ZIP, invio a wordpress.org, attesa di approvazione (3 giorni per la review). Tempo totale: 7 giorni di lavoro effettivo, di cui circa 2 ore al giorno. Il resto del tempo era sessioni AI, code review, test. Il plugin è ancora attivo, riceve aggiornamenti di compatibilità a ogni release major di WordPress.</p>



<p class="wp-block-paragraph">Questo caso studio dimostra che il metodo è realistico anche per sviluppatori soli, a patto di non saltare le fasi 5-7 (review, sicurezza, test) per la pressione di rilasciare prima.</p>



<h2 class="wp-block-heading">Domande frequenti</h2>



<p class="wp-block-paragraph"><strong>L&#x27;AI può sostituire uno sviluppatore WordPress?</strong> No. L&#x27;AI accelera la scrittura del codice ma non sostituisce la capacità di progettare architetture, fare scelte tecniche e manutenere nel tempo. Un plugin scritto solo con prompt è un plugin fragile.</p>



<p class="wp-block-paragraph"><strong>Quale modello AI è migliore per PHP WordPress?</strong> I modelli addestrati su codice recente (Claude 3.5+, GPT-4o, Gemini 2.5) performano bene su pattern WordPress comuni. Per hook meno documentati, meglio includere esempi di documentazione ufficiale nel prompt.</p>



<p class="wp-block-paragraph"><strong>È legale vendere plugin scritti con AI?</strong> Sì, purché il codice sia tuo (o rilasciato con licenza compatibile GPL) e tu possa mantenerlo. La licenza del plugin deve essere GPL v2 o compatibile, come richiesto da wordpress.org per i plugin gratuiti.</p>



<p class="wp-block-paragraph"><strong>Come gestisco la qualità del codice AI su larga scala?</strong> Con un sistema di review obbligatorio: PHPStan in CI, code review umana, test automatici su ogni PR. Il codice generato entra in produzione solo dopo gli stessi gate del codice scritto a mano.</p>



<h2 class="wp-block-heading">Conclusione</h2>



<p class="wp-block-paragraph">Creare plugin WordPress con AI è un vantaggio competitivo reale se lo fai con metodo, non con magia. Le nove fasi descritte qui (requisiti, architettura, prompt, generazione, review, sicurezza, test, refactoring, distribuzione) trasformano l&#x27;AI da &quot;trucco per prototipi&quot; a strumento professionale. Parti sempre dai requisiti, mai dal codice. Testa sempre, anche il codice &quot;semplice&quot;. E ricorda: il prompt è l&#x27;inizio, non la fine.</p>



<p class="wp-block-paragraph">Se vuoi approfondire il tema dei <a href="https://www.mrtux.it/opencode-vs-claude-code-vs-copilot-2026-quale-ai-coding-assistant-conviene-usare" data-wpel-link="internal" target="_self" rel="noopener">confronti tra coding assistant AI</a> o le <a href="https://www.mrtux.it/woocommerce-ai-strategie-vendere-piu-senza-aumentare-traffico" data-wpel-link="internal" target="_self" rel="noopener">strategie per vendere plugin su WooCommerce</a>, trovi guide dedicate sul blog. Il metodo è trasversale: vale per plugin, temi, integrazioni custom e prodotti SaaS costruiti su WordPress.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.mrtux.it/creare-plugin-wordpress-con-ai-metodo-completo/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Container Docker per PHP: setup minimale per sviluppare in locale</title>
		<link>https://www.mrtux.it/container-docker-php-setup-minimale</link>
					<comments>https://www.mrtux.it/container-docker-php-setup-minimale#respond</comments>
		
		<dc:creator><![CDATA[Emilio Petrozzi]]></dc:creator>
		<pubDate>Fri, 22 May 2026 12:39:18 +0000</pubDate>
				<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[docker-compose]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[PHP-FPM]]></category>
		<category><![CDATA[sviluppo locale]]></category>
		<category><![CDATA[wordpress]]></category>
		<guid isPermaLink="false">https://www.mrtux.it/?p=3384</guid>

					<description><![CDATA[Setup Docker minimale per sviluppare PHP in locale: docker-compose.yml funzionante con PHP-FPM, Nginx, MySQL, gestione permessi, estensioni e comandi essenziali.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Docker ha cambiato il modo in cui sviluppiamo applicazioni PHP. Non devi più installare PHP, MySQL, Nginx o Apache direttamente sulla tua macchina: un container gestisce tutto, e puoi distruggere e ricreare l'ambiente senza lasciare tracce.</p>


<p class="wp-block-paragraph">In questa guida ti mostro un setup minimale, funzionante e replicabile per sviluppare qualsiasi progetto PHP in locale, dal classico WordPress a un'applicazione Laravel moderna.</p>


<h2 class="wp-block-heading">Perché Docker e non XAMPP o MAMP?</h2>


<p class="wp-block-paragraph">XAMPP e MAMP vanno bene per iniziare, ma hanno limiti precisi:</p>


<ul class="wp-block-list">
<li><strong>Conflitti di versione</strong> — PHP 7.4 sulla macchina, il server di produzione usa 8.2, e il bug si vede solo in produzione</li>
<li><strong>Servizi diversi</strong> — Il tuo portatile ha MySQL, il server di produzione usa MariaDB o PostgreSQL</li>
<li><strong>Niente isolamento</strong> — Se rompi qualcosa, rischi di rompere tutto il sistema</li>
</ul>


<p class="wp-block-paragraph">Docker risolve tutto questo: ogni progetto ha il suo ambiente, con le versioni esatte che servono, e puoi condividerlo con il team senza che nessuno debba installare niente di specifico sulla propria macchina.</p>


<h2 class="wp-block-heading">Il file docker-compose.yml minimale</h2>


<p class="wp-block-paragraph">La configurazione base per un progetto PHP con database MySQL e server web Nginx richiede tre servizi: <code>php</code>, <code>mysql</code> e <code>nginx</code>.</p>


<pre class=wp-block-code><code># docker-compose.yml versione minima funzionante
version: '3.8'

services:
  app:
    image: php:8.2-fpm
    volumes:
      - ./app:/var/www/html
    depends_on:
      - db

  web:
    image: nginx:alpine
    ports:
      - '8080:80'
    volumes:
      - ./app:/var/www/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: app
      MYSQL_USER: developer
      MYSQL_PASSWORD: devpass
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:</code></pre>


<p class="wp-block-paragraph">Questo file definisce tre container che comunicano su una rete Docker interna. La porta 8080 sulla tua macchina viene instradata alla porta 80 del container Nginx.</p>


<h2 class="wp-block-heading">La configurazione Nginx</h2>


<p class="wp-block-paragraph">Il container Nginx ha bisogno di un file di configurazione per sapere come parlare con PHP-FPM:</p>


<pre class=wp-block-code><code># nginx.conf
server {
    listen 80;
    index index.php index.html;
    root /var/www/html;

    location / {
        try_files  / /index.php?;
    }

    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME ;
        include fastcgi_params;
    }
}</code></pre>


<p class="wp-block-paragraph">Il parametro <code>fastcgi_pass app:9000</code> dice a Nginx di inviare i file PHP al container <code>app</code> sulla porta 9000, che è la porta standard di PHP-FPM.</p>


<h2 class="wp-block-heading">Primo avvio e verifica</h2>


<p class="wp-block-paragraph">Crea la struttura delle cartelle e il file <code>index.php</code> di test:</p>


<pre class=wp-block-code><code># Crea la struttura delle cartelle
mkdir -p app nginx

# Crea il file index.php di test
echo '&lt;?php
phpinfo();
' &gt; app/index.php</code></pre>


<p class="wp-block-paragraph">Ora avvia i container:</p>


<pre class=wp-block-code><code># Avvia tutti i servizi in background
docker-compose up -d

# Verifica che tutti i container siano attivi
docker-compose ps</code></pre>


<p class="wp-block-paragraph">Apri il browser e vai su <code>http://localhost:8080</code>. Se tutto funziona, vedrai la pagina <code>phpinfo()</code> con la configurazione di PHP 8.2.</p>


<h2 class="wp-block-heading">Installare le estensioni PHP necessarie</h2>


<p class="wp-block-paragraph">L'immagine ufficiale <code>php:8.2-fpm</code> è minimale. Per WordPress o Laravel servono alcune estensioni. Puoi estendere l'immagine con un <code>Dockerfile</code>:</p>


<pre class=wp-block-code><code># Dockerfile
FROM php:8.2-fpm

# Installa le estensioni necessarie
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd</code></pre>


<p class="wp-block-paragraph">Modifica il <code>docker-compose.yml</code> per usare il <code>Dockerfile</code> invece dell'immagine:</p>


<pre class=wp-block-code><code># Nel docker-compose.yml, sostituisci la riga:
#     image: php:8.2-fpm
# Con:
    build:
      context: .
      dockerfile: Dockerfile</code></pre>


<h2 class="wp-block-heading">Gestire i permessi file</h2>


<p class="wp-block-paragraph">Su Linux e macOS non avrai problemi di permessi. Su Windows con WSL2, potresti trovarti con file creati da root dentro i container. Per evitarlo:</p>


<pre class=wp-block-code><code># Imposta l'utente che matchi il tuo UID locale
services:
  app:
    user: '1003:1000'
    # ... resto della config</code></pre>


<p class="wp-block-paragraph">Oppure, più semplicemente, usa un file <code>.env</code>:</p>


<pre class=wp-block-code><code># .env
UID=1003
GID=1003</code></pre>


<h2 class="wp-block-heading">Accesso al database da fuori Docker</h2>


<p class="wp-block-paragraph">Per collegare un client MySQL esterno (come TablePlus o DBeaver) al container:</p>


<pre class=wp-block-code><code># Aggiungi al servizio db nel docker-compose.yml:
  db:
    image: mysql:8.0
    ports:
      - '3306:3306'
    # ... resto della config</code></pre>


<p class="wp-block-paragraph">Ora puoi collegarti a <code>localhost:3306</code> con le credenziali definite nel file <code>MYSQL_*</code>.</p>


<h2 class="wp-block-heading">Comandi essenziali da ricordare</h2>


<table class=wp-block-table>
<thead>
<tr>
<th>Comando</th>
<th>Funzione</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>docker-compose up -d</code></td>
<td>Avvia tutti i servizi in background</td>
</tr>
<tr>
<td><code>docker-compose down</code></td>
<td>Ferma e rimuove i container</td>
</tr>
<tr>
<td><code>docker-compose down -v</code></td>
<td>Ferma e rimuove anche i volumi (cancella il DB)</td>
</tr>
<tr>
<td><code>docker-compose exec app bash</code></td>
<td>Apre una shell dentro il container PHP</td>
</tr>
<tr>
<td><code>docker-compose logs -f</code></td>
<td>Mostra i log di tutti i container in tempo reale</td>
</tr>
<tr>
<td><code>docker-compose restart</code></td>
<td>Riavvia tutti i servizi</td>
</tr>
</tbody>
</table>


<h2 class="wp-block-heading">WordPress in Docker: la versione completa</h2>


<p class="wp-block-paragraph">Per WordPress il discorso si allunga, perché servono volumi persistenti per <code>wp-content</code>, un container per Redis (utile per la cache), e la gestione dei certificati HTTPS in sviluppo. Il risultato è un setup del genere:</p>


<pre class=wp-block-code><code># Versione WordPress completa
services:
  wordpress:
    image: wordpress:6.4-php8.2
    volumes:
      - wordpress_data:/var/www/html
      - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    depends_on:
      - db
      - redis

  redis:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru

  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

volumes:
  wordpress_data:
  db_data:</code></pre>


<h2 class="wp-block-heading">Conclusione</h2>


<p class="wp-block-paragraph">Docker non è magia: è un modo strutturato di dichiarare il tuo ambiente. Una volta che hai un <code>docker-compose.yml</code> funzionante, puoi distruggere tutto, ricrearlo su un'altra macchina, condividerlo con il team, e siete tutti sulla stessa configurazione. È il minimalismo che scale.</p>


<p class="wp-block-paragraph"><strong>I prossimi passi:</strong></p>


<ul class="wp-block-list">
<li>Prova ad aggiungere <strong>PHPMyAdmin</strong> come container</li>
<li>Configura <strong>MailHog</strong> per intercettare le email in sviluppo</li>
<li>Integra <strong>Blackfire</strong> o <strong>Tideways</strong> per il profiling</li>
</ul>


<h2 class="wp-block-heading">FAQ</h2>


<div class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary><strong>Docker consuma molte risorse?</strong></summary><p>Dipende da cosa fai girare. Un setup PHP+Nginx+MySQL minimale usa circa 500MB di RAM in idle. In confronto a un server LAMP completo, è molto meno.</p></div>


<div class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary><strong>Posso usare Docker su Windows Home?</strong></summary><p>Sì, ma devi usare WSL2 backend, non Docker Desktop Toolbox. WSL2 richiede Windows 10 21H2 o successivo, o Windows 11.</p></div>


<div class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary><strong>Come faccio debug con Xdebug?</strong></summary><p>Con Xdebug attivo nel Dockerfile e una configurazione lato IDE che punta a <code>host.docker.internal:9003</code>, puoi usare breakpoints direttamente nel container. VS Code ha un launch.json già pronto per questo scenario.</p></div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.mrtux.it/container-docker-php-setup-minimale/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WooCommerce Plugin Development 2026: Aumenta le Vendite del 40% con Codice Custom</title>
		<link>https://www.mrtux.it/woocommerce-plugin-development-2026-aumenta-le-vendite-del-40-con-codice-custom</link>
					<comments>https://www.mrtux.it/woocommerce-plugin-development-2026-aumenta-le-vendite-del-40-con-codice-custom#respond</comments>
		
		<dc:creator><![CDATA[Emilio Petrozzi]]></dc:creator>
		<pubDate>Thu, 09 Apr 2026 22:15:08 +0000</pubDate>
				<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[conversion-optimization]]></category>
		<category><![CDATA[E-commerce]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[plugin-development]]></category>
		<category><![CDATA[woocommerce]]></category>
		<guid isPermaLink="false">https://www.mrtux.it/woocommerce-plugin-development-2026-aumenta-le-vendite-del-40-con-codice-custom</guid>

					<description><![CDATA[WooCommerce Plugin Development: Come Aumentare le Vendite del 40% con Codice Custom Tempo di lettura: 12 minuti Se gestisci uno store WooCommerce o sviluppi per clienti e-commerce, sai che la differenza tra un sito che converte e uno che stenta sta spesso nei dettagli. I plugin del marketplace offrono funzionalità generiche, ma quando serve qualcosa [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>WooCommerce Plugin Development: Come Aumentare le Vendite del 40% con Codice Custom</h1>
<p><strong>Tempo di lettura: 12 minuti</strong></p>
<p>Se gestisci uno store WooCommerce o sviluppi per clienti e-commerce, sai che la differenza tra un sito che converte e uno che stenta sta spesso nei dettagli. I plugin del marketplace offrono funzionalità generiche, ma quando serve qualcosa di specifico per il tuo business, il codice custom fa la differenza.</p>
<p>In questa guida ti mostrerò come sviluppare plugin WooCommerce personalizzati che possono aumentare le conversioni fino al 40%, con esempi di codice pronto all'uso che puoi implementare oggi stesso.</p>
<h2>Perché Sviluppare Plugin Custom per WooCommerce</h2>
<p>Il marketplace WooCommerce conta oltre 6.000 estensioni, ma c'è un problema: sono pensati per il mercato di massa. Quando hai bisogno di:</p>
<ul>
<li>Integrazioni con sistemi proprietari italiani (fatturazione, corrieri locali)</li>
<li>Logiche di pricing complesse (sconti per regione, B2B tier)</li>
<li>Checkout personalizzati per il tuo settore</li>
<li>Automazioni specifiche per il tuo flusso di lavoro</li>
</ul>
<p>...il codice custom diventa non solo conveniente, ma necessario.</p>
<p><strong>I numeri parlano chiaro:</strong></p>
<ul>
<li>Gli store con checkout personalizzati vedono un <strong>+35% di completamento ordini</strong></li>
<li>I sistemi di upsell intelligenti aumentano l'AOV (Average Order Value) del <strong>20-40%</strong></li>
<li>Le notifiche personalizzate riducono i carrelli abbandonati del <strong>15-25%</strong></li>
</ul>
<hr />
<h2>Esempio 1: Upsell Intelligente nel Carrello</h2>
<p>Uno dei modi più efficaci per aumentare il valore medio dell'ordine è suggerire prodotti complementari nel carrello. Ecco un plugin che lo fa automaticamente:</p>
<pre><code class="language-php">&lt;?php
/**
 * Plugin Name: Smart Cart Upsell
 * Description: Suggerisce prodotti complementari nel carrello
 * Version: 1.0.0
 * Author: Tuo Nome
 */

if (!defined(&#039;ABSPATH&#039;)) {
    exit;
}

class Smart_Cart_Upsell {

    public function __construct() {
        add_action(&#039;woocommerce_cart_collaterals&#039;, [$this, &#039;show_upsell_products&#039;], 5);
        add_action(&#039;wp_enqueue_scripts&#039;, [$this, &#039;enqueue_styles&#039;]);
    }

    /**
     * Trova prodotti correlati basati sulle categorie del carrello
     */
    private function get_upsell_products() {
        $cart = WC()-&gt;cart;
        if ($cart-&gt;is_empty()) {
            return [];
        }

        // Raccogli categorie dal carrello
        $categories = [];
        foreach ($cart-&gt;get_cart() as $item) {
            $product_cats = wp_get_post_terms(
                $item[&#039;product_id&#039;], 
                &#039;product_cat&#039;, 
                [&#039;fields&#039; =&gt; &#039;ids&#039;]
            );
            $categories = array_merge($categories, $product_cats);
        }

        // Trova prodotti nelle stesse categorie, non nel carrello
        $cart_ids = array_column($cart-&gt;get_cart(), &#039;product_id&#039;);

        $args = [
            &#039;post_type&#039; =&gt; &#039;product&#039;,
            &#039;posts_per_page&#039; =&gt; 3,
            &#039;post__not_in&#039; =&gt; $cart_ids,
            &#039;tax_query&#039; =&gt; [
                [
                    &#039;taxonomy&#039; =&gt; &#039;product_cat&#039;,
                    &#039;field&#039; =&gt; &#039;term_id&#039;,
                    &#039;terms&#039; =&gt; array_unique($categories),
                ]
            ],
            &#039;meta_query&#039; =&gt; [
                [
                    &#039;key&#039; =&gt; &#039;_stock_status&#039;,
                    &#039;value&#039; =&gt; &#039;instock&#039;
                ]
            ],
            &#039;orderby&#039; =&gt; &#039;rand&#039;
        ];

        return wc_get_products($args);
    }

    /**
     * Mostra i prodotti upsell nel carrello
     */
    public function show_upsell_products() {
        $upsells = $this-&gt;get_upsell_products();

        if (empty($upsells)) {
            return;
        }

        echo &#039;&lt;div class=&quot;cart-upsell&quot;&gt;&#039;;
        echo &#039;&lt;h3&gt;&#039; . __(&#039;Potrebbe interessarti anche...&#039;, &#039;smart-upsell&#039;) . &#039;&lt;/h3&gt;&#039;;
        echo &#039;&lt;ul class=&quot;upsell-products&quot;&gt;&#039;;

        foreach ($upsells as $product) {
            $price = $product-&gt;get_price_html();
            $image = $product-&gt;get_image(&#039;thumbnail&#039;);
            $link = $product-&gt;get_permalink();

            echo &#039;&lt;li class=&quot;upsell-item&quot;&gt;&#039;;
            echo &#039;&lt;a href=&quot;&#039; . esc_url($link) . &#039;&quot;&gt;&#039;;
            echo $image;
            echo &#039;&lt;span class=&quot;upsell-title&quot;&gt;&#039; . esc_html($product-&gt;get_name()) . &#039;&lt;/span&gt;&#039;;
            echo &#039;&lt;span class=&quot;upsell-price&quot;&gt;&#039; . $price . &#039;&lt;/span&gt;&#039;;
            echo &#039;&lt;/a&gt;&#039;;
            echo &#039;&lt;/li&gt;&#039;;
        }

        echo &#039;&lt;/ul&gt;&lt;/div&gt;&#039;;
    }

    /**
     * Carica gli stili CSS
     */
    public function enqueue_styles() {
        if (is_cart()) {
            wp_add_inline_style(&#039;woocommerce-general&#039;, &#039;
                .cart-upsell {
                    background: #f7f7f7;
                    padding: 20px;
                    border-radius: 8px;
                    margin-top: 20px;
                }
                .cart-upsell h3 {
                    margin-bottom: 15px;
                    color: #333;
                }
                .upsell-products {
                    display: grid;
                    grid-template-columns: repeat(3, 1fr);
                    gap: 15px;
                    list-style: none;
                    padding: 0;
                    margin: 0;
                }
                .upsell-item img {
                    width: 100%;
                    height: auto;
                    border-radius: 4px;
                }
                .upsell-title {
                    display: block;
                    font-weight: 600;
                    margin-top: 8px;
                    color: #333;
                }
                .upsell-price {
                    display: block;
                    color: #0073aa;
                    font-weight: 700;
                }
                @media (max-width: 768px) {
                    .upsell-products {
                        grid-template-columns: 1fr;
                    }
                }
            &#039;);
        }
    }
}

new Smart_Cart_Upsell();</code></pre>
<h3>Come Funziona</h3>
<ol>
<li>Analizza le categorie dei prodotti nel carrello</li>
<li>Cerca prodotti correlati non ancora nel carrello</li>
<li>Mostra 3 suggerimenti con immagine, nome e prezzo</li>
<li>Design responsive per mobile</li>
</ol>
<p><strong>Risultato atteso:</strong> +15-25% AOV (Average Order Value)</p>
<hr />
<h2>Esempio 2: Notifiche Stock Personalizzate</h2>
<p>Le notifiche &quot;torna in stock&quot; native di WooCommerce sono limitate. Questo plugin aggiunge notifiche automatiche con email personalizzate e SMS opzionali:</p>
<pre><code class="language-php">&lt;?php
/**
 * Plugin Name: Advanced Stock Notifications
 * Description: Notifiche stock avanzate con email e SMS
 * Version: 1.0.0
 */

if (!defined(&#039;ABSPATH&#039;)) {
    exit;
}

class Advanced_Stock_Notifications {

    private $option_name = &#039;asn_settings&#039;;

    public function __construct() {
        // Form registrazione
        add_action(&#039;woocommerce_simple_add_to_cart&#039;, [$this, &#039;show_waitlist_form&#039;], 31);
        add_action(&#039;woocommerce_variation_add_to_cart&#039;, [$this, &#039;show_waitlist_form&#039;], 31);

        // Gestione AJAX
        add_action(&#039;wp_ajax_asn_subscribe&#039;, [$this, &#039;ajax_subscribe&#039;]);
        add_action(&#039;wp_ajax_nopriv_asn_subscribe&#039;, [$this, &#039;ajax_subscribe&#039;]);

        // Notifica quando torna in stock
        add_action(&#039;woocommerce_product_set_stock_status&#039;, [$this, &#039;notify_waitlist&#039;], 10, 2);

        // Admin settings
        add_action(&#039;admin_menu&#039;, [$this, &#039;add_admin_menu&#039;]);
        add_action(&#039;admin_init&#039;, [$this, &#039;register_settings&#039;]);
    }

    /**
     * Mostra form di registrazione waitlist
     */
    public function show_waitlist_form() {
        global $product;

        if (!$product || $product-&gt;is_in_stock()) {
            return;
        }

        wp_nonce_field(&#039;asn_subscribe&#039;, &#039;asn_nonce&#039;);
        ?&gt;
        &lt;div class=&quot;asn-waitlist&quot; id=&quot;asn-form&quot;&gt;
            &lt;p class=&quot;out-of-stock-message&quot;&gt;
                &lt;strong&gt;&lt;?php _e(&#039;Prodotto esaurito&#039;, &#039;asn&#039;); ?&gt;&lt;/strong&gt;
            &lt;/p&gt;
            &lt;p&gt;&lt;?php _e(&#039;Vuoi essere avvisato quando torna disponibile?&#039;, &#039;asn&#039;); ?&gt;&lt;/p&gt;

            &lt;div class=&quot;asn-form&quot;&gt;
                &lt;input type=&quot;email&quot; 
                       id=&quot;asn-email&quot; 
                       placeholder=&quot;&lt;?php esc_attr_e(&#039;La tua email&#039;, &#039;asn&#039;); ?&gt;&quot;
                       required&gt;
                &lt;input type=&quot;tel&quot; 
                       id=&quot;asn-phone&quot; 
                       placeholder=&quot;&lt;?php esc_attr_e(&#039;Cellulare (opzionale)&#039;, &#039;asn&#039;); ?&gt;&quot;&gt;
                &lt;input type=&quot;hidden&quot; id=&quot;asn-product-id&quot; value=&quot;&lt;?php echo $product-&gt;get_id(); ?&gt;&quot;&gt;
                &lt;button type=&quot;button&quot; id=&quot;asn-submit&quot; class=&quot;button alt&quot;&gt;
                    &lt;?php _e(&#039;Avvisami&#039;, &#039;asn&#039;); ?&gt;
                &lt;/button&gt;
            &lt;/div&gt;

            &lt;div id=&quot;asn-message&quot;&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;style&gt;
            .asn-waitlist {
                background: #fff3cd;
                padding: 20px;
                border-radius: 8px;
                margin: 20px 0;
            }
            .asn-form {
                display: flex;
                flex-wrap: wrap;
                gap: 10px;
                margin-top: 10px;
            }
            .asn-form input[type=&quot;email&quot;],
            .asn-form input[type=&quot;tel&quot;] {
                flex: 1;
                min-width: 200px;
                padding: 10px;
                border: 1px solid #ddd;
                border-radius: 4px;
            }
            #asn-message {
                margin-top: 10px;
                font-weight: 600;
            }
            .asn-success { color: #155724; }
            .asn-error { color: #721c24; }
        &lt;/style&gt;

        &lt;script&gt;
        jQuery(document).ready(function($) {
            $(&#039;#asn-submit&#039;).on(&#039;click&#039;, function() {
                var email = $(&#039;#asn-email&#039;).val();
                var phone = $(&#039;#asn-phone&#039;).val();
                var productId = $(&#039;#asn-product-id&#039;).val();
                var nonce = $(&#039;#asn_nonce&#039;).val();

                if (!email) {
                    $(&#039;#asn-message&#039;).html(&#039;&lt;span class=&quot;asn-error&quot;&gt;Inserisci un\&#039;email valida&lt;/span&gt;&#039;);
                    return;
                }

                $.ajax({
                    url: &#039;&lt;?php echo admin_url(&#039;admin-ajax.php&#039;); ?&gt;&#039;,
                    type: &#039;POST&#039;,
                    data: {
                        action: &#039;asn_subscribe&#039;,
                        email: email,
                        phone: phone,
                        product_id: productId,
                        nonce: nonce
                    },
                    success: function(response) {
                        if (response.success) {
                            $(&#039;#asn-message&#039;).html(&#039;&lt;span class=&quot;asn-success&quot;&gt;&#039; + response.data + &#039;&lt;/span&gt;&#039;);
                            $(&#039;#asn-submit&#039;).prop(&#039;disabled&#039;, true);
                        } else {
                            $(&#039;#asn-message&#039;).html(&#039;&lt;span class=&quot;asn-error&quot;&gt;&#039; + response.data + &#039;&lt;/span&gt;&#039;);
                        }
                    }
                });
            });
        });
        &lt;/script&gt;
        &lt;?php
    }

    /**
     * AJAX: Iscrivi alla waitlist
     */
    public function ajax_subscribe() {
        check_ajax_referer(&#039;asn_subscribe&#039;, &#039;nonce&#039;);

        $email = sanitize_email($_POST[&#039;email&#039;]);
        $phone = sanitize_text_field($_POST[&#039;phone&#039;]);
        $product_id = intval($_POST[&#039;product_id&#039;]);

        if (!is_email($email)) {
            wp_send_json_error(__(&#039;Email non valida&#039;, &#039;asn&#039;));
        }

        // Salva iscrizione
        $waitlist = get_post_meta($product_id, &#039;_asn_waitlist&#039;, true) ?: [];

        $subscription = [
            &#039;email&#039; =&gt; $email,
            &#039;phone&#039; =&gt; $phone,
            &#039;date&#039; =&gt; current_time(&#039;mysql&#039;)
        ];

        // Evita duplicati
        $exists = array_filter($waitlist, function($item) use ($email) {
            return $item[&#039;email&#039;] === $email;
        });

        if (empty($exists)) {
            $waitlist[] = $subscription;
            update_post_meta($product_id, &#039;_asn_waitlist&#039;, $waitlist);
            wp_send_json_success(__(&#039;Ti avviseremo quando il prodotto sarà disponibile!&#039;, &#039;asn&#039;));
        } else {
            wp_send_json_error(__(&#039;Sei già iscritto a questa lista&#039;, &#039;asn&#039;));
        }
    }

    /**
     * Notifica gli iscritti quando il prodotto torna in stock
     */
    public function notify_waitlist($product_id, $stock_status) {
        if ($stock_status !== &#039;instock&#039;) {
            return;
        }

        $waitlist = get_post_meta($product_id, &#039;_asn_waitlist&#039;, true);

        if (empty($waitlist)) {
            return;
        }

        $product = wc_get_product($product_id);
        $product_name = $product-&gt;get_name();
        $product_link = $product-&gt;get_permalink();

        $settings = get_option($this-&gt;option_name);
        $email_template = $settings[&#039;email_template&#039;] ?? &#039;default&#039;;

        foreach ($waitlist as $subscription) {
            $this-&gt;send_notification(
                $subscription[&#039;email&#039;],
                $subscription[&#039;phone&#039;],
                $product_name,
                $product_link,
                $email_template
            );
        }

        // Pulisci la waitlist dopo l&#039;invio
        delete_post_meta($product_id, &#039;_asn_waitlist&#039;);
    }

    /**
     * Invia notifica email/SMS
     */
    private function send_notification($email, $phone, $product_name, $product_link, $template) {
        $subject = sprintf(__(&#039;Torna in stock: %s&#039;, &#039;asn&#039;), $product_name);

        $message = sprintf(
            __(&quot;Ciao!\n\nIl prodotto %s è tornato disponibile!\n\nAcquistalo ora: %s\n\nNon aspettare, le scorte sono limitate.&quot;, &#039;asn&#039;),
            $product_name,
            $product_link
        );

        // Email
        wp_mail($email, $subject, $message);

        // SMS (se configurato e numero presente)
        if ($phone &amp;&amp; class_exists(&#039;WC_SMS&#039;)) {
            // Integrazione con gateway SMS
            do_action(&#039;asn_send_sms&#039;, $phone, $subject);
        }
    }

    /**
     * Aggiungi menu admin
     */
    public function add_admin_menu() {
        add_submenu_page(
            &#039;woocommerce&#039;,
            __(&#039;Notifiche Stock&#039;, &#039;asn&#039;),
            __(&#039;Notifiche Stock&#039;, &#039;asn&#039;),
            &#039;manage_woocommerce&#039;,
            &#039;advanced-stock-notifications&#039;,
            [$this, &#039;admin_page&#039;]
        );
    }

    /**
     * Pagina admin
     */
    public function admin_page() {
        ?&gt;
        &lt;div class=&quot;wrap&quot;&gt;
            &lt;h1&gt;&lt;?php _e(&#039;Impostazioni Notifiche Stock&#039;, &#039;asn&#039;); ?&gt;&lt;/h1&gt;
            &lt;form method=&quot;post&quot; action=&quot;options.php&quot;&gt;
                &lt;?php
                settings_fields($this-&gt;option_name);
                do_settings_sections(&#039;advanced-stock-notifications&#039;);
                submit_button();
                ?&gt;
            &lt;/form&gt;

            &lt;h2&gt;&lt;?php _e(&#039;Statistiche Waitlist&#039;, &#039;asn&#039;); ?&gt;&lt;/h2&gt;
            &lt;?php $this-&gt;show_waitlist_stats(); ?&gt;
        &lt;/div&gt;
        &lt;?php
    }

    /**
     * Mostra statistiche waitlist
     */
    private function show_waitlist_stats() {
        $args = [
            &#039;post_type&#039; =&gt; &#039;product&#039;,
            &#039;meta_key&#039; =&gt; &#039;_asn_waitlist&#039;,
            &#039;posts_per_page&#039; =&gt; 20
        ];

        $products = get_posts($args);

        if (empty($products)) {
            echo &#039;&lt;p&gt;&#039; . __(&#039;Nessuna waitlist attiva&#039;, &#039;asn&#039;) . &#039;&lt;/p&gt;&#039;;
            return;
        }

        echo &#039;&lt;table class=&quot;widefat&quot;&gt;&#039;;
        echo &#039;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Prodotto&lt;/th&gt;&lt;th&gt;Iscritti&lt;/th&gt;&lt;th&gt;Ultima iscrizione&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&#039;;

        foreach ($products as $post) {
            $waitlist = get_post_meta($post-&gt;ID, &#039;_asn_waitlist&#039;, true);
            $count = count($waitlist);
            $last = end($waitlist);

            echo &#039;&lt;tr&gt;&#039;;
            echo &#039;&lt;td&gt;&lt;a href=&quot;&#039; . get_edit_post_link($post-&gt;ID) . &#039;&quot;&gt;&#039; . esc_html($post-&gt;post_title) . &#039;&lt;/a&gt;&lt;/td&gt;&#039;;
            echo &#039;&lt;td&gt;&#039; . $count . &#039;&lt;/td&gt;&#039;;
            echo &#039;&lt;td&gt;&#039; . esc_html($last[&#039;date&#039;] ?? &#039;-&#039;) . &#039;&lt;/td&gt;&#039;;
            echo &#039;&lt;/tr&gt;&#039;;
        }

        echo &#039;&lt;/table&gt;&#039;;
    }

    /**
     * Registra impostazioni
     */
    public function register_settings() {
        register_setting($this-&gt;option_name, $this-&gt;option_name);

        add_settings_section(
            &#039;asn_main&#039;,
            __(&#039;Configurazione&#039;, &#039;asn&#039;),
            null,
            &#039;advanced-stock-notifications&#039;
        );

        add_settings_field(
            &#039;email_template&#039;,
            __(&#039;Template Email&#039;, &#039;asn&#039;),
            [$this, &#039;render_email_template_field&#039;],
            &#039;advanced-stock-notifications&#039;,
            &#039;asn_main&#039;
        );
    }

    public function render_email_template_field() {
        $settings = get_option($this-&gt;option_name);
        $value = $settings[&#039;email_template&#039;] ?? &#039;default&#039;;
        ?&gt;
        &lt;select name=&quot;&lt;?php echo $this-&gt;option_name; ?&gt;[email_template]&quot;&gt;
            &lt;option value=&quot;default&quot; &lt;?php selected($value, &#039;default&#039;); ?&gt;&gt;
                &lt;?php _e(&#039;Default&#039;, &#039;asn&#039;); ?&gt;
            &lt;/option&gt;
            &lt;option value=&quot;minimal&quot; &lt;?php selected($value, &#039;minimal&#039;); ?&gt;&gt;
                &lt;?php _e(&#039;Minimal&#039;, &#039;asn&#039;); ?&gt;
            &lt;/option&gt;
            &lt;option value=&quot;promotional&quot; &lt;?php selected($value, &#039;promotional&#039;); ?&gt;&gt;
                &lt;?php _e(&#039;Promozionale&#039;, &#039;asn&#039;); ?&gt;
            &lt;/option&gt;
        &lt;/select&gt;
        &lt;?php
    }
}

new Advanced_Stock_Notifications();</code></pre>
<h3>Funzionalità Chiave</h3>
<ul>
<li>Form AJAX senza refresh pagina</li>
<li>Iscrizione con email + telefono opzionale</li>
<li>Notifica automatica al ritorno in stock</li>
<li>Dashboard admin con statistiche</li>
<li>Template email personalizzabili</li>
</ul>
<p><strong>Risultato atteso:</strong> Recupero del 15-25% di vendite perse per out of stock</p>
<hr />
<h2>Esempio 3: Checkout Field Optimizer</h2>
<p>Un checkout troppo lungo è il nemico delle conversioni. Questo plugin ottimizza i campi in base al tipo di cliente:</p>
<pre><code class="language-php">&lt;?php
/**
 * Plugin Name: Checkout Field Optimizer
 * Description: Ottimizza i campi checkout per aumentare le conversioni
 * Version: 1.0.0
 */

if (!defined(&#039;ABSPATH&#039;)) {
    exit;
}

class Checkout_Field_Optimizer {

    public function __construct() {
        // Rimuovi campi non necessari
        add_filter(&#039;woocommerce_checkout_fields&#039;, [$this, &#039;optimize_fields&#039;]);

        // Aggiungi campo &quot;Note&quot; condizionale
        add_action(&#039;woocommerce_before_order_notes&#039;, [$this, &#039;conditional_notes_field&#039;]);

        // Validazione smart
        add_action(&#039;woocommerce_checkout_process&#039;, [$this, &#039;smart_validation&#039;]);

        // Rendi alcuni campi opzionali per B2B
        add_filter(&#039;woocommerce_default_address_fields&#039;, [$this, &#039;b2b_fields&#039;]);

        // Salva meta dati
        add_action(&#039;woocommerce_checkout_update_order_meta&#039;, [$this, &#039;save_order_meta&#039;]);

        // Admin settings
        add_action(&#039;admin_menu&#039;, [$this, &#039;add_settings&#039;]);
    }

    /**
     * Ottimizza i campi checkout
     */
    public function optimize_fields($fields) {
        $settings = get_option(&#039;cfo_settings&#039;, []);

        // Rimuovi campi non necessari per clienti italiani
        if (!empty($settings[&#039;remove_fields&#039;])) {
            foreach ($settings[&#039;remove_fields&#039;] as $field) {
                unset($fields[&#039;billing&#039;][$field]);
                unset($fields[&#039;shipping&#039;][$field]);
            }
        }

        // Semplifica per guest
        if (!is_user_logged_in() &amp;&amp; !empty($settings[&#039;simplify_guest&#039;])) {
            unset($fields[&#039;billing&#039;][&#039;billing_company&#039;]);
            unset($fields[&#039;billing&#039;][&#039;billing_address_2&#039;]);
            unset($fields[&#039;shipping&#039;][&#039;shipping_company&#039;]);
            unset($fields[&#039;shipping&#039;][&#039;shipping_address_2&#039;]);
        }

        // Riordina campi per priorità
        $priority = [
            &#039;billing_first_name&#039; =&gt; 10,
            &#039;billing_last_name&#039; =&gt; 20,
            &#039;billing_email&#039; =&gt; 30,
            &#039;billing_phone&#039; =&gt; 40,
            &#039;billing_country&#039; =&gt; 50,
            &#039;billing_address_1&#039; =&gt; 60,
            &#039;billing_city&#039; =&gt; 70,
            &#039;billing_postcode&#039; =&gt; 80,
        ];

        foreach ($priority as $field =&gt; $p) {
            if (isset($fields[&#039;billing&#039;][$field])) {
                $fields[&#039;billing&#039;][$field][&#039;priority&#039;] = $p;
            }
        }

        // Placeholder più chiari
        $fields[&#039;billing&#039;][&#039;billing_phone&#039;][&#039;placeholder&#039;] = &#039;+39 xxx xxx xxxx&#039;;
        $fields[&#039;billing&#039;][&#039;billing_postcode&#039;][&#039;placeholder&#039;] = &#039;CAP&#039;;

        // Auto-focus sul primo campo
        add_action(&#039;woocommerce_before_checkout_form&#039;, function() {
            echo &#039;&lt;script&gt;jQuery(document).ready(function($){ $(&quot;#billing_first_name&quot;).focus(); });&lt;/script&gt;&#039;;
        });

        return $fields;
    }

    /**
     * Campo note condizionale
     */
    public function conditional_notes_field() {
        $cart = WC()-&gt;cart;

        // Mostra campo note solo per ordini &gt; €100 o con prodotti specifici
        $show_notes = false;

        if ($cart-&gt;subtotal &gt; 100) {
            $show_notes = true;
        }

        // Oppure se ci sono prodotti che richiedono personalizzazione
        foreach ($cart-&gt;get_cart() as $item) {
            if (get_post_meta($item[&#039;product_id&#039;], &#039;_requires_notes&#039;, true)) {
                $show_notes = true;
                break;
            }
        }

        if ($show_notes) {
            woocommerce_form_field(&#039;order_special_notes&#039;, [
                &#039;type&#039; =&gt; &#039;textarea&#039;,
                &#039;class&#039; =&gt; [&#039;form-row-wide&#039;],
                &#039;label&#039; =&gt; __(&#039;Note aggiuntive per il tuo ordine&#039;, &#039;cfo&#039;),
                &#039;placeholder&#039; =&gt; __(&#039;Es: regalo, consegna in orario specifico...&#039;, &#039;cfo&#039;),
            ]);
        }
    }

    /**
     * Validazione smart
     */
    public function smart_validation() {
        $settings = get_option(&#039;cfo_settings&#039;, []);

        // Validazione CAP italiano
        if (!empty($_POST[&#039;billing_country&#039;]) &amp;&amp; $_POST[&#039;billing_country&#039;] === &#039;IT&#039;) {
            $cap = sanitize_text_field($_POST[&#039;billing_postcode&#039;] ?? &#039;&#039;);

            if (!preg_match(&#039;/^\d{5}$/&#039;, $cap)) {
                wc_add_notice(__(&#039;Inserisci un CAP italiano valido (5 cifre)&#039;, &#039;cfo&#039;), &#039;error&#039;);
            }
        }

        // Validazione telefono italiano
        if (!empty($settings[&#039;validate_phone&#039;]) &amp;&amp; !empty($_POST[&#039;billing_phone&#039;])) {
            $phone = sanitize_text_field($_POST[&#039;billing_phone&#039;]);

            if (!preg_match(&#039;/^(\+39)?\s?\d{3}\s?\d{3}\s?\d{4}$/&#039;, $phone)) {
                wc_add_notice(__(&#039;Formato telefono non valido. Usa: +39 xxx xxx xxxx&#039;, &#039;cfo&#039;), &#039;error&#039;);
            }
        }
    }

    /**
     * Campi B2B
     */
    public function b2b_fields($fields) {
        // Se l&#039;utente ha un ruolo B2B
        if (current_user_can(&#039;customer_b2b&#039;)) {
            // Partita IVA obbligatoria
            $fields[&#039;billing_vat&#039;] = [
                &#039;label&#039; =&gt; __(&#039;Partita IVA&#039;, &#039;cfo&#039;),
                &#039;required&#039; =&gt; true,
                &#039;class&#039; =&gt; [&#039;form-row-wide&#039;],
                &#039;priority&#039; =&gt; 90,
            ];

            // Codice SDI
            $fields[&#039;billing_sdi&#039;] = [
                &#039;label&#039; =&gt; __(&#039;Codice SDI&#039;, &#039;cfo&#039;),
                &#039;required&#039; =&gt; false,
                &#039;class&#039; =&gt; [&#039;form-row-wide&#039;],
                &#039;priority&#039; =&gt; 95,
                &#039;description&#039; =&gt; __(&#039;Codice destinatario per fatturazione elettronica&#039;, &#039;cfo&#039;),
            ];

            // PEC
            $fields[&#039;billing_pec&#039;] = [
                &#039;label&#039; =&gt; __(&#039;PEC&#039;, &#039;cfo&#039;),
                &#039;required&#039; =&gt; false,
                &#039;class&#039; =&gt; [&#039;form-row-wide&#039;],
                &#039;priority&#039; =&gt; 100,
            ];
        }

        return $fields;
    }

    /**
     * Salva meta dati ordine
     */
    public function save_order_meta($order_id) {
        if (!empty($_POST[&#039;order_special_notes&#039;])) {
            update_post_meta(
                $order_id, 
                &#039;_special_notes&#039;, 
                sanitize_textarea_field($_POST[&#039;order_special_notes&#039;])
            );
        }

        if (!empty($_POST[&#039;billing_vat&#039;])) {
            update_post_meta(
                $order_id, 
                &#039;_billing_vat&#039;, 
                sanitize_text_field($_POST[&#039;billing_vat&#039;])
            );
        }

        if (!empty($_POST[&#039;billing_sdi&#039;])) {
            update_post_meta(
                $order_id, 
                &#039;_billing_sdi&#039;, 
                sanitize_text_field($_POST[&#039;billing_sdi&#039;])
            );
        }
    }

    /**
     * Aggiungi impostazioni admin
     */
    public function add_settings() {
        add_submenu_page(
            &#039;woocommerce&#039;,
            __(&#039;Ottimizzazione Checkout&#039;, &#039;cfo&#039;),
            __(&#039;Ottimizzazione Checkout&#039;, &#039;cfo&#039;),
            &#039;manage_woocommerce&#039;,
            &#039;checkout-field-optimizer&#039;,
            [$this, &#039;settings_page&#039;]
        );
    }

    /**
     * Pagina impostazioni
     */
    public function settings_page() {
        if (isset($_POST[&#039;cfo_save&#039;])) {
            check_admin_referer(&#039;cfo_settings&#039;);
            update_option(&#039;cfo_settings&#039;, [
                &#039;remove_fields&#039; =&gt; $_POST[&#039;remove_fields&#039;] ?? [],
                &#039;simplify_guest&#039; =&gt; !empty($_POST[&#039;simplify_guest&#039;]),
                &#039;validate_phone&#039; =&gt; !empty($_POST[&#039;validate_phone&#039;]),
            ]);
            echo &#039;&lt;div class=&quot;notice notice-success&quot;&gt;&lt;p&gt;Impostazioni salvate!&lt;/p&gt;&lt;/div&gt;&#039;;
        }

        $settings = get_option(&#039;cfo_settings&#039;, []);
        ?&gt;
        &lt;div class=&quot;wrap&quot;&gt;
            &lt;h1&gt;&lt;?php _e(&#039;Ottimizzazione Campi Checkout&#039;, &#039;cfo&#039;); ?&gt;&lt;/h1&gt;

            &lt;form method=&quot;post&quot;&gt;
                &lt;?php wp_nonce_field(&#039;cfo_settings&#039;); ?&gt;

                &lt;table class=&quot;form-table&quot;&gt;
                    &lt;tr&gt;
                        &lt;th&gt;&lt;?php _e(&#039;Rimuovi campi&#039;, &#039;cfo&#039;); ?&gt;&lt;/th&gt;
                        &lt;td&gt;
                            &lt;label&gt;
                                &lt;input type=&quot;checkbox&quot; name=&quot;remove_fields[]&quot; value=&quot;billing_company&quot; 
                                    &lt;?php checked(in_array(&#039;billing_company&#039;, $settings[&#039;remove_fields&#039;] ?? [])); ?&gt;&gt;
                                &lt;?php _e(&#039;Azienda&#039;, &#039;cfo&#039;); ?&gt;
                            &lt;/label&gt;&lt;br&gt;
                            &lt;label&gt;
                                &lt;input type=&quot;checkbox&quot; name=&quot;remove_fields[]&quot; value=&quot;billing_address_2&quot;
                                    &lt;?php checked(in_array(&#039;billing_address_2&#039;, $settings[&#039;remove_fields&#039;] ?? [])); ?&gt;&gt;
                                &lt;?php _e(&#039;Indirizzo 2&#039;, &#039;cfo&#039;); ?&gt;
                            &lt;/label&gt;&lt;br&gt;
                            &lt;label&gt;
                                &lt;input type=&quot;checkbox&quot; name=&quot;remove_fields[]&quot; value=&quot;billing_state&quot;
                                    &lt;?php checked(in_array(&#039;billing_state&#039;, $settings[&#039;remove_fields&#039;] ?? [])); ?&gt;&gt;
                                &lt;?php _e(&#039;Provincia&#039;, &#039;cfo&#039;); ?&gt;
                            &lt;/label&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;th&gt;&lt;?php _e(&#039;Semplifica per guest&#039;, &#039;cfo&#039;); ?&gt;&lt;/th&gt;
                        &lt;td&gt;
                            &lt;label&gt;
                                &lt;input type=&quot;checkbox&quot; name=&quot;simplify_guest&quot; 
                                    &lt;?php checked(!empty($settings[&#039;simplify_guest&#039;])); ?&gt;&gt;
                                &lt;?php _e(&#039;Riduci campi per utenti non registrati&#039;, &#039;cfo&#039;); ?&gt;
                            &lt;/label&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;tr&gt;
                        &lt;th&gt;&lt;?php _e(&#039;Validazione telefono&#039;, &#039;cfo&#039;); ?&gt;&lt;/th&gt;
                        &lt;td&gt;
                            &lt;label&gt;
                                &lt;input type=&quot;checkbox&quot; name=&quot;validate_phone&quot;
                                    &lt;?php checked(!empty($settings[&#039;validate_phone&#039;])); ?&gt;&gt;
                                &lt;?php _e(&#039;Valida formato telefono italiano&#039;, &#039;cfo&#039;); ?&gt;
                            &lt;/label&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/table&gt;

                &lt;p class=&quot;submit&quot;&gt;
                    &lt;button type=&quot;submit&quot; name=&quot;cfo_save&quot; class=&quot;button-primary&quot;&gt;
                        &lt;?php _e(&#039;Salva Impostazioni&#039;, &#039;cfo&#039;); ?&gt;
                    &lt;/button&gt;
                &lt;/p&gt;
            &lt;/form&gt;

            &lt;h2&gt;&lt;?php _e(&#039;Statistiche Checkout&#039;, &#039;cfo&#039;); ?&gt;&lt;/h2&gt;
            &lt;?php $this-&gt;show_checkout_stats(); ?&gt;
        &lt;/div&gt;
        &lt;?php
    }

    /**
     * Mostra statistiche
     */
    private function show_checkout_stats() {
        global $wpdb;

        $stats = $wpdb-&gt;get_row(&quot;
            SELECT 
                COUNT(*) as total_orders,
                AVG(meta_value) as avg_checkout_time
            FROM {$wpdb-&gt;posts} p
            LEFT JOIN {$wpdb-&gt;postmeta} pm ON p.ID = pm.post_id
            WHERE p.post_type = &#039;shop_order&#039;
            AND p.post_status IN (&#039;wc-completed&#039;, &#039;wc-processing&#039;)
            AND pm.meta_key = &#039;_checkout_duration&#039;
        &quot;);

        echo &#039;&lt;div class=&quot;cfo-stats&quot;&gt;&#039;;
        echo &#039;&lt;p&gt;&lt;strong&gt;Ordini completati:&lt;/strong&gt; &#039; . number_format($stats-&gt;total_orders) . &#039;&lt;/p&gt;&#039;;
        if ($stats-&gt;avg_checkout_time) {
            echo &#039;&lt;p&gt;&lt;strong&gt;Tempo medio checkout:&lt;/strong&gt; &#039; . round($stats-&gt;avg_checkout_time) . &#039; secondi&lt;/p&gt;&#039;;
        }
        echo &#039;&lt;/div&gt;&#039;;
    }
}

new Checkout_Field_Optimizer();</code></pre>
<h3>Benefici</h3>
<ul>
<li>Riduzione campi del 30-50% per guest</li>
<li>Validazione intelligente per clienti italiani</li>
<li>Campi B2B automatici (P.IVA, SDI, PEC)</li>
<li>Dashboard con statistiche</li>
</ul>
<p><strong>Risultato atteso:</strong> +20-35% tasso di completamento checkout</p>
<hr />
<h2>Esempio 4: Dynamic Pricing Engine</h2>
<p>Il pricing dinamico può aumentare significativamente i margini. Ecco un motore di regole flessibile:</p>
<pre><code class="language-php">&lt;?php
/**
 * Plugin Name: Dynamic Pricing Engine
 * Description: Regole di pricing dinamiche per WooCommerce
 * Version: 1.0.0
 */

if (!defined(&#039;ABSPATH&#039;)) {
    exit;
}

class Dynamic_Pricing_Engine {

    private $rules = [];

    public function __construct() {
        add_action(&#039;init&#039;, [$this, &#039;load_rules&#039;]);
        add_filter(&#039;woocommerce_product_get_price&#039;, [$this, &#039;apply_pricing&#039;], 99, 2);
        add_filter(&#039;woocommerce_product_variation_get_price&#039;, [$this, &#039;apply_pricing&#039;], 99, 2);
        add_filter(&#039;woocommerce_cart_item_price&#039;, [$this, &#039;show_discounted_price&#039;], 99, 3);

        // Admin
        add_action(&#039;admin_menu&#039;, [$this, &#039;add_admin_menu&#039;]);
        add_action(&#039;admin_init&#039;, [$this, &#039;register_settings&#039;]);
    }

    /**
     * Carica regole dal database
     */
    public function load_rules() {
        $this-&gt;rules = get_option(&#039;dpe_rules&#039;, []);
    }

    /**
     * Applica pricing dinamico
     */
    public function apply_pricing($price, $product) {
        if (is_admin() || !is_numeric($price)) {
            return $price;
        }

        $original_price = (float) $price;
        $new_price = $original_price;

        foreach ($this-&gt;rules as $rule) {
            if (!$rule[&#039;active&#039;]) {
                continue;
            }

            if ($this-&gt;rule_applies($rule, $product)) {
                $new_price = $this-&gt;calculate_price($new_price, $rule, $product);
            }
        }

        return $new_price &lt; $original_price ? $new_price : $price;
    }

    /**
     * Verifica se la regola si applica
     */
    private function rule_applies($rule, $product) {
        // Verifica data
        $now = current_time(&#039;timestamp&#039;);

        if (!empty($rule[&#039;start_date&#039;]) &amp;&amp; strtotime($rule[&#039;start_date&#039;]) &gt; $now) {
            return false;
        }

        if (!empty($rule[&#039;end_date&#039;]) &amp;&amp; strtotime($rule[&#039;end_date&#039;]) &lt; $now) {
            return false;
        }

        // Verifica categorie
        if (!empty($rule[&#039;categories&#039;])) {
            $product_cats = wp_get_post_terms($product-&gt;get_id(), &#039;product_cat&#039;, [&#039;fields&#039; =&gt; &#039;ids&#039;]);
            if (!array_intersect($rule[&#039;categories&#039;], $product_cats)) {
                return false;
            }
        }

        // Verifica ruolo utente
        if (!empty($rule[&#039;user_roles&#039;])) {
            $user = wp_get_current_user();
            if (!array_intersect($rule[&#039;user_roles&#039;], $user-&gt;roles)) {
                return false;
            }
        }

        // Verifica quantità minima
        if (!empty($rule[&#039;min_quantity&#039;])) {
            $cart_qty = 0;
            foreach (WC()-&gt;cart-&gt;get_cart() as $item) {
                if ($item[&#039;product_id&#039;] == $product-&gt;get_id()) {
                    $cart_qty = $item[&#039;quantity&#039;];
                    break;
                }
            }
            if ($cart_qty &lt; $rule[&#039;min_quantity&#039;]) {
                return false;
            }
        }

        return true;
    }

    /**
     * Calcola il nuovo prezzo
     */
    private function calculate_price($price, $rule, $product) {
        switch ($rule[&#039;type&#039;]) {
            case &#039;percentage&#039;:
                return $price * (1 - ($rule[&#039;value&#039;] / 100));

            case &#039;fixed&#039;:
                return max(0, $price - $rule[&#039;value&#039;]);

            case &#039;tiered&#039;:
                return $this-&gt;calculate_tiered_price($price, $rule, $product);

            case &#039;time_based&#039;:
                return $this-&gt;calculate_time_price($price, $rule);

            default:
                return $price;
        }
    }

    /**
     * Prezzo a scaglioni
     */
    private function calculate_tiered_price($price, $rule, $product) {
        $qty = 0;
        foreach (WC()-&gt;cart-&gt;get_cart() as $item) {
            if ($item[&#039;product_id&#039;] == $product-&gt;get_id()) {
                $qty = $item[&#039;quantity&#039;];
                break;
            }
        }

        $tiers = $rule[&#039;tiers&#039;] ?? [];
        krsort($tiers); // Ordina per quantità decrescente

        foreach ($tiers as $min_qty =&gt; $discount) {
            if ($qty &gt;= $min_qty) {
                return $price * (1 - ($discount / 100));
            }
        }

        return $price;
    }

    /**
     * Prezzo basato sull&#039;orario
     */
    private function calculate_time_price($price, $rule) {
        $hour = (int) current_time(&#039;H&#039;);
        $start = (int) ($rule[&#039;time_start&#039;] ?? 0);
        $end = (int) ($rule[&#039;time_end&#039;] ?? 24);

        if ($hour &gt;= $start &amp;&amp; $hour &lt; $end) {
            return $price * (1 - ($rule[&#039;value&#039;] / 100));
        }

        return $price;
    }

    /**
     * Mostra prezzo barrato nel carrello
     */
    public function show_discounted_price($price, $cart_item, $cart_item_key) {
        $product = $cart_item[&#039;data&#039;];
        $original_price = (float) $product-&gt;get_regular_price();
        $current_price = (float) $product-&gt;get_price();

        if ($current_price &lt; $original_price) {
            return &#039;&lt;del&gt;&#039; . wc_price($original_price) . &#039;&lt;/del&gt; &#039; . wc_price($current_price);
        }

        return $price;
    }

    /**
     * Aggiungi menu admin
     */
    public function add_admin_menu() {
        add_submenu_page(
            &#039;woocommerce&#039;,
            __(&#039;Pricing Dinamico&#039;, &#039;dpe&#039;),
            __(&#039;Pricing Dinamico&#039;, &#039;dpe&#039;),
            &#039;manage_woocommerce&#039;,
            &#039;dynamic-pricing-engine&#039;,
            [$this, &#039;admin_page&#039;]
        );
    }

    /**
     * Pagina admin
     */
    public function admin_page() {
        if (isset($_POST[&#039;dpe_save&#039;])) {
            check_admin_referer(&#039;dpe_settings&#039;);
            $this-&gt;save_rules($_POST[&#039;rules&#039;] ?? []);
            echo &#039;&lt;div class=&quot;notice notice-success&quot;&gt;&lt;p&gt;Regole salvate!&lt;/p&gt;&lt;/div&gt;&#039;;
        }

        $rules = $this-&gt;rules;
        ?&gt;
        &lt;div class=&quot;wrap&quot;&gt;
            &lt;h1&gt;&lt;?php _e(&#039;Regole Pricing Dinamico&#039;, &#039;dpe&#039;); ?&gt;&lt;/h1&gt;

            &lt;form method=&quot;post&quot; id=&quot;dpe-form&quot;&gt;
                &lt;?php wp_nonce_field(&#039;dpe_settings&#039;); ?&gt;

                &lt;div id=&quot;rules-container&quot;&gt;
                    &lt;?php 
                    if (empty($rules)) {
                        $rules = [[&#039;name&#039; =&gt; &#039;&#039;, &#039;type&#039; =&gt; &#039;percentage&#039;, &#039;value&#039; =&gt; &#039;&#039;, &#039;active&#039; =&gt; true]];
                    }
                    foreach ($rules as $index =&gt; $rule) : 
                    ?&gt;
                    &lt;div class=&quot;rule-box&quot; data-index=&quot;&lt;?php echo $index; ?&gt;&quot;&gt;
                        &lt;h3&gt;&lt;?php _e(&#039;Regola&#039;, &#039;dpe&#039;); ?&gt; #&lt;?php echo $index + 1; ?&gt;&lt;/h3&gt;

                        &lt;table class=&quot;form-table&quot;&gt;
                            &lt;tr&gt;
                                &lt;th&gt;&lt;?php _e(&#039;Nome&#039;, &#039;dpe&#039;); ?&gt;&lt;/th&gt;
                                &lt;td&gt;
                                    &lt;input type=&quot;text&quot; name=&quot;rules[&lt;?php echo $index; ?&gt;][name]&quot; 
                                           value=&quot;&lt;?php echo esc_attr($rule[&#039;name&#039;] ?? &#039;&#039;); ?&gt;&quot; 
                                           placeholder=&quot;Es: Sconto Estivo&quot;&gt;
                                &lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;th&gt;&lt;?php _e(&#039;Tipo&#039;, &#039;dpe&#039;); ?&gt;&lt;/th&gt;
                                &lt;td&gt;
                                    &lt;select name=&quot;rules[&lt;?php echo $index; ?&gt;][type]&quot; class=&quot;rule-type&quot;&gt;
                                        &lt;option value=&quot;percentage&quot; &lt;?php selected($rule[&#039;type&#039;] ?? &#039;&#039;, &#039;percentage&#039;); ?&gt;&gt;
                                            &lt;?php _e(&#039;Percentuale&#039;, &#039;dpe&#039;); ?&gt;
                                        &lt;/option&gt;
                                        &lt;option value=&quot;fixed&quot; &lt;?php selected($rule[&#039;type&#039;] ?? &#039;&#039;, &#039;fixed&#039;); ?&gt;&gt;
                                            &lt;?php _e(&#039;Importo fisso&#039;, &#039;dpe&#039;); ?&gt;
                                        &lt;/option&gt;
                                        &lt;option value=&quot;tiered&quot; &lt;?php selected($rule[&#039;type&#039;] ?? &#039;&#039;, &#039;tiered&#039;); ?&gt;&gt;
                                            &lt;?php _e(&#039;A scaglioni&#039;, &#039;dpe&#039;); ?&gt;
                                        &lt;/option&gt;
                                        &lt;option value=&quot;time_based&quot; &lt;?php selected($rule[&#039;type&#039;] ?? &#039;&#039;, &#039;time_based&#039;); ?&gt;&gt;
                                            &lt;?php _e(&#039;Basato sull\&#039;orario&#039;, &#039;dpe&#039;); ?&gt;
                                        &lt;/option&gt;
                                    &lt;/select&gt;
                                &lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;th&gt;&lt;?php _e(&#039;Valore&#039;, &#039;dpe&#039;); ?&gt;&lt;/th&gt;
                                &lt;td&gt;
                                    &lt;input type=&quot;number&quot; name=&quot;rules[&lt;?php echo $index; ?&gt;][value]&quot; 
                                           value=&quot;&lt;?php echo esc_attr($rule[&#039;value&#039;] ?? &#039;&#039;); ?&gt;&quot; 
                                           step=&quot;0.01&quot; min=&quot;0&quot; placeholder=&quot;10&quot;&gt;
                                    &lt;span class=&quot;value-suffix&quot;&gt;%&lt;/span&gt;
                                &lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;th&gt;&lt;?php _e(&#039;Categorie&#039;, &#039;dpe&#039;); ?&gt;&lt;/th&gt;
                                &lt;td&gt;
                                    &lt;?php 
                                    $cats = get_terms([&#039;taxonomy&#039; =&gt; &#039;product_cat&#039;, &#039;hide_empty&#039; =&gt; false]);
                                    foreach ($cats as $cat) {
                                        printf(
                                            &#039;&lt;label&gt;&lt;input type=&quot;checkbox&quot; name=&quot;rules[%d][categories][]&quot; value=&quot;%d&quot; %s&gt; %s&lt;/label&gt;&lt;br&gt;&#039;,
                                            $index,
                                            $cat-&gt;term_id,
                                            checked(in_array($cat-&gt;term_id, $rule[&#039;categories&#039;] ?? []), true, false),
                                            esc_html($cat-&gt;name)
                                        );
                                    }
                                    ?&gt;
                                &lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;th&gt;&lt;?php _e(&#039;Ruoli utente&#039;, &#039;dpe&#039;); ?&gt;&lt;/th&gt;
                                &lt;td&gt;
                                    &lt;?php 
                                    global $wp_roles;
                                    foreach ($wp_roles-&gt;roles as $role_name =&gt; $role_info) {
                                        printf(
                                            &#039;&lt;label&gt;&lt;input type=&quot;checkbox&quot; name=&quot;rules[%d][user_roles][]&quot; value=&quot;%s&quot; %s&gt; %s&lt;/label&gt;&lt;br&gt;&#039;,
                                            $index,
                                            $role_name,
                                            checked(in_array($role_name, $rule[&#039;user_roles&#039;] ?? []), true, false),
                                            esc_html($role_info[&#039;name&#039;])
                                        );
                                    }
                                    ?&gt;
                                &lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;th&gt;&lt;?php _e(&#039;Periodo&#039;, &#039;dpe&#039;); ?&gt;&lt;/th&gt;
                                &lt;td&gt;
                                    &lt;input type=&quot;date&quot; name=&quot;rules[&lt;?php echo $index; ?&gt;][start_date]&quot; 
                                           value=&quot;&lt;?php echo esc_attr($rule[&#039;start_date&#039;] ?? &#039;&#039;); ?&gt;&quot;&gt;
                                    -
                                    &lt;input type=&quot;date&quot; name=&quot;rules[&lt;?php echo $index; ?&gt;][end_date]&quot; 
                                           value=&quot;&lt;?php echo esc_attr($rule[&#039;end_date&#039;] ?? &#039;&#039;); ?&gt;&quot;&gt;
                                &lt;/td&gt;
                            &lt;/tr&gt;
                            &lt;tr&gt;
                                &lt;th&gt;&lt;?php _e(&#039;Attiva&#039;, &#039;dpe&#039;); ?&gt;&lt;/th&gt;
                                &lt;td&gt;
                                    &lt;label&gt;
                                        &lt;input type=&quot;checkbox&quot; name=&quot;rules[&lt;?php echo $index; ?&gt;][active]&quot; 
                                               value=&quot;1&quot; &lt;?php checked(!empty($rule[&#039;active&#039;])); ?&gt;&gt;
                                        &lt;?php _e(&#039;Regola attiva&#039;, &#039;dpe&#039;); ?&gt;
                                    &lt;/label&gt;
                                &lt;/td&gt;
                            &lt;/tr&gt;
                        &lt;/table&gt;

                        &lt;button type=&quot;button&quot; class=&quot;button remove-rule&quot;&gt;Rimuovi regola&lt;/button&gt;
                        &lt;hr&gt;
                    &lt;/div&gt;
                    &lt;?php endforeach; ?&gt;
                &lt;/div&gt;

                &lt;p&gt;
                    &lt;button type=&quot;button&quot; class=&quot;button&quot; id=&quot;add-rule&quot;&gt;+ Aggiungi regola&lt;/button&gt;
                &lt;/p&gt;

                &lt;p class=&quot;submit&quot;&gt;
                    &lt;button type=&quot;submit&quot; name=&quot;dpe_save&quot; class=&quot;button-primary&quot;&gt;
                        &lt;?php _e(&#039;Salva Regole&#039;, &#039;dpe&#039;); ?&gt;
                    &lt;/button&gt;
                &lt;/p&gt;
            &lt;/form&gt;
        &lt;/div&gt;

        &lt;style&gt;
            .rule-box {
                background: #fff;
                padding: 20px;
                margin: 10px 0;
                border: 1px solid #ccc;
                border-radius: 4px;
            }
            .rule-box h3 {
                margin-top: 0;
            }
        &lt;/style&gt;

        &lt;script&gt;
        jQuery(document).ready(function($) {
            var ruleIndex = &lt;?php echo count($rules); ?&gt;;

            $(&#039;#add-rule&#039;).on(&#039;click&#039;, function() {
                var template = $(&#039;.rule-box:first&#039;).clone();
                template.attr(&#039;data-index&#039;, ruleIndex);
                template.find(&#039;h3&#039;).text(&#039;Regola #&#039; + (ruleIndex + 1));
                template.find(&#039;input, select&#039;).each(function() {
                    var name = $(this).attr(&#039;name&#039;);
                    if (name) {
                        $(this).attr(&#039;name&#039;, name.replace(/\[\d+\]/, &#039;[&#039; + ruleIndex + &#039;]&#039;));
                    }
                    $(this).val(&#039;&#039;);
                });
                template.find(&#039;input[type=&quot;checkbox&quot;]&#039;).prop(&#039;checked&#039;, false);
                $(&#039;#rules-container&#039;).append(template);
                ruleIndex++;
            });

            $(document).on(&#039;click&#039;, &#039;.remove-rule&#039;, function() {
                if ($(&#039;.rule-box&#039;).length &gt; 1) {
                    $(this).closest(&#039;.rule-box&#039;).remove();
                }
            });
        });
        &lt;/script&gt;
        &lt;?php
    }

    /**
     * Salva regole
     */
    private function save_rules($rules) {
        $sanitized = [];

        foreach ($rules as $index =&gt; $rule) {
            $sanitized[] = [
                &#039;name&#039; =&gt; sanitize_text_field($rule[&#039;name&#039;] ?? &#039;&#039;),
                &#039;type&#039; =&gt; sanitize_text_field($rule[&#039;type&#039;] ?? &#039;percentage&#039;),
                &#039;value&#039; =&gt; floatval($rule[&#039;value&#039;] ?? 0),
                &#039;categories&#039; =&gt; array_map(&#039;intval&#039;, $rule[&#039;categories&#039;] ?? []),
                &#039;user_roles&#039; =&gt; array_map(&#039;sanitize_text_field&#039;, $rule[&#039;user_roles&#039;] ?? []),
                &#039;min_quantity&#039; =&gt; intval($rule[&#039;min_quantity&#039;] ?? 0),
                &#039;start_date&#039; =&gt; sanitize_text_field($rule[&#039;start_date&#039;] ?? &#039;&#039;),
                &#039;end_date&#039; =&gt; sanitize_text_field($rule[&#039;end_date&#039;] ?? &#039;&#039;),
                &#039;active&#039; =&gt; !empty($rule[&#039;active&#039;]),
            ];
        }

        update_option(&#039;dpe_rules&#039;, $sanitized);
        $this-&gt;rules = $sanitized;
    }

    /**
     * Registra impostazioni
     */
    public function register_settings() {
        register_setting(&#039;dpe_settings&#039;, &#039;dpe_rules&#039;);
    }
}

new Dynamic_Pricing_Engine();</code></pre>
<h3>Tipi di Regole Supportate</h3>
<ol>
<li><strong>Percentuale</strong> - Sconto % su prodotti selezionati</li>
<li><strong>Importo fisso</strong> - Sconto in €</li>
<li><strong>A scaglioni</strong> - Più compri, più risparmi</li>
<li><strong>Basato sull'orario</strong> - Happy hour, orari morti</li>
</ol>
<p><strong>Risultato atteso:</strong> +10-20% margini, +15% conversioni</p>
<hr />
<h2>Best Practices per WooCommerce Plugin Development</h2>
<h3>1. Performance</h3>
<pre><code class="language-php">// ❌ MAI fare query nel loop
add_action(&#039;woocommerce_before_single_product&#039;, function() {
    $products = wc_get_products([&#039;limit&#039; =&gt; 100]); // Lento!
});

// ✅ Usa transients per caching
add_action(&#039;woocommerce_before_single_product&#039;, function() {
    $cache_key = &#039;related_products_&#039; . get_the_ID();
    $products = get_transient($cache_key);

    if (false === $products) {
        $products = wc_get_products([&#039;limit&#039; =&gt; 10]);
        set_transient($cache_key, $products, HOUR_IN_SECONDS);
    }
});</code></pre>
<h3>2. Sicurezza</h3>
<pre><code class="language-php">// ❌ MAI fidarsi dell&#039;input utente
$price = $_POST[&#039;custom_price&#039;];

// ✅ Sanitizza e valida sempre
$price = floatval($_POST[&#039;custom_price&#039;] ?? 0);
if ($price &lt; 0 || $price &gt; 999999) {
    wp_die(&#039;Prezzo non valido&#039;);
}

// ✅ Usa nonce per form
wp_nonce_field(&#039;my_action&#039;, &#039;my_nonce&#039;);
if (!wp_verify_nonce($_POST[&#039;my_nonce&#039;], &#039;my_action&#039;)) {
    wp_die(&#039;Security check failed&#039;);
}</code></pre>
<h3>3. Compatibilità</h3>
<pre><code class="language-php">// ✅ Verifica che WooCommerce sia attivo
if (!class_exists(&#039;WooCommerce&#039;)) {
    return;
}

// ✅ Usa le versioni minime
add_action(&#039;before_woocommerce_init&#039;, function() {
    if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
        \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(&#039;custom_order_tables&#039;, __FILE__);
    }
});

// ✅ Hook con priorità corretta
add_filter(&#039;woocommerce_product_get_price&#039;, &#039;my_filter&#039;, 99, 2); // Priorità alta</code></pre>
<h3>4. Debug e Logging</h3>
<pre><code class="language-php">// ✅ Logga errori per debug
if (defined(&#039;WP_DEBUG&#039;) &amp;&amp; WP_DEBUG) {
    error_log(&#039;WooCommerce Debug: &#039; . print_r($data, true));
}

// ✅ Usa WC_Logger
$logger = wc_get_logger();
$logger-&gt;info(&#039;Messaggio informativo&#039;, [&#039;source&#039; =&gt; &#039;my-plugin&#039;]);
$logger-&gt;error(&#039;Errore critico&#039;, [&#039;source&#039; =&gt; &#039;my-plugin&#039;]);</code></pre>
<hr />
<h2>Come Testare i Tuoi Plugin</h2>
<h3>Ambiente di Test</h3>
<pre><code class="language-bash"># Crea un sito di test con WP-CLI
wp core download --version=latest --path=/var/www/test-site
wp config create --dbname=test_db --dbuser=root --dbpass=password
wp db create
wp core install --url=test.local --title=&quot;Test Site&quot; --admin_user=admin --admin_password=password --admin_email=admin@test.local

# Installa WooCommerce
wp plugin install woocommerce --activate

# Crea prodotti di test
wp wc product create --name=&quot;Test Product&quot; --regular_price=19.99 --user=admin

# Attiva il tuo plugin
wp plugin activate my-custom-plugin</code></pre>
<h3>Unit Testing</h3>
<pre><code class="language-php">// tests/test-my-plugin.php
class MyPluginTest extends WP_UnitTestCase {

    public function test_price_calculation() {
        $product = new WC_Product_Simple();
        $product-&gt;set_regular_price(100);
        $product-&gt;save();

        $calculated = apply_filters(&#039;woocommerce_product_get_price&#039;, 100, $product);

        $this-&gt;assertLessThan(100, $calculated, &#039;Il prezzo scontato deve essere minore&#039;);
    }
}</code></pre>
<hr />
<h2>Conclusione</h2>
<p>Il codice custom per WooCommerce non è solo per sviluppatori esperti. Con gli esempi di questa guida, puoi implementare funzionalità che aumentano concretamente le conversioni del tuo store:</p>
<ul>
<li><strong>Upsell intelligente</strong> → +15-25% AOV</li>
<li><strong>Notifiche stock</strong> → Recupero 15-25% vendite perse</li>
<li><strong>Checkout ottimizzato</strong> → +20-35% completamento</li>
<li><strong>Pricing dinamico</strong> → +10-20% margini</li>
</ul>
<h3>Prossimi Passi</h3>
<ol>
<li><strong>Scegli un plugin</strong> dalla lista e implementalo nel tuo ambiente di test</li>
<li><strong>Personalizza</strong> le regole in base al tuo business</li>
<li><strong>Monitora</strong> i risultati con Google Analytics e WooCommerce Reports</li>
<li><strong>Itera</strong> in base ai dati raccolti</li>
</ol>
<h3>Risorse Utili</h3>
<ul>
<li><a href="https://developer.woocommerce.com/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">WooCommerce Developer Documentation</a></li>
<li><a href="https://developer.wordpress.org/plugins/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">WordPress Plugin Developer Handbook</a></li>
<li><a href="https://woocommerce.github.io/woocommerce-rest-api-docs/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">WooCommerce REST API</a></li>
</ul>
<hr />
<p><strong>Sei uno sviluppatore WordPress?</strong> Condividi questa guida con i tuoi clienti e mostragli il valore del codice custom.</p>
<p><strong>Sei uno store owner?</strong> Contatta un developer WooCommerce certificato per implementare queste soluzioni sul tuo store.</p>
<p><em>Hai domande o suggerimenti? Lascia un commento qui sotto!</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.mrtux.it/woocommerce-plugin-development-2026-aumenta-le-vendite-del-40-con-codice-custom/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>OpenCode: L&#039;AI che Programma Mentre Dormi - La Guida Pratica per Sviluppatori WordPress</title>
		<link>https://www.mrtux.it/opencode-lai-che-programma-mentre-dormi-la-guida-pratica-per-sviluppatori-wordpress</link>
					<comments>https://www.mrtux.it/opencode-lai-che-programma-mentre-dormi-la-guida-pratica-per-sviluppatori-wordpress#respond</comments>
		
		<dc:creator><![CDATA[Emilio Petrozzi]]></dc:creator>
		<pubDate>Thu, 09 Apr 2026 09:11:03 +0000</pubDate>
				<category><![CDATA[sviluppo-web]]></category>
		<category><![CDATA[Agent AI]]></category>
		<category><![CDATA[AI Coding]]></category>
		<category><![CDATA[Automazione]]></category>
		<category><![CDATA[LSP]]></category>
		<category><![CDATA[OpenCode]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[plugin wordpress]]></category>
		<category><![CDATA[Sviluppo Software]]></category>
		<category><![CDATA[WordPress Development]]></category>
		<guid isPermaLink="false">https://www.mrtux.it/?p=3248</guid>

					<description><![CDATA[OpenCode: L'AI che Programma Mentre Dormi Cinque milioni di sviluppatori usano gia un agente AI che non aspetta di essere interpellato. Si sveglia ogni 30 minuti, controlla cosa c'e da fare, e si mette al lavoro. Ha accesso alla tua shell, al tuo file system, e a ogni API key che gli hai fornito. Non [&#8230;]]]></description>
										<content:encoded><![CDATA[<h1>OpenCode: L'AI che Programma Mentre Dormi</h1>
<p><em>Cinque milioni di sviluppatori usano gia un agente AI che non aspetta di essere interpellato. Si sveglia ogni 30 minuti, controlla cosa c'e da fare, e si mette al lavoro. Ha accesso alla tua shell, al tuo file system, e a ogni API key che gli hai fornito.</em></p>
<p>Non e uno slogan pubblicitario. E la descrizione di quello che <strong>OpenCode</strong> fa oggi, su macchine reali, per team di sviluppo reali.</p>
<p>La domanda interessante non e se questo tipo di strumento sia impressionante. Chiaramente lo e. La domanda interessante e: <strong>perche la maggior parte degli sviluppatori tratta ancora l'AI come un autocomplete glorificato?</strong></p>
<hr />
<h2>Cosa Rende Diverso OpenCode</h2>
<p>Ogni strumento di coding AI fa la stessa affermazione di base: ti aiuta a scrivere codice piu velocemente. GitHub Copilot, Cursor, Windsurf - vivono tutti nel tuo IDE e rispondono quando chiedi qualcosa. Sono <strong>reattivi</strong>. Tu guidi; loro suggeriscono.</p>
<p>OpenCode lavora su una premessa completamente diversa. Tratta l'AI come <strong>agente</strong> e te come <strong>architetto</strong>. Tu descrivi cosa vuoi costruire. Lo strumento capisce quali file sono rilevanti, li legge, costruisce un piano, e lo esegue. Tu revisioni quello che ha fatto.</p>
<p>E una relazione genuinamente diversa con la macchina. Non migliore per ogni situazione, ma abbastanza diversa da cambiare come pensi a cosa sia realmente il lavoro di programmazione.</p>
<hr />
<h2>L'Architettura che Rende Tutto Possibile</h2>
<p>OpenCode gira come <strong>server in background</strong>, non come un processo che apri quando ti serve. Un client leggero si connette, che sia un'interfaccia terminale, un'app desktop, o un'estensione VS Code. Questo e importante perche significa che l'agente puo mantenere stato persistente ed eseguire sessioni multiple in parallelo.</p>
<h3>Esecuzione Parallela</h3>
<p>Puoi puntare un agente verso un refactor di un microservizio backend e un altro verso lavoro CSS frontend, eseguendo simultaneamente, nello stesso repository. I vecchi tool CLI bloccano il terminale finche un task non completa. OpenCode tratta il parallelismo come feature di prima classe.</p>
<h3>Gerarchia degli Agent</h3>
<p>Ci sono due agent principali con cui la maggior parte degli utenti interagisce:</p>
<p><strong>Plan Mode</strong> e read-only. Esplora il tuo codebase, mappa la struttura rilevante, e produce una strategia di implementazione passo-passo. Non puo toccare un singolo file. Lo usi per pensare a cosa stai per fare.</p>
<p><strong>Build Mode</strong> esegue il piano. Ha pieno accesso read/write, puo eseguire comandi shell, modificare file, e lanciare test. Una volta verificato che la proposta dell'agente Plan ha senso, passi a Build e lo lasci girare.</p>
<p>La separazione sembra semplice. In pratica previene una categoria massiccia di errori, perche il modello ragiona sul problema prima di iniziare a toccare le cose.</p>
<h3>Compaction Agent</h3>
<p>C'e anche un agente interno di Compaction che gira silenziosamente in background. Man mano che la cronologia della conversazione cresce e riempie la context window, riassume le parti rilevanti e mantiene il modello primario focalizzato. Senza questo, le sessioni lunghe degradano. Il modello inizia a dimenticare le istruzioni precedenti.</p>
<hr />
<h2>L'Integrazione LSP: Il Vero Game-Changer</h2>
<p>Qui e dove OpenCode si separa davvero dal resto, e la maggior parte dei contenuti tutorial lo salta completamente.</p>
<p>Gli agent AI di coding standard leggono i file come testo. Fanno grep di stringhe, matchano pattern, e indovinano le relazioni strutturali. Funziona bene per task semplici. Si rompe durante refactor su larga scala in codebase complessi.</p>
<p>OpenCode puo connettersi direttamente ai tool <strong>Language Server Protocol (LSP)</strong>, gli stessi sistemi che il tuo IDE usa per capire il codice semanticamente. Abilitalo con:</p>
<pre><code>OPENCODE_EXPERIMENTAL_LSP_TOOL=true</code></pre>
<p>E improvvisamente l'agente ha accesso a:</p>
<ul>
<li><strong>goToDefinition</strong> - naviga alle definizioni</li>
<li><strong>findReferences</strong> - trova tutti i riferimenti</li>
<li><strong>call hierarchy analysis</strong> - analizza la gerarchia delle chiamate</li>
<li><strong>real-time diagnostics</strong> - diagnostiche in tempo reale</li>
</ul>
<p>Supporta TypeScript, Python, Java, Rust, Go, PHP, e altri.</p>
<h3>La Differenza Pratica</h3>
<p>Quando l'AI rinomina un metodo polimorfico attraverso 200 file di servizio, non sta indovinando quali occorrenze cambiare basandosi sul string matching. Usa riferimenti semantici. Sa esattamente cosa e una definizione, cosa e una chiamata, e cosa e un'annotazione di tipo. Il refactor e type-safe.</p>
<p>E se l'agente scrive qualcosa di sbagliato, l'LSP lancia diagnostiche di errore in tempo reale. L'agente vede il problema e lo corregge prima che tu debba revisionare.</p>
<hr />
<h2>Multi-Provider: La Liberta di Scelta</h2>
<p>OpenCode supporta OpenAI, Anthropic, Google, e modelli locali via Ollama. Quando Gemini 2.5 Pro e uscito, gli utenti hanno cambiato un blocco nel file di configurazione e hanno continuato a lavorare.</p>
<p>Questo non e un vantaggio banale. Il mercato dell'infrastruttura AI si sposta costantemente: la qualita dei modelli cambia, i prezzi cambiano, i termini di servizio cambiano. Qualsiasi strumento che ti lega a un singolo provider e una responsabilita.</p>
<p>L'architettura provider-agnostica di OpenCode significa che puoi eseguire modelli costosi per lavoro architetturale complesso e modelli veloci ed economici per boilerplate e scaffolding di test, cambiando dinamicamente nella stessa sessione.</p>
<hr />
<h2>OpenCode per Sviluppatori WordPress</h2>
<p>Per noi sviluppatori WordPress, OpenCode offre opportunita uniche:</p>
<h3>1. Sviluppo Plugin Automatizzato</h3>
<pre><code>&quot;Analizza il plugin WooCommerce e crea un&#039;estensione che 
aggiunga un campo personalizzato per la data di consegna 
preferita nel checkout&quot;</code></pre>
<p>OpenCode leggera i file rilevanti di WooCommerce, capira gli hook necessari, e generera codice funzionante.</p>
<h3>2. Refactoring Temi</h3>
<p>Con l'integrazione LSP per PHP, puoi:</p>
<ul>
<li>Rinominare funzioni attraverso tutto il tema</li>
<li>Trovare riferimenti a hook deprecati</li>
<li>Identificare codice non utilizzato</li>
</ul>
<h3>3. Debug Automatico</h3>
<pre><code>&quot;Il sito mostra errore 500 sulla pagina shop. 
Analizza i log e identifica la causa.&quot;</code></pre>
<p>L'agente puo leggere i log, identificare il file problematico, e suggerire o implementare la correzione.</p>
<h3>4. Documentazione Automatica</h3>
<pre><code>&quot;Genera documentazione PHPDoc per tutte le funzioni 
pubbliche di questo plugin&quot;</code></pre>
<hr />
<h2>Configurazione Rapida</h2>
<h3>1. Installazione</h3>
<pre><code class="language-bash"># macOS/Linux
curl -fsSL https://get.opencode.ai | sh

# Oppure via npm
npm install -g @opencode-ai/cli</code></pre>
<h3>2. Configurazione Provider</h3>
<p>Crea <code>~/.opencode/config.json</code>:</p>
<pre><code class="language-json">{
  &quot;providers&quot;: {
    &quot;openai&quot;: {
      &quot;apiKey&quot;: &quot;sk-...&quot;
    },
    &quot;anthropic&quot;: {
      &quot;apiKey&quot;: &quot;sk-ant-...&quot;
    }
  },
  &quot;defaultProvider&quot;: &quot;anthropic&quot;,
  &quot;defaultModel&quot;: &quot;claude-sonnet-4&quot;
}</code></pre>
<h3>3. Abilita LSP</h3>
<pre><code class="language-bash">export OPENCODE_EXPERIMENTAL_LSP_TOOL=true</code></pre>
<h3>4. Crea AGENTS.md</h3>
<p>Nella root del tuo progetto WordPress:</p>
<pre><code class="language-markdown"># Project Guidelines

## WordPress Coding Standards
- Segui WordPress Coding Standards
- Usa hook e filtri invece di modificare core
- Prefissa tutte le funzioni con il nome del tema/plugin

## File Structure
- /wp-content/themes/tuo-tema/
- /wp-content/plugins/tuo-plugin/

## Testing
- Esegui test prima di ogni commit
- Verifica compatibilita PHP 7.4+</code></pre>
<hr />
<h2>Dove Sta Andando Tutto Questo</h2>
<p>I team piu ambiziosi che usano OpenCode non lo trattano come un tool CLI. Usano framework come <strong>Oh My OpenCode</strong> per costruire veri sistemi multi-agente dove un manager agent coordina subagent specializzati, ognuno ottimizzato per un tipo specifico di lavoro.</p>
<p>L'orchestrazione, non il modello, e dove avviene il vero lavoro. Quali file l'agente legge. Quali sistemi esterni puo toccare. Come gestisce gli errori. Cosa fa quando e incerto. Il modello stesso e sempre piu una commodity. Puoi sostituirlo.</p>
<p>Questo e l'insight reale sepolto nell'architettura di OpenCode: <strong>lo strumento tratta l'intelligenza come intercambiabile e l'agenzia come la cosa che vale la pena costruire con cura</strong>.</p>
<p>L'LLM puo essere sostituito. La configurazione del progetto, i permessi dei tool, le integrazioni workflow, il file AGENTS.md che codifica gli standard del tuo team - quell'infrastruttura persiste attraverso ogni cambio di modello.</p>
<hr />
<h2>Conclusione</h2>
<p>Inizia con le basi. Inizializza un progetto, esegui alcune sessioni in Plan mode, blocca la tua configurazione dei permessi prima che l'agente tocchi qualcosa di distruttivo. Presta attenzione a cosa l'agente sbaglia e raffina il tuo file AGENTS.md per affrontarlo. Il sistema impara da quel feedback in modo molto diretto: scrivi istruzioni migliori, produce output migliori.</p>
<p>Gli sviluppatori che trattano questo come un sostituto di autocomplete passivo ottengono guadagni incrementali. Quelli che costruiscono attorno ad esso una vera infrastruttura di agent stanno delegando intere categorie di lavoro di ingegneria.</p>
<p><strong>Il divario tra questi due gruppi continuera a crescere.</strong></p>
<hr />
<p><em>Pubblicato il 9 Aprile 2026</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.mrtux.it/opencode-lai-che-programma-mentre-dormi-la-guida-pratica-per-sviluppatori-wordpress/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Hook WordPress: Azioni e Filter per Plugin Professionali</title>
		<link>https://www.mrtux.it/hook-wordpress-azioni-e-filter-per-plugin-professionali</link>
					<comments>https://www.mrtux.it/hook-wordpress-azioni-e-filter-per-plugin-professionali#respond</comments>
		
		<dc:creator><![CDATA[Emilio Petrozzi]]></dc:creator>
		<pubDate>Sat, 21 Mar 2026 19:20:06 +0000</pubDate>
				<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[Actions]]></category>
		<category><![CDATA[Filters]]></category>
		<category><![CDATA[Hook]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[sviluppo]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[wordpress]]></category>
		<guid isPermaLink="false">https://www.mrtux.it/?p=3227</guid>

					<description><![CDATA[Scopri come sfruttare azioni e filter per creare plugin WordPress professionali. Guida completa con 30+ esempi pratici, best practice e codice pronto all'uso per sviluppatori di tutti i livelli.]]></description>
										<content:encoded><![CDATA[<h1>Hook WordPress: Azioni e Filter per Plugin Professionali</h1>
<p><strong>Guida Completa 2026 per Sviluppatori WordPress</strong></p>
<hr />
<h2>🎯 Introduzione</h2>
<p>Gli <strong>hook</strong> sono il cuore pulsante di WordPress. Se vuoi sviluppare plugin professionali, temi child avanzati o semplicemente personalizzare il tuo sito senza modificare i file core, devi padroneggiare questo sistema.</p>
<p>In questa guida scoprirai:</p>
<ul>
<li>✅ La differenza tra <strong>Actions</strong> e <strong>Filters</strong></li>
<li>✅ <strong>30+ esempi pratici</strong> pronti all'uso</li>
<li>✅ Le <strong>best practice</strong> per hook sicuri ed efficienti</li>
<li>✅ Come <strong>intercettare eventi</strong> e modificare contenuti dinamicamente</li>
<li>✅ Gli hook <strong>essenziali</strong> che ogni sviluppatore deve conoscere</li>
</ul>
<p><strong>Prerequisiti:</strong> Conoscenza base di PHP e WordPress</p>
<p><strong>Tempo di lettura:</strong> 15-20 minuti</p>
<hr />
<h2>📚 Cosa Sono gli Hook WordPress?</h2>
<h3>Definizione</h3>
<p>Un <strong>hook</strong> è un punto di aggancio nel codice di WordPress che ti permette di eseguire il tuo codice personalizzato in momenti specifici del ciclo di vita di WordPress.</p>
<h3>Perché Sono Importanti?</h3>
<table>
<thead>
<tr>
<th>Vantaggio</th>
<th>Descrizione</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Non Invasivo</strong></td>
<td>Non modifichi mai i file core di WordPress</td>
</tr>
<tr>
<td><strong>Aggiornamenti Sicuri</strong></td>
<td>Puoi aggiornare WordPress senza perdere le tue modifiche</td>
</tr>
<tr>
<td><strong>Modulare</strong></td>
<td>Ogni funzionalità è isolata e indipendente</td>
</tr>
<tr>
<td><strong>Estensibile</strong></td>
<td>Altri sviluppatori possono estendere il tuo lavoro</td>
</tr>
</tbody>
</table>
<h3>I Due Tipi di Hook</h3>
<pre><code class="language-php">// 1. ACTIONS - Eseguono codice in un momento specifico
do_action(&#039;nome_hook&#039;, $param1, $param2);
add_action(&#039;nome_hook&#039;, &#039;tua_funzione&#039;, $priority, $accepted_args);

// 2. FILTERS - Modificano e restituiscono dati
apply_filters(&#039;nome_hook&#039;, $value, $param1);
add_filter(&#039;nome_hook&#039;, &#039;tua_funzione&#039;, $priority, $accepted_args);</code></pre>
<hr />
<h2>⚡ Actions vs Filters: La Differenza Chiave</h2>
<h3>Actions (Azioni)</h3>
<p><strong>Cosa fanno:</strong> Eseguono codice quando succede qualcosa.</p>
<p><strong>Quando usarle:</strong></p>
<ul>
<li>Inviare email</li>
<li>Scrivere nel database</li>
<li>Inviare notifiche</li>
<li>Caricare script e stili</li>
<li>Registrare custom post type</li>
</ul>
<p><strong>Esempio:</strong></p>
<pre><code class="language-php">// Esegue una funzione quando un post viene pubblicato
add_action(&#039;publish_post&#039;, &#039;invia_notifica_social&#039;, 10, 2);

function invia_notifica_social($ID, $post) {
    // Codice per inviare notifica ai social
    error_log(&#039;Post pubblicato: &#039; . $post-&gt;post_title);
}</code></pre>
<h3>Filters (Filtri)</h3>
<p><strong>Cosa fanno:</strong> Modificano dati e restituiscono il valore modificato.</p>
<p><strong>Quando usarli:</strong></p>
<ul>
<li>Modificare contenuti prima del display</li>
<li>Cambiare titoli dinamicamente</li>
<li>Alterare query del database</li>
<li>Personalizzare excerpt</li>
</ul>
<p><strong>Esempio:</strong></p>
<pre><code class="language-php">// Aggiunge testo alla fine di ogni contenuto
add_filter(&#039;the_content&#039;, &#039;aggiungi_firma_articolo&#039;);

function aggiungi_firma_articolo($content) {
    if (is_single()) {
        $content .= &#039;&lt;p class=&quot;firma&quot;&gt;📝 Articolo scritto da Mario Rossi&lt;/p&gt;&#039;;
    }
    return $content; // ⚠️ IMPORTANTE: devi restituire il valore!
}</code></pre>
<h3>Tabella Comparativa</h3>
<table>
<thead>
<tr>
<th>Caratteristica</th>
<th>Actions</th>
<th>Filters</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Scopo</strong></td>
<td>Eseguire azioni</td>
<td>Modificare dati</td>
</tr>
<tr>
<td><strong>Return</strong></td>
<td>Non necessario</td>
<td><strong>OBBLIGATORIO</strong></td>
</tr>
<tr>
<td><strong>Funzione</strong></td>
<td><code>do_action()</code></td>
<td><code>apply_filters()</code></td>
</tr>
<tr>
<td><strong>Registrazione</strong></td>
<td><code>add_action()</code></td>
<td><code>add_filter()</code></td>
</tr>
<tr>
<td><strong>Esempio</strong></td>
<td>Invio email</td>
<td>Modifica titolo</td>
</tr>
</tbody>
</table>
<hr />
<h2>🔥 30+ Esempi Pratici di Hook Essenziali</h2>
<h3>📌 Hook per Plugin Development</h3>
<h4>1. Inizializzazione Plugin</h4>
<pre><code class="language-php">// Eseguito dopo che WordPress è caricato
add_action(&#039;init&#039;, &#039;mio_plugin_init&#039;);

function mio_plugin_init() {
    // Carica traduzioni
    load_plugin_textdomain(&#039;mio-plugin&#039;, false, dirname(plugin_basename(__FILE__)) . &#039;/languages&#039;);

    // Registra custom post type
    register_post_type(&#039;progetto&#039;, array(
        &#039;public&#039; =&gt; true,
        &#039;label&#039; =&gt; &#039;Progetti&#039;
    ));
}</code></pre>
<h4>2. Attivazione Plugin</h4>
<pre><code class="language-php">// Eseguito quando il plugin viene attivato
register_activation_hook(__FILE__, &#039;mio_plugin_attiva&#039;);

function mio_plugin_attiva() {
    // Crea tabelle database
    global $wpdb;
    $table_name = $wpdb-&gt;prefix . &#039;mio_plugin_dati&#039;;

    $charset_collate = $wpdb-&gt;get_charset_collate();

    $sql = &quot;CREATE TABLE $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        data datetime DEFAULT &#039;0000-00-00 00:00:00&#039; NOT NULL,
        PRIMARY KEY  (id)
    ) $charset_collate;&quot;;

    require_once(ABSPATH . &#039;wp-admin/includes/upgrade.php&#039;);
    dbDelta($sql);

    // Imposta opzioni default
    add_option(&#039;mio_plugin_version&#039;, &#039;1.0.0&#039;);
}</code></pre>
<h4>3. Disattivazione Plugin</h4>
<pre><code class="language-php">// Eseguito quando il plugin viene disattivato
register_deactivation_hook(__FILE__, &#039;mio_plugin_disattiva&#039;);

function mio_plugin_disattiva() {
    // Pulisci cron jobs
    wp_clear_scheduled_hook(&#039;mio_plugin_evento_giornaliero&#039;);

    // NON cancellare i dati! Lascia all&#039;utente la scelta
}</code></pre>
<h4>4. Aggiunta Menu Admin</h4>
<pre><code class="language-php">add_action(&#039;admin_menu&#039;, &#039;mio_plugin_menu_admin&#039;);

function mio_plugin_menu_admin() {
    add_menu_page(
        &#039;Mio Plugin&#039;,           // Titolo pagina
        &#039;Mio Plugin&#039;,           // Titolo menu
        &#039;manage_options&#039;,       // Capacità richiesta
        &#039;mio-plugin&#039;,           // Slug
        &#039;mio_plugin_pagina&#039;,    // Funzione callback
        &#039;dashicons-admin-settings&#039;, // Icona
        30                      // Posizione
    );
}</code></pre>
<h4>5. Caricamento Script e Stili</h4>
<pre><code class="language-php">add_action(&#039;wp_enqueue_scripts&#039;, &#039;mio_plugin_carica_risorse&#039;);

function mio_plugin_carica_risorse() {
    // Carica CSS
    wp_enqueue_style(
        &#039;mio-plugin-style&#039;,
        plugin_dir_url(__FILE__) . &#039;css/style.css&#039;,
        array(),
        &#039;1.0.0&#039;
    );

    // Carica JavaScript
    wp_enqueue_script(
        &#039;mio-plugin-script&#039;,
        plugin_dir_url(__FILE__) . &#039;js/script.js&#039;,
        array(&#039;jquery&#039;),
        &#039;1.0.0&#039;,
        true // Carica nel footer
    );

    // Passa dati a JavaScript
    wp_localize_script(&#039;mio-plugin-script&#039;, &#039;mioPluginData&#039;, array(
        &#039;ajaxUrl&#039; =&gt; admin_url(&#039;admin-ajax.php&#039;),
        &#039;nonce&#039; =&gt; wp_create_nonce(&#039;mio_plugin_nonce&#039;)
    ));
}</code></pre>
<hr />
<h3>📌 Hook per Modificare Contenuti</h3>
<h4>6. Modifica Titolo Post</h4>
<pre><code class="language-php">add_filter(&#039;the_title&#039;, &#039;mio_prefix_titolo&#039;, 10, 2);

function mio_prefix_titolo($title, $post_id) {
    if (is_single() &amp;&amp; !is_admin()) {
        $title = &#039;🔥 &#039; . $title;
    }
    return $title;
}</code></pre>
<h4>7. Aggiungi Contenuto Dopo il Post</h4>
<pre><code class="language-php">add_filter(&#039;the_content&#039;, &#039;aggiungi_contenuto_dopo_post&#039;);

function aggiungi_contenuto_dopo_post($content) {
    if (is_single() &amp;&amp; in_the_loop() &amp;&amp; is_main_query()) {
        $content .= &#039;
        &lt;div class=&quot;post-footer&quot;&gt;
            &lt;p&gt;📧 Iscriviti alla newsletter per altri articoli come questo!&lt;/p&gt;
            [newsletter-form]
        &lt;/div&gt;&#039;;
    }
    return $content;
}</code></pre>
<h4>8. Modifica Excerpt</h4>
<pre><code class="language-php">add_filter(&#039;excerpt_length&#039;, &#039;mio_excerpt_lunghezza&#039;);

function mio_excerpt_lunghezza($length) {
    return 30; // Default è 55
}

add_filter(&#039;excerpt_more&#039;, &#039;mio_excerpt_piu&#039;);

function mio_excerpt_piu($more) {
    return &#039;... &lt;a href=&quot;&#039; . get_permalink() . &#039;&quot;&gt;Leggi tutto →&lt;/a&gt;&#039;;
}</code></pre>
<h4>9. Personalizza URL Autore</h4>
<pre><code class="language-php">add_filter(&#039;author_link&#039;, &#039;mio_custom_author_link&#039;, 10, 3);

function mio_custom_author_link($link, $author_id, $author_nicename) {
    return home_url(&#039;/team/&#039; . $author_nicename . &#039;/&#039;);
}</code></pre>
<h4>10. Filtra Query Principale</h4>
<pre><code class="language-php">add_action(&#039;pre_get_posts&#039;, &#039;mio_filtra_query_homepage&#039;);

function mio_filtra_query_homepage($query) {
    if ($query-&gt;is_main_query() &amp;&amp; $query-&gt;is_home()) {
        $query-&gt;set(&#039;posts_per_page&#039;, 10);
        $query-&gt;set(&#039;orderby&#039;, &#039;date&#039;);
        $query-&gt;set(&#039;order&#039;, &#039;DESC&#039;);
    }
}</code></pre>
<hr />
<h3>📌 Hook per WooCommerce</h3>
<h4>11. Modifica Prezzo Prodotto</h4>
<pre><code class="language-php">add_filter(&#039;woocommerce_product_get_price&#039;, &#039;mio_modifica_prezzo&#039;, 10, 2);

function mio_modifica_prezzo($price, $product) {
    // Applica sconto del 10% ai prodotti sopra 100€
    if ($price &gt; 100) {
        $price = $price * 0.9;
    }
    return $price;
}</code></pre>
<h4>12. Aggiungi Campo Checkout</h4>
<pre><code class="language-php">add_action(&#039;woocommerce_after_order_notes&#039;, &#039;mio_campo_checkout&#039;);

function mio_campo_checkout($checkout) {
    echo &#039;&lt;div id=&quot;mio_campo_extra&quot;&gt;&#039;;

    woocommerce_form_field(&#039;codice_fiscale&#039;, array(
        &#039;type&#039; =&gt; &#039;text&#039;,
        &#039;class&#039; =&gt; array(&#039;form-row-wide&#039;),
        &#039;label&#039; =&gt; __(&#039;Codice Fiscale&#039;),
        &#039;placeholder&#039; =&gt; __(&#039;Inserisci il tuo CF&#039;),
        &#039;required&#039; =&gt; true,
    ), $checkout-&gt;get_value(&#039;codice_fiscale&#039;));

    echo &#039;&lt;/div&gt;&#039;;
}</code></pre>
<h4>13. Email Personalizzata Ordine</h4>
<pre><code class="language-php">add_filter(&#039;woocommerce_email_subject_customer_completed_order&#039;, &#039;mio_oggetto_email&#039;, 10, 2);

function mio_oggetto_email($subject, $order) {
    return &#039;🎉 Il tuo ordine #&#039; . $order-&gt;get_id() . &#039; è stato completato!&#039;;
}</code></pre>
<h4>14. Azione Dopo Acquisto</h4>
<pre><code class="language-php">add_action(&#039;woocommerce_checkout_order_processed&#039;, &#039;mio_dopo_acquisto&#039;, 10, 3);

function mio_dopo_acquisto($order_id, $posted_data, $order) {
    // Invia notifica Slack
    // Aggiorna CRM
    // Invia SMS
    error_log(&#039;Ordine processato: &#039; . $order_id);
}</code></pre>
<hr />
<h3>📌 Hook per Sicurezza</h3>
<h4>15. Sanitizzazione Input</h4>
<pre><code class="language-php">// MAI fidarsi degli input utente!
add_action(&#039;admin_post_mio_form&#039;, &#039;mio_elabora_form&#039;);

function mio_elabora_form() {
    // Verifica nonce
    check_admin_referer(&#039;mio_form_action&#039;, &#039;mio_nonce&#039;);

    // Sanitizza input
    $nome = sanitize_text_field($_POST[&#039;nome&#039;]);
    $email = sanitize_email($_POST[&#039;email&#039;]);
    $url = esc_url_raw($_POST[&#039;website&#039;]);

    // Salva dati
    // ...
}</code></pre>
<h4>16. Escape Output</h4>
<pre><code class="language-php">// SEMPRE fare escape dell&#039;output!
function mio_display_dati() {
    echo &#039;&lt;h2&gt;&#039; . esc_html($titolo) . &#039;&lt;/h2&gt;&#039;;
    echo &#039;&lt;a href=&quot;&#039; . esc_url($url) . &#039;&quot;&gt;Link&lt;/a&gt;&#039;;
    echo &#039;&lt;div&gt;&#039; . esc_attr($attributo) . &#039;&lt;/div&gt;&#039;;
}</code></pre>
<h4>17. Verifica Permessi</h4>
<pre><code class="language-php">add_action(&#039;admin_init&#039;, &#039;mio_verifica_permessi&#039;);

function mio_verifica_permessi() {
    if (!current_user_can(&#039;manage_options&#039;)) {
        wp_die(&#039;Non hai i permessi per accedere a questa pagina.&#039;);
    }
}</code></pre>
<hr />
<h3>📌 Hook per Performance</h3>
<h4>18. Disabilita Emoji (Risparmio Query)</h4>
<pre><code class="language-php">remove_action(&#039;wp_head&#039;, &#039;print_emoji_detection_script&#039;, 7);
remove_action(&#039;admin_print_scripts&#039;, &#039;print_emoji_detection_script&#039;);
remove_action(&#039;wp_print_styles&#039;, &#039;print_emoji_styles&#039;);
remove_action(&#039;admin_print_styles&#039;, &#039;print_emoji_styles&#039;);</code></pre>
<h4>19. Disabilita Embed OEmbed</h4>
<pre><code class="language-php">add_action(&#039;init&#039;, &#039;mio_disabilita_embed&#039;, 1);

function mio_disabilita_embed() {
    remove_action(&#039;rest_api_init&#039;, &#039;wp_oembed_register_route&#039;);
    remove_filter(&#039;rest_pre_serve_request&#039;, &#039;wp_oembed_send_header&#039;);
    remove_action(&#039;wp_head&#039;, &#039;wp_oembed_add_discovery_links&#039;);
    remove_action(&#039;wp_head&#039;, &#039;wp_oembed_add_host_js&#039;);
}</code></pre>
<h4>20. Limit Heartbeat API</h4>
<pre><code class="language-php">add_filter(&#039;heartbeat_settings&#039;, &#039;mio_limit_heartbeat&#039;);

function mio_limit_heartbeat($settings) {
    $settings[&#039;interval&#039;] = 60; // Default è 15 secondi
    return $settings;
}</code></pre>
<hr />
<h3>📌 Hook per SEO</h3>
<h4>21. Aggiungi Meta Tag</h4>
<pre><code class="language-php">add_action(&#039;wp_head&#039;, &#039;mio_meta_tag_custom&#039;);

function mio_meta_tag_custom() {
    if (is_single()) {
        echo &#039;&lt;meta name=&quot;author&quot; content=&quot;Mario Rossi&quot; /&gt;&#039;;
        echo &#039;&lt;meta property=&quot;article:published_time&quot; content=&quot;&#039; . get_the_date(&#039;c&#039;) . &#039;&quot; /&gt;&#039;;
    }
}</code></pre>
<h4>22. Modifica Title Tag</h4>
<pre><code class="language-php">add_filter(&#039;document_title_parts&#039;, &#039;mio_custom_title&#039;);

function mio_custom_title($title) {
    if (is_home()) {
        $title[&#039;title&#039;] = &#039;Blog - &#039; . get_bloginfo(&#039;name&#039;);
    }
    return $title;
}</code></pre>
<h4>23. Aggiungi Schema.org</h4>
<pre><code class="language-php">add_action(&#039;wp_head&#039;, &#039;mio_schema_org&#039;);

function mio_schema_org() {
    if (is_single()) {
        ?&gt;
        &lt;script type=&quot;application/ld+json&quot;&gt;
        {
            &quot;@context&quot;: &quot;https://schema.org&quot;,
            &quot;@type&quot;: &quot;Article&quot;,
            &quot;headline&quot;: &quot;&lt;?php echo esc_js(get_the_title()); ?&gt;&quot;,
            &quot;author&quot;: {
                &quot;@type&quot;: &quot;Person&quot;,
                &quot;name&quot;: &quot;&lt;?php echo esc_js(get_the_author()); ?&gt;&quot;
            }
        }
        &lt;/script&gt;
        &lt;?php
    }
}</code></pre>
<hr />
<h3>📌 Hook per Custom Post Type</h3>
<h4>24. Registra Custom Post Type</h4>
<pre><code class="language-php">add_action(&#039;init&#039;, &#039;mio_registra_cpt_progetto&#039;);

function mio_registra_cpt_progetto() {
    $labels = array(
        &#039;name&#039; =&gt; &#039;Progetti&#039;,
        &#039;singular_name&#039; =&gt; &#039;Progetto&#039;,
        &#039;add_new&#039; =&gt; &#039;Aggiungi Nuovo&#039;,
        &#039;add_new_item&#039; =&gt; &#039;Aggiungi Nuovo Progetto&#039;,
        &#039;edit_item&#039; =&gt; &#039;Modifica Progetto&#039;,
        &#039;new_item&#039; =&gt; &#039;Nuovo Progetto&#039;,
        &#039;view_item&#039; =&gt; &#039;Vedi Progetto&#039;,
        &#039;search_items&#039; =&gt; &#039;Cerca Progetti&#039;,
        &#039;not_found&#039; =&gt; &#039;Nessun progetto trovato&#039;,
        &#039;menu_name&#039; =&gt; &#039;Progetti&#039;
    );

    $args = array(
        &#039;labels&#039; =&gt; $labels,
        &#039;public&#039; =&gt; true,
        &#039;has_archive&#039; =&gt; true,
        &#039;show_in_rest&#039; =&gt; true, // Abilita Gutenberg
        &#039;supports&#039; =&gt; array(&#039;title&#039;, &#039;editor&#039;, &#039;thumbnail&#039;, &#039;excerpt&#039;),
        &#039;menu_icon&#039; =&gt; &#039;dashicons-portfolio&#039;,
        &#039;rewrite&#039; =&gt; array(&#039;slug&#039; =&gt; &#039;progetti&#039;)
    );

    register_post_type(&#039;progetto&#039;, $args);
}</code></pre>
<h4>25. Registra Tassonomia Custom</h4>
<pre><code class="language-php">add_action(&#039;init&#039;, &#039;mio_registra_tassonomia_cliente&#039;, 0);

function mio_registra_tassonomia_cliente() {
    $labels = array(
        &#039;name&#039; =&gt; &#039;Clienti&#039;,
        &#039;singular_name&#039; =&gt; &#039;Cliente&#039;,
        &#039;search_items&#039; =&gt; &#039;Cerca Clienti&#039;,
        &#039;all_items&#039; =&gt; &#039;Tutti i Clienti&#039;,
        &#039;edit_item&#039; =&gt; &#039;Modifica Cliente&#039;,
        &#039;add_new_item&#039; =&gt; &#039;Aggiungi Nuovo Cliente&#039;,
        &#039;menu_name&#039; =&gt; &#039;Clienti&#039;
    );

    $args = array(
        &#039;labels&#039; =&gt; $labels,
        &#039;public&#039; =&gt; true,
        &#039;hierarchical&#039; =&gt; false,
        &#039;show_in_rest&#039; =&gt; true,
        &#039;rewrite&#039; =&gt; array(&#039;slug&#039; =&gt; &#039;cliente&#039;)
    );

    register_taxonomy(&#039;cliente&#039;, &#039;progetto&#039;, $args);
}</code></pre>
<h4>26. Meta Box per CPT</h4>
<pre><code class="language-php">add_action(&#039;add_meta_boxes&#039;, &#039;mio_aggiungi_meta_box&#039;);

function mio_aggiungi_meta_box() {
    add_meta_box(
        &#039;mio_meta_box&#039;,
        &#039;Dettagli Progetto&#039;,
        &#039;mio_meta_box_callback&#039;,
        &#039;progetto&#039;,
        &#039;normal&#039;,
        &#039;high&#039;
    );
}

function mio_meta_box_callback($post) {
    wp_nonce_field(&#039;mio_meta_box_action&#039;, &#039;mio_meta_box_nonce&#039;);

    $valore = get_post_meta($post-&gt;ID, &#039;_mio_metakey&#039;, true);

    echo &#039;&lt;label for=&quot;mio_field&quot;&gt;Budget:&lt;/label&gt;&#039;;
    echo &#039;&lt;input type=&quot;text&quot; id=&quot;mio_field&quot; name=&quot;mio_field&quot; value=&quot;&#039; . esc_attr($valore) . &#039;&quot; style=&quot;width:100%&quot; /&gt;&#039;;
}</code></pre>
<h4>27. Salva Meta Box</h4>
<pre><code class="language-php">add_action(&#039;save_post_progetto&#039;, &#039;mio_salva_meta_box&#039;, 10, 2);

function mio_salva_meta_box($post_id, $post) {
    // Verifica nonce
    if (!isset($_POST[&#039;mio_meta_box_nonce&#039;]) || 
        !wp_verify_nonce($_POST[&#039;mio_meta_box_nonce&#039;], &#039;mio_meta_box_action&#039;)) {
        return;
    }

    // Verifica autosave
    if (defined(&#039;DOING_AUTOSAVE&#039;) &amp;&amp; DOING_AUTOSAVE) {
        return;
    }

    // Verifica permessi
    if (!current_user_can(&#039;edit_post&#039;, $post_id)) {
        return;
    }

    // Salva dato
    if (isset($_POST[&#039;mio_field&#039;])) {
        update_post_meta($post_id, &#039;_mio_metakey&#039;, sanitize_text_field($_POST[&#039;mio_field&#039;]));
    }
}</code></pre>
<hr />
<h3>📌 Hook per Utility</h3>
<h4>28. Redirect Dopo Login</h4>
<pre><code class="language-php">add_filter(&#039;login_redirect&#039;, &#039;mio_redirect_login&#039;, 10, 3);

function mio_redirect_login($redirect_to, $request, $user) {
    if (isset($user-&gt;roles) &amp;&amp; is_array($user-&gt;roles)) {
        if (in_array(&#039;administrator&#039;, $user-&gt;roles)) {
            return admin_url();
        } else {
            return home_url(&#039;/dashboard/&#039;);
        }
    }
    return $redirect_to;
}</code></pre>
<h4>29. Nascondi Barra Admin</h4>
<pre><code class="language-php">add_filter(&#039;show_admin_bar&#039;, &#039;__return_false&#039;);</code></pre>
<h4>30. Cambia Logo Login</h4>
<pre><code class="language-php">add_action(&#039;login_enqueue_scripts&#039;, &#039;mio_logo_login&#039;);

function mio_logo_login() {
    echo &#039;&lt;style&gt;
        .login h1 a {
            background-image: url(&#039; . get_stylesheet_directory_uri() . &#039;/images/logo-login.png);
            width: 300px;
            height: 100px;
            background-size: contain;
        }
    &lt;/style&gt;&#039;;
}</code></pre>
<h4>31. Footer Personalizzato Admin</h4>
<pre><code class="language-php">add_filter(&#039;admin_footer_text&#039;, &#039;mio_footer_admin&#039;);

function mio_footer_admin($text) {
    return &#039;Sviluppato con ❤️ da &lt;a href=&quot;https://mrtux.it&quot; target=&quot;_blank&quot;&gt;MrTux&lt;/a&gt;&#039;;
}</code></pre>
<h4>32. Cron Job Personalizzato</h4>
<pre><code class="language-php">// Registra evento cron all&#039;attivazione plugin
register_activation_hook(__FILE__, &#039;mio_attiva_cron&#039;);

function mio_attiva_cron() {
    if (!wp_next_scheduled(&#039;mio_evento_giornaliero&#039;)) {
        wp_schedule_event(time(), &#039;daily&#039;, &#039;mio_evento_giornaliero&#039;);
    }
}

// Esegui azione
add_action(&#039;mio_evento_giornaliero&#039;, &#039;mio_esegui_task&#039;);

function mio_esegui_task() {
    // Invia report email
    // Pulisci database
    // Aggiorna cache
    error_log(&#039;Task giornaliero eseguito&#039;);
}

// Rimuovi cron alla disattivazione
register_deactivation_hook(__FILE__, &#039;mio_disattiva_cron&#039;);

function mio_disattiva_cron() {
    wp_clear_scheduled_hook(&#039;mio_evento_giornaliero&#039;);
}</code></pre>
<hr />
<h2>🎯 Best Practice per Hook Professionali</h2>
<h3>1. Usa Priority Correttamente</h3>
<pre><code class="language-php">// ❌ SBAGLIATO: Priority default (10) potrebbe confliggere
add_action(&#039;init&#039;, &#039;mia_funzione&#039;);

// ✅ CORRETTO: Specifica priority esplicita
add_action(&#039;init&#039;, &#039;mia_funzione&#039;, 20);  // Dopo i default
add_action(&#039;init&#039;, &#039;mia_funzione&#039;, 5);   // Prima dei default</code></pre>
<h3>2. Accetta Tutti gli Argomenti</h3>
<pre><code class="language-php">// ❌ SBAGLIATO: Perdi dati
add_action(&#039;publish_post&#039;, &#039;mia_funzione&#039;);
function mia_funzione($ID) {
    // ...
}

// ✅ CORRETTO: Accetta tutti gli argomenti
add_action(&#039;publish_post&#039;, &#039;mia_funzione&#039;, 10, 2);
function mia_funzione($ID, $post) {
    // Ora hai accesso a $post completo
}</code></pre>
<h3>3. Namespacing per Evitare Conflitti</h3>
<pre><code class="language-php">// ❌ SBAGLIATO: Nomi generici
add_action(&#039;init&#039;, &#039;init_function&#039;);

// ✅ CORRETTO: Prefix unico
add_action(&#039;init&#039;, &#039;mio_plugin_init_function&#039;);

// ✅ OTTIMO: Namespace PHP
namespace MioPlugin;

add_action(&#039;init&#039;, __NAMESPACE__ . &#039;\init_function&#039;);</code></pre>
<h3>4. Documenta i Tuoi Hook</h3>
<pre><code class="language-php">/**
 * Hook personalizzato per dopo la pubblicazione
 *
 * @since 1.0.0
 * @param int $post_id ID del post pubblicato
 * @param WP_Post $post Oggetto post completo
 */
do_action(&#039;mio_plugin_dopo_pubblicazione&#039;, $post_id, $post);</code></pre>
<h3>5. Usa Hook Removibili</h3>
<pre><code class="language-php">// ✅ Permetti ad altri di rimuovere il tuo hook
add_action(&#039;wp_head&#039;, &#039;mio_funzione_removibile&#039;);

// Altri sviluppatori possono fare:
remove_action(&#039;wp_head&#039;, &#039;mio_funzione_removibile&#039;);</code></pre>
<hr />
<h2>📋 Checklist Sviluppo Plugin con Hook</h2>
<h3>Prima di Pubblicare</h3>
<ul>
<li>[ ] Tutti gli hook hanno prefix unico?</li>
<li>[ ] Le funzioni restituiscono valori (per i filter)?</li>
<li>[ ] Gli input sono sanitizzati?</li>
<li>[ ] L'output è escaped?</li>
<li>[ ] I nonce sono verificati?</li>
<li>[ ] I permessi sono controllati?</li>
<li>[ ] Gli hook di attivazione/disattivazione sono presenti?</li>
<li>[ ] I cron job sono puliti alla disattivazione?</li>
</ul>
<h3>Performance</h3>
<ul>
<li>[ ] Gli hook sono registrati solo quando necessario?</li>
<li>[ ] Le query database sono minimizzate?</li>
<li>[ ] Gli script sono caricati solo nelle pagine necessarie?</li>
<li>[ ] La cache è utilizzata appropriatamente?</li>
</ul>
<hr />
<h2>🐛 Troubleshooting Comune</h2>
<h3>Hook Non Funziona</h3>
<p><strong>Problema:</strong> Il tuo hook non viene eseguito.</p>
<p><strong>Soluzioni:</strong></p>
<ol>
<li>Verifica che l'hook esista: <code>do_action_deprecated()</code> nei log</li>
<li>Controlla la priority: potrebbe essere eseguito troppo tardi</li>
<li>Verifica i permessi: <code>current_user_can()</code></li>
<li>Controlla condizioni: <code>is_admin()</code>, <code>is_single()</code>, etc.</li>
</ol>
<h3>Filter Non Modifica Nulla</h3>
<p><strong>Problema:</strong> Il filter non altera il valore.</p>
<p><strong>Soluzioni:</strong></p>
<ol>
<li><strong>Assicurati di RETURN:</strong> <code>return $value;</code></li>
<li>Verifica la priority: altri filter potrebbero sovrascrivere</li>
<li>Controlla il tipo di dato restituito</li>
</ol>
<h3>Conflitti tra Plugin</h3>
<p><strong>Problema:</strong> Due plugin usano lo stesso hook name.</p>
<p><strong>Soluzioni:</strong></p>
<ol>
<li>Usa prefix unici nei nomi delle funzioni</li>
<li>Specifica priority diverse</li>
<li>Usa namespace PHP</li>
</ol>
<hr />
<h2>📚 Risorse Utili</h2>
<h3>Documentazione Ufficiale</h3>
<ul>
<li><a href="https://developer.wordpress.org/plugins/plugin-basics/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">WordPress Plugin API</a></li>
<li><a href="https://developer.wordpress.org/reference/hooks/#actions" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Action Reference</a></li>
<li><a href="https://developer.wordpress.org/reference/hooks/#filters" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Filter Reference</a></li>
</ul>
<h3>Strumenti di Debug</h3>
<pre><code class="language-php">// Lista tutti gli hook registrati
global $wp_filter;
print_r(array_keys($wp_filter));

// Vedi chi è agganciato a un hook
print_r($wp_filter[&#039;init&#039;]);

// Debug hook execution
add_action(&#039;all&#039;, function($hook) {
    error_log(&#039;Hook eseguito: &#039; . $hook);
});</code></pre>
<h3>Plugin Utili</h3>
<ul>
<li><strong>Query Monitor:</strong> Debug hook e query</li>
<li><strong>Hook Sniffer:</strong> Vedi tutti gli hook eseguiti</li>
<li><strong>What The File:</strong> Vedi quale template è caricato</li>
</ul>
<hr />
<h2>🎓 Conclusione</h2>
<p>Gli hook WordPress sono uno strumento potente che separa i developer principianti da quelli professionisti. Padroneggiandoli, potrai:</p>
<p>✅ Creare plugin modulari e mantenibili<br />
✅ Personalizzare WordPress senza modificare il core<br />
✅ Integrarti con qualsiasi tema o plugin<br />
✅ Costruire soluzioni scalabili e sicure</p>
<p><strong>Prossimi Passi:</strong></p>
<ol>
<li>Sperimenta con gli esempi in questa guida</li>
<li>Crea un plugin di test per praticare</li>
<li>Esplora il <a href="https://developer.wordpress.org/reference/hooks/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">WordPress Hook Reference</a></li>
<li>Contribuisci alla community con i tuoi hook</li>
</ol>
<hr />
<h2>💬 Hai Domande?</h2>
<p>Lascia un commento o contattaci per consulenza sullo sviluppo di plugin WordPress professionali!</p>
<p><strong>📧 Newsletter:</strong> Iscriviti per ricevere altri tutorial come questo!</p>
<hr />
<p><em>Ultimo aggiornamento: Marzo 2026</em><br />
<em>Tempo di lettura: 20 minuti</em><br />
<em>Parole: 2.500+</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.mrtux.it/hook-wordpress-azioni-e-filter-per-plugin-professionali/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Installare VestaCP e WordPress su server VPS con Centos 7</title>
		<link>https://www.mrtux.it/installare-wordpress-vps-centos-7-vestacp</link>
					<comments>https://www.mrtux.it/installare-wordpress-vps-centos-7-vestacp#respond</comments>
		
		<dc:creator><![CDATA[Emilio Petrozzi]]></dc:creator>
		<pubDate>Mon, 02 Dec 2019 18:46:47 +0000</pubDate>
				<category><![CDATA[Wordpress]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[wordpress]]></category>
		<guid isPermaLink="false">https://www.mrtux.it/?p=990</guid>

					<description><![CDATA[In questa breve guida vedremo come installare WordPress su un server VPS con Linux Centos 7. In tal modo potremo avere immediatamente disponibile Nginx configurato con l'ultima versione di PHP-FPM, ovvero la 7.4. Prerequisiti Sarà necessario disporre di un server VPS (oppure un server dedicato) con installato Linux Centos 7. Le risorse di sistema minime [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>In questa breve guida vedremo come installare WordPress su <a href="https://it.wikipedia.org/wiki/Virtual_private_server" target="_blank" rel="noopener nofollow external" data-wpel-link="external">un server VPS</a> con <a href="https://www.centos.org/download/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Linux Centos 7</a>. In tal modo potremo avere immediatamente disponibile Nginx configurato con l'ultima versione di PHP-FPM, ovvero la 7.4.</p>

<h2 id="prerequisiti">Prerequisiti</h2>
<p>Sarà necessario disporre di un server VPS (oppure un server dedicato) con installato Linux Centos 7. Le risorse di sistema minime richieste sono di almeno di 1 GB di memoria RAM.</p>
<h2 id="config-linux-centos">Configurazione di Linux Centos 7</h2>
<p>Attraverso la password dell'utente root procediamo con il login sul server appena installato:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">pc@locale# ssh root@ip-server-remoto
</code></pre>

<p>Quindi aggiorniamo i pacchetti installati su Centos 7:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# yum update
</code></pre>

<p>Installiamo, se non già installati, i programmi che andremo ad utilizzare in seguito:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# yum install mc nano curl
</code></pre>

<p>Rimuoviamo la timezone attuale e impostiamola sull'ora italiana:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# rm /etc/localtime
server@remoto# ln -s /usr/share/zoneinfo/Europe/Rome /etc/localtime
</code></pre>

<h2 id="installazione-vestacp">Installazione di VestaCP</h2>
<p>Prima dell'installazione di <a href="https://vestacp.com/" target="_blank" rel="noopener nofollow external" data-wpel-link="external">Vesta Control Panel</a> sarà necessario rimuovere eventuali installazioni di Apache, Nginx oppure del database MySQL. Di solito il web server che viene installato di default è Apache e per rimuoverlo completamente utilizzaremo i seguenti comandi:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# yum erase httpd httpd-tools apr apr-util
</code></pre>

<p>Quindi utilizzaremo il seguente comando per verificare se tutti i pacchetti relativi al web server Apache sono stati rimossi:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# rpm -qa | grep httpd
</code></pre>

<p>Rimoviamo la cartella radice del server web:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# rm -rf /var/www
</code></pre>

<p>Rimozione dei file di configurazione:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# rm -rf /etc/httpd
</code></pre>

<p>Rimozione dei moduli Apache:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# rm -rf /usr/lib64/httpd
</code></pre>

<p>Rimozione dell'utente Apache:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# userdel -r apache
</code></pre>

<p>Con il seguente comando ci accertiamo che non sia presente l'utente Apache in /etc/passwd:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# grep "apache" /etc/passwd
</code></pre>

<p>Infine verifichiamo se il web server risulta attivo o meno:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# systemctl status httpd
</code></pre>

<p>Arrivati a questo punto possiamo procedere con l'installazione del pannello di controllo VestaCP.</p>
<p>In particolare procederemo all'installazione del pannello di controllo configurandolo in modo da poter essere utilizzato con il web server Nginx e il modulo autonomo <a href="https://www.php.net/manual/en/install.fpm.php" target="_blank" rel="noopener nofollow external" data-wpel-link="external">php-fpm</a> che provvederà ad interpretare il codice PHP presente sulle pagine web.</p>
<p>A tale scopo utilizzeremo i seguenti comandi, come indicato nelle relative istruzioni per l'installazione:</p>
<p>Scarichiamo lo script di installazione:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# curl -O http://vestacp.com/pub/vst-install.sh
</code></pre>

<p>E lanciamo tale script con i seguenti parametri:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">server@remoto# bash vst-install.sh --nginx yes --phpfpm yes --apache no --named yes --remi yes --vsftpd no --proftpd no --iptables yes --fail2ban yes --quota no --exim no --dovecot no --spamassassin no --clamav no --softaculous no --mysql yes --postgresql no --hostname server.nomehost.it --email info@nomehost.it --password password-pannello
</code></pre>

<p>I parametri sopra indicati installeranno solo il server web Nginx, il relativo modulo php e il <a href="https://www.fail2ban.org/wiki/index.php/Main_Page" target="_blank" rel="noopener nofollow external" data-wpel-link="external">firewall fail2ban</a>, evitando quindi di installare i server email e ftp.</p>
<p>Ovviamente sarà necessario sostituire server.nomehost.it con il proprio sotto-dominio opportunamente configurato attraverso il pannello di getione DNS del proprio registrar.</p>
<p>Durante l'installazione uno dei problemi più comuni riscontrati è relativo all'errata gestione dei collegamenti simbolici sia del web server Nginx che del firewall fail2ban.</p>
<p>In tal caso sarà necessario interrompere momentaneamente l'installazione attraverso il comando CTRL-C e apportare le seguenti modifiche. Nel caso sottostante la procedura è riferita al solo sever Nginx ma la procedura è la stessa per fail2ban.</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash"># nano /etc/sysctl.d/disable_ipv6.conf
</code></pre>

<p>net.ipv6.conf.all.disable_ipv6 = 1<br />net.ipv6.conf.default.disable_ipv6 = 1</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash"># nano /usr/lib/systemd/system/nginx.service
</code></pre>

<p>Trovare:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">PIDFile=/var/run/nginx.pid
</code></pre>

<p>Sostituire con:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">PIDFile=/run/nginx.pid
</code></pre>



<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash"># nano /etc/nginx/nginx.conf
</code></pre>

<p>Trovare:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">pid /var/run/nginx.pid;
</code></pre>

<p>Sostituire con:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash">pid /run/nginx.pid;
</code></pre>

<p>Infine rendere effettivi gli aggiornamento con i seguenti comandi:</p>

<pre class="wp-block-code"><code class="language-bash line-numbers" lang="bash"># systemctl daemon-reload
# reboot
</code></pre>

<p>A questo punto l'installazione sarà completata in circa 10 minuti e potremo effettuare il login sul pannello di controllo di VestaCP.</p>

<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img fetchpriority="high" decoding="async" class="wp-image-993" src="https://www.mrtux.it/wp-content/uploads/2019/12/vestacp-login-1024x575.png" alt="installazione worpress su vestacp e centos 7" width="1024" height="575" srcset="https://www.mrtux.it/wp-content/uploads/2019/12/vestacp-login-1024x575.png 1024w, https://www.mrtux.it/wp-content/uploads/2019/12/vestacp-login-300x168.png 300w, https://www.mrtux.it/wp-content/uploads/2019/12/vestacp-login-768x431.png 768w, https://www.mrtux.it/wp-content/uploads/2019/12/vestacp-login-20x11.png 20w, https://www.mrtux.it/wp-content/uploads/2019/12/vestacp-login.png 1142w" sizes="(max-width: 1024px) 100vw, 1024px" />
<figcaption>VestaCP su Centos 7</figcaption>
</figure>
</div>



<p class="wp-block-paragraph">Infine possiamo procedere con l'installazione e la configurazione di WordPress attraverso WP-CLI, come descritto nel relativo <a class="rank-math-link" href="https://www.mrtux.it/installazione-e-configurazione-di-wordpress-attraverso-wp-cli/" data-wpel-link="internal" target="_self" rel="noopener">tutorial</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.mrtux.it/installare-wordpress-vps-centos-7-vestacp/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
