Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/corsivo-suite/forms/archive/refs/heads/master.zipLa pagina Attività e impostazioni usa il workspace Corsivo: Attività occupa tutta la larghezza; Configurazione raccoglie Generali e Integrazioni nella navigazione laterale. Gli URL tab=activity, tab=settings e tab=integrations restano validi. Le modifiche non salvate attivano l'avviso del browser quando si lascia il form.
Gli asset assets/admin-workspace.css, admin-workspace-layout.css e admin-workspace.js sono inclusi nel plugin: nessun altro plugin è necessario per la navigazione. Il primo file è la copia del foundation admin-workspace/style.css del package wp-admin-ui; gli adattamenti locali sono separati. Le schermate PHP non richiedono di ricompilare il bundle DataViews. Il test node tests/workspace-navigation.cjs <percorso-al-modulo-jsdom> verifica navigazione, conservazione dei campi, validazione e avviso modifiche.
Moduli di contatto nativi Gutenberg per la suite Corsivo: form composti a blocchi nell'editor, submission REST con anti-abuso a più livelli, upload privati, archivio richieste in bacheca e registro attività idempotente.
Scopo
Fornire ai siti della suite un form builder senza CPT dedicati, shortcode o pannelli di costruzione: il form è contenuto Gutenberg a tutti gli effetti, componibile e traducibile come il resto della pagina. Il plugin garantisce che ogni submission sia validata server-side, non duplicabile, archiviata in modo verificabile e notificata con esito tracciato, mantenendo al minimo i dati personali persistiti. Destinatari: sviluppatori e redazioni che gestiscono siti Corsivo con esigenze di contatto e consenso GDPR documentato.
Come funziona
Definizione
Il blocco corsivo/form (registrato in PHP tramite Define Blocks, dipendenza obbligatoria) contiene come inner block i campi, il pulsante corsivo/form-submit e alcuni blocchi core di layout. Le impostazioni — titolo, destinatari, oggetto, messaggio di conferma, flag archivio — vivono negli attributi del blocco: non esiste un post type per i form. L'identità è form_id, un SHA-256 stabile della definizione normalizzata (impostazioni + campi + flag strutturali). Ogni campo ha una chiave (field_key, derivata dall'etichetta se vuota) usata nei merge delle notifiche.
| Blocco | Tipo | Note |
|---|---|---|
corsivo/form-text |
testo | field_key sender_name alimenta il Reply-To |
corsivo/form-email |
indicizzato per gli strumenti privacy | |
corsivo/form-tel |
telefono | |
corsivo/form-textarea |
testo lungo | max 5000 caratteri |
corsivo/form-select |
scelta | opzioni deduplicate, valore verificato server-side |
corsivo/form-number |
numero | valori finiti, minimo, massimo e incremento configurabili |
corsivo/form-date |
data | calendario ISO YYYY-MM-DD, minimo e massimo inclusivi |
corsivo/form-radio |
scelta singola | gruppo accessibile con fieldset e legend; opzioni verificate server-side |
corsivo/form-file |
file singolo o multiplo | archivio obbligatorio; formati, quantità e dimensione configurabili |
corsivo/form-checkbox |
spunta | accetta solo valore esplicito |
corsivo/form-privacy |
consenso | sempre obbligatorio, con link all'informativa |
Condizioni dei campi
Nell’inspector ogni campo, salvo il consenso privacy, può avere fino a 10 condizioni, combinate con all (tutte, default) oppure any (almeno una). La sorgente si indica attraverso la chiave canonica del campo: per collegare campi assegna una field_key esplicita, stabile e univoca. La posizione dei blocchi non determina l’ordine di valutazione delle dipendenze.
Gli operatori sono equal, not_equal, contains, not_contains, is_empty, is_not_empty, greater, greater_or_equal, less e less_or_equal. I confronti ordinati sono disponibili per numeri e date; quelli di contenimento per campi testuali e scelte. File e privacy non possono essere sorgenti di condizioni. Riferimenti mancanti, riferimenti a sé stessi e cicli rendono invalida la configurazione; una sorgente nascosta non può attivare i campi dipendenti, nemmeno con is_empty o not_equal.
Il frontend disabilita i controlli nascosti e li esclude da FormData, validazione ed errori. Il server risolve autonomamente gli stessi vincoli: ignora valori e upload dei campi noti ma nascosti, anche se inviati manualmente, e li esclude da archivio, notifiche, Reply-To e action delle integrazioni. I file associati a chiavi sconosciute restano rifiutati. Il consenso privacy resta sempre visibile e obbligatorio. Valori numerici non finiti, date inesistenti e opzioni estranee alla configurazione non sono sorgenti valide.
Le condizioni vuote e i nuovi attributi ai valori predefiniti non alterano la definizione normalizzata dei form precedenti: identità e token già emessi restano compatibili finché non cambia la configurazione effettiva.
Token
I destinatari impostati nei blocchi devono appartenere all'elenco Destinatari autorizzati nelle impostazioni generali. L'indirizzo amministrativo del sito è sempre ammesso; gli altri indirizzi, anche di form già esistenti, vanno aggiunti esplicitamente. Il filtro PHP corsivo_forms_allowed_recipients può estendere l'elenco da codice fidato. La possibilità di modificare una pagina non consente quindi di usare il sito per inviare notifiche a destinatari arbitrari.
Al render la definizione completa — impostazioni, campi con evidenza della privacy policy (URL, ID, hash SHA-256 del contenuto, data di modifica), pagina, lingua, modalità sorgente — viene cifrata in un token AES-256-GCM con chiave derivata dai salt di WordPress e contesto network/blog: destinatari e impostazioni di notifica restano nel token cifrato. Le definizioni dei campi e le condizioni sono esposte al client per la gestione dell’interfaccia; il server le rivaluta dalla definizione autenticata. La sorgente viene classificata (post; template con catena di hash di template, template part e blocchi riutilizzabili; rendered come fallback) e il TTL è 1 giorno per rendered, 90 giorni per post/template (filtro corsivo_forms_form_token_ttl). Questo consente il form anche in template FSE, template part, pattern sincronizzati e Query Loop. A ogni submit la sorgente viene riverificata: se il post non contiene più quel form, la catena template ha hash diversi o l'informativa privacy è cambiata, il token è revocato (form_changed, privacy_policy_changed); cambiare la lingua della pagina lo invalida (form_language_changed).
Render
Il markup include honeypot (corsivo_forms_hp), feedback aria-live e un avviso "JavaScript necessario": il pulsante resta type="button" finché lo script frontend non lo attiva, quindi non esiste un percorso di invio senza JS. Un campo file espone accept, multiple e la descrizione accessibile dei limiti, ma questi attributi sono solo UX: il contratto viene sempre applicato dal server. Se la configurazione è invalida il form viene reso disabilitato con l'errore esplicito: destinatari malformati, select obbligatoria o radio senza opzioni, condizioni o regole di notifica invalide, campo privacy senza informativa pubblicata, oltre 50 campi, struttura troppo profonda, submit mancante, OpenSSL assente, campo file senza formati, archivio disattivato in presenza di file o storage privato non attestabile.
Submit
Lo script invia multipart/form-data a POST /wp-json/corsivo/v1/forms/submit costruendo FormData dal form e aggiungendo token, request_id (UUID generato dal client, conservato quando l'esito di rete è ignoto) e formId; non imposta manualmente Content-Type, così il browser genera il boundary. I campi ordinari restano scalari, mentre i file singoli e multipli arrivano tramite i file params della REST request. Pipeline server, nell'ordine:
- limite body 27 MB per multipart e 2 MB per gli altri payload, applicato su
rest_pre_dispatch, e limite cumulativo dei file di 25 MB; - controllo same-origin:
Sec-Fetch-Site: cross-siterifiutato, headerOriginnormalizzato e confrontato conhome_url; - fingerprint SHA-256 dei parametri normalizzati e dell'identità di ogni file (
field, nome originale, errore PHP, byte e SHA-256 del contenuto), esclusi token, honeypot erequest_id; replay lookup surequest_id: risposta già salvata restituita senza rieseguire nulla, mentre la stessa chiave con contenuto o form diverso produce 409request_id_conflict; - pre-limit e honeypot;
- decodifica del token e riverifica di pubblicità della pagina, lingua, sorgente ed evidenza policy;
- validazione server-side dei campi e preparazione dei file; gli errori consumano un budget dedicato e non toccano quello degli invii validi;
- rate limit submission e claim idempotente sul registro attività (chiave unica
request_id); - archiviazione (se attiva), notifica, action
corsivo_forms_submission, aggiornamento del record e persistenza della risposta per i replay futuri.
Un claim rimasto processing oltre il timeout (5 minuti, filtro corsivo_forms_processing_timeout) viene marcato unknown e reso ritentabile con esito esplicito; il replay di una risposta persa funziona anche a token scaduto.
I limiti per client raggruppano gli IPv6 nella stessa rete /64 e usano una finestra a scadenza fissa sotto lock. Prima di archiviare gli upload viene consumato anche un budget condiviso di 250 MiB per 24 ore, configurabile con corsivo_forms_daily_upload_budget: cambiare IP o riutilizzare un token valido non elude questo limite. Dietro proxy fidati, l'integrazione server deve risolvere l'indirizzo tramite corsivo_forms_client_ip; gli header inoltrati non vengono considerati affidabili automaticamente.
Dopo una modifica dell'informativa, le pagine in cache devono essere rigenerate: un token riferito alla vecchia policy continua correttamente a produrre privacy_policy_changed. Dopo una migrazione, lo storage privato deve essere nuovamente verificabile prima di cancellare file; percorsi senza attestazione non vengono adottati automaticamente.
Archiviazione
Se il flag archivio è attivo la richiesta diventa un post del CPT privato corsivo_submission: tutte le capability mappate su manage_options, create_posts negato, niente REST né ricerca frontend. La scrittura è draft → verifica di ogni meta → publish: se un meta non risulta scritto, il post parziale viene eliminato con compensazione verificata (post e meta orfani inclusi) e la submission fallisce in modo pulito. Ogni campo email è indicizzato in _corsivo_forms_email_index; i consensi sono salvati con l'evidenza congelata nel token (evidence_hash, data di accettazione, riferimenti alla policy).
File privati
Il blocco corsivo/form-file può essere obbligatorio, singolo o multiplo. L’inspector configura l’allowlist delle estensioni, il numero massimo per campo (1–10; un campo singolo forza 1) e la dimensione massima per file (1–20 MB, default 5 MB); i default sono PDF, JPG/JPEG e PNG. Il registry server ammette esclusivamente pdf, jpg, jpeg, png, doc, docx, xls, xlsx, csv, txt, odt e ods: valori esterni al registry vengono eliminati durante la normalizzazione e un’allowlist vuota rende il form indisponibile.
Ogni upload viene verificato per errore PHP, presenza e leggibilità del temporaneo, assenza di symlink, dimensione dichiarata/reale, estensione, risultato di wp_check_filetype_and_ext() e MIME rilevato dal contenuto. Immagini, documenti ZIP-based e file testuali hanno controlli aggiuntivi: decodifica immagine, struttura DOCX/XLSX/ODF e rifiuto di contenuti eseguibili o markup attivo. Se MIME detection, ZipArchive quando necessario, hashing o qualunque controllo di integrità non sono disponibili, il file viene rifiutato; non si usa mai il MIME dichiarato dal browser come fonte di verità.
I file non entrano nella Media Library e non hanno URL pubblico. Lo storage predefinito è corsivo-forms-private/<hash-installazione> fuori dal webroot più esterno rilevato; può essere sostituito definendo CORSIVO_FORMS_PRIVATE_DIR con un percorso assoluto esterno a tutti i webroot prima del caricamento del plugin. La struttura è sites/<blog_id>/submissions/<submission_id>/: root, sito e richiesta sono attestati da marker plain deterministici. Percorsi relativi, root del filesystem, directory interne o antenate dei webroot, symlink, marker mancanti/diversi e directory con elementi inattesi vengono rifiutati senza tentare adozioni o cancellazioni.
I file vengono validati e preparati, poi spostati con nome casuale <upload_id>.<estensione> e permessi 0640 nella directory della submission draft. Dimensione e SHA-256 sono riverificati dopo lo spostamento; _corsivo_forms_uploads conserva in chiaro id, campo, nome originale, nome storage, estensione, MIME, byte, SHA-256 e timestamp GMT. Marker e metadati persistenti non dipendono dai salt WordPress, quindi una rotazione dei salt non li rende illeggibili. Qualunque errore elimina in compensazione file, directory e post parziale; un form con file richiede sempre l’archiviazione e non invia notifiche se la richiesta non è stata archiviata integralmente.
Nel dettaglio amministrativo gli allegati sono scaricabili soltanto tramite admin-post.php da utenti con manage_options e nonce legato a submission e upload. Prima dello stream vengono ricontrollati metadati, directory attestata, contenimento del path, dimensione e SHA-256; la risposta forza attachment, nosniff, sandbox CSP, no-cache e noindex. Le email e i merge tag contengono soltanto i nomi originali: nessun binario, allegato email, URL pubblico o link amministrativo viene inviato.
Il ciclo di vita dei file coincide con quello della submission. Eliminazione definitiva, retention ed eraser privacy rimuovono prima i file e bloccano l’eliminazione del post se lo storage non può essere ripulito; l’exporter include nome, MIME e dimensione, non il contenuto. Con delete_data_on_uninstall=false submission e file restano; con opt-in l’uninstall multisite elimina per sito soltanto directory e file riconosciuti dai marker, fermandosi fail-closed su elementi estranei. Una root personalizzata resta condivisa ma isolata per blog_id.
Notifiche
Destinatari dalla configurazione (max 10, deduplicati case-insensitive; vuoto = email amministratore), oggetto con merge {chiave}, Reply-To composto da campo email e campo sender_name. Il trasporto preferito è Corsivo Mail (provider template corsivo_forms_form, merge tag tra cui {{fields_html}}, {{field_chiave}} e {{field_chiave_url}}), con fallback per destinatario a wp_mail() HTML. L'esito è registrato per submission: accepted, partial, failed, pending. I valori nei merge sono sanitizzati contro header/attribute injection e protocolli pericolosi anche offuscati con entità HTML; per i campi file il valore è la sola lista dei nomi originali.
Le regole di notifica del blocco form (notification_rules, massimo 10) usano le stesse condizioni e modalità all/any dei campi. La prima regola corrispondente sostituisce destinatari e oggetto della notifica standard; in assenza di corrispondenze resta la configurazione standard. Le regole hanno destinatari statici, verificati contro l’allowlist corrente anche dopo l’emissione del token: nessun valore inserito nel form può diventare un destinatario. Le risposte dei campi nascosti non attivano regole. L’esito della notifica e il replay idempotente conservano il contratto esistente.
Attività, retention e cron
La tabella wp_corsivo_forms_activity (InnoDB, request_id UNIQUE) registra gli eventi submission, integration, deleted, deleted_permanently, erased, retention_cleanup, activity_clear, settings_updated con soli identificativi, stati, codici errore e timestamp GMT. I messaggi vengono redatti (email → [email], percorsi → [path], eccezioni → classe + fingerprint HMAC): mai IP, valori dei campi, body email o destinatari. Il cron giornaliero corsivo_forms_daily_cleanup applica la retention alle attività, elimina le submission parziali più vecchie di un'ora e quelle scadute — sul timestamp canonico di invio, non sulla data del post — a batch da 250 con cursore; corsivo_forms_cleanup_batch prosegue le code lunghe e corsivo_forms_activity_schema_verify è il one-shot di verifica fisica dello storage.
La tab Attività usa @corsivo-suite/wp-admin-dataviews 0.1.0 compilato nel plugin. La collection autenticata GET /wp-json/corsivo/v1/forms/activity espone soltanto il DTO amministrativo necessario, applica manage_options e delega ricerca, filtri e paginazione alle query PHP esistenti. La pulizia non passa dalla REST API: resta l'handler admin-post con nonce e conserva i claim tecnici recenti.
Storage
Lo schema della tabella attività è current-only: installazione fresh-only a due fasi sotto lock MySQL, con verifica fisica di colonne, indici ed engine InnoDB. Una tabella completa conforme al blueprint viene riattestata anche se contiene righe; namespace inattesi, struttura incoerente o stato non verificabile mantengono il plugin fail-closed, con route submit a 503 e notice amministrativa.
Punti rilevanti
- Anti-spam a più livelli senza CAPTCHA: honeypot, same-origin, pre-limit (60 richieste/5 min), budget errori di validazione separato (30/15 min per form) e budget invii validi (10/15 min per form). Chi sbaglia non consuma il budget degli utenti legittimi; il replay di una risposta già salvata non consuma nulla.
- Pseudonimizzazione dei rate limit: gli scope sono
HMAC(IP | bucket)con salt di WordPress, quindi le chiavi di throttling non contengono IP in chiaro e non sono ricollegabili senza la chiave del sito. L'IP èREMOTE_ADDR; dietro proxy o CDN va valorizzato con il filtrocorsivo_forms_client_ip, fidandosi degli header inoltrati solo da proxy noti. - Idempotenza end-to-end:
request_idclient + fingerprint del contenuto + chiave unica + risposta persistita = stessa richiesta, stessa risposta, una sola submission, un solo set di file e una sola notifica; un payload diverso con la stessa chiave viene rifiutato anche se cambia soltanto il contenuto binario. - Fail-closed: configurazione invalida → form disabilitato con motivo; activity storage o upload storage non verificati → submit indisponibile; OpenSSL assente → nessun token; mismatch di tipo, hash, marker, path o cleanup → operazione interrotta. Nessun percorso degrada in silenzio.
- Minimizzazione: il registro attività non duplica dati inseriti; le submission esistono solo se l'archivio è attivo; l'evidenza consenso è hash e riferimento, non copia dell'informativa; per gli upload restano soltanto file privato e metadati necessari a integrità, amministrazione e privacy.
- Retention e strumenti privacy WP: attività 1–3650 giorni (default 90; a registro disattivato restano per un giorno solo gli eventi amministrativi di disattivazione/pulizia e i claim tecnici di idempotenza), richieste 0–3650 giorni (0 = nessuna scadenza). Exporter ed eraser WordPress indicizzano tutte le email, esportano evidenze e metadati file, eliminano submission e file a lotti da 100 con cursore e segnalano gli elementi non eliminabili senza proseguire in modo distruttivo.
- Confini dichiarati: nessun invio senza JavaScript. La route REST è pubblica by design (riceve richieste anonime): le difese sono tutte server-side. Gli upload sono limitati al registry interno, non passano dalla Media Library e non vengono mai esposti o spediti per email. Alla disinstallazione i dati vengono conservati salvo opt-in esplicito.
Integrazioni con la suite
- Define Blocks — unica dipendenza obbligatoria (
Requires Plugins: define-blocks): registra blocchi e controlli editor dallo schema PHP. - Corsivo Mail — opzionale e disattivabile dalla tab Integrazioni: Forms registra il provider
corsivo_forms_formvia filtrocorsivo_mail_core_emailse consegna concorsivo_mail_deliver(); senza template disponibile usawp_mail()senza coinvolgere la coda globale. - Corsivo Privacy — opzionale e disattivabile: il campo consenso usa la pagina policy da
corsivo_privacy_get_pages_state()con risoluzione della lingua corrente; in assenza vale la privacy policy nativa di WordPress (wp_page_for_privacy_policy). - Corsivo Newsletter — ascolta l'action
corsivo_forms_submission($submission, $clean, $submission_id): se la submission contiene un campo spuntato con chiavenewslettere un'email mittente, iscrive il contatto con evidenza di consenso. Forms non carica né conosce codice Newsletter; un'eccezione nell'integrazione viene isolata e registrata senza far fallire la submission. - WPML —
wpml-config.xmlespone alla traduzione label, placeholder, opzioni, valori attesi nelle condizioni, oggetti delle notifiche, messaggio di conferma e testi del campo privacy; le chiavi dei campi restano non traducibili e i valori attesi per select/radio vanno tradotti insieme alle rispettive opzioni;corsivo_submissionnon è traducibile. La lingua della submission è risolta per pagina (wpml_post_language_details) e registrata nella richiesta. - Filtri per l'estensione:
corsivo_forms_form_definition,corsivo_forms_allow_post,corsivo_forms_is_public_render_context,corsivo_forms_submission_language, più i filtri di rate limit (corsivo_forms_rate_limit/_window, variantivalidationepreflight) e TTL citati sopra.
Test
npm run test:php esegue le regressioni isolate; il test delle query privacy richiede l'estensione PHP SQLite3 e usa soltanto un database in memoria. Le submission nel cestino restano incluse nell'export privacy e nella retention finché non vengono eliminate definitivamente.
cd wp-content/plugins/corsivo-forms
npm --prefix admin-app ci
npm run check
npm run package
wp eval-file wp-content/plugins/corsivo-forms/tests/run.php
wp eval-file wp-content/plugins/corsivo-forms/tests/extension-wordpress.php
wp eval-file wp-content/plugins/corsivo-forms/tests/admin-dataviews-wordpress.php
run.php (stile TAP, exit code 1 in presenza di fallimenti) copre: normalizzazione di impostazioni e campi, validazione, ciclo di vita del token, destinatari e merge anti-injection, redazione del registro, claim/replay/conflitti/claim interrotti, storage submission con compensazione, retention, exporter/eraser, cicli di blocchi riutilizzabili e un E2E REST con i tre budget di rate limit. I casi upload verificano schema/render del blocco, multipart singolo e multiplo, allowlist estensione/MIME e contenuto, limiti per file/campo/request, fingerprint binario e conflitto idempotente, storage fuori webroot con marker plain, metadati e hash, compensazione, download autorizzato, privacy/retention e uninstall multisite fail-closed. Il runner ripristina hook, post, file e directory temporanee, opzioni e chiavi di throttling create.
storage-static.php (PHP diretto, senza WordPress) fa guardie statiche sul contratto storage current-only: vieta dbDelta e ALTER TABLE, richiede installazione a due fasi con lock e verifica fisica dello schema.
npm run check esegue lint JavaScript, regressioni JavaScript e PHP isolate, quindi la build amministrativa. extension-regressions.php verifica nuovi tipi, grafo delle condizioni, instradamento e compatibilità delle definizioni; le fixture condivise verificano la coerenza tra valutazione PHP e frontend. extension-wordpress.php esercita le estensioni nel runtime WordPress con notifiche simulate e ripristino delle fixture.
npm run package crea lo ZIP con un’allowlist esplicita: include asset pubblici, build amministrativa, PHP, configurazione WPML e documentazione; esclude dipendenze di sviluppo, sorgenti amministrativi e suite di test. Le verifiche WordPress vanno eseguite dalla root del sito usando i percorsi mostrati sopra; i comandi npm dalla root del plugin.
Configurazione
Menu principale Richieste (posizione 30), con archivio delle richieste e pagina Attività e impostazioni: tab Attività (DataViews con ricerca, filtri, paginazione e pulizia manuale che conserva i claim in elaborazione), Impostazioni e Integrazioni. La pagina usa admin.php?page=corsivo-forms-settings; i vecchi collegamenti da tools.php vengono reindirizzati conservando tab, filtri e notifiche. Il menu funziona senza altri plugin Corsivo. Opzione unica corsivo_forms_settings:
| Chiave | Default | Note |
|---|---|---|
log_enabled |
true |
registro attività |
log_retention_days |
90 |
1–3650 |
submission_retention_days |
0 |
0–3650, 0 = nessuna scadenza |
delete_data_on_uninstall |
false |
elimina richieste, attività, tabella e impostazioni alla disinstallazione |
corsivo_mail_enabled |
true |
usa Corsivo Mail se disponibile |
corsivo_privacy_enabled |
true |
usa la policy di Corsivo Privacy se disponibile |
Limiti fissi rilevanti: body multipart 27 MB, massimo 25 MB di file e 10 file complessivi per request, massimo configurabile di 10 file per campo e 20 MB per file, 50 campi per form, 10 destinatari, 10 condizioni per campo o regola e 10 regole di notifica, testo 500 caratteri (textarea 5000), token max ~48 KB. I payload non multipart restano limitati a 2 MB. upload_max_filesize, post_max_size e altri limiti PHP/server possono ridurre questi valori. Il testo suggerito per la privacy policy del sito (wp_add_privacy_policy_content) riflette retention e presenza dei file. Requisiti: WordPress 6.6+, PHP 8.1+, estensione OpenSSL, Define Blocks attivo; ZipArchive è necessario per accettare DOCX, XLSX, ODT e ODS. Multisito supportato (attivazione, cleanup e uninstall per sito). Distribuito dal canale privato plugins.corsivo.dev tramite Corsivo Updater; licenza GPL-2.0-or-later (vedi LICENSE).
CORSIVO_FORMS_PRIVATE_DIR non è un’opzione amministrativa: se definita, deve contenere una directory assoluta dedicata e fuori dai webroot. Il plugin non sposta automaticamente i file quando cambia il percorso; la configurazione deve quindi essere stabilita prima dell’uso dei campi file.
Bootstrap, lifecycle, sicurezza e build
Il bootstrap corsivo-forms.php carica anche includes/uploads.php e registra l’attivazione; Define Blocks resta la dipendenza obbligatoria. init registra blocchi e CPT submission, rest_api_init espone il submit anonimo e la collection attività riservata a manage_options, plugins_loaded/admin_init verificano l’activity storage e il render di un form file attesta lazy lo storage privato. L’attivazione crea la tabella attività per ogni sito; la disattivazione rimuove i cron ma conserva submission e file. uninstall.php cancella dati e storage privato soltanto con l’opt-in. Gli altri ingressi sono render callback, admin-post per pulizia e download file, privacy exporter/eraser e cron; non esistono AJAX o CLI. admin-app/ compila DataViews e WP Admin UI nel bundle distribuibile, senza dipendenze runtime dal plugin showcase. React 18.3.1 e React DOM 18.3.1 sono dipendenze esclusivamente di sviluppo per risolvere i peer del package; la build li lascia esterni e usa gli handle React/Element registrati da WordPress a runtime. La route pubblica usa token cifrato, same-origin, honeypot, rate limit, fingerprint e idempotenza; download, collection e mutazioni amministrative usano capability e nonce WordPress. Limiti: niente CAPTCHA, invio senza JavaScript, form multipagina o form CPT; storage current-only senza percorsi legacy o migrazioni implicite.
Inventario completo dei file
Ogni percorso è relativo alla root del plugin. admin-app/node_modules/ resta locale e non entra nella release; il bundle contiene le dipendenze JavaScript necessarie, mentre non sono presenti vendor/ o libs/tcpdf/.
README.md— contratto operativo corrente di blocchi form, token, submit, storage, privacy, test e inventario..gitignore— esclude gli archivi ZIP e le dipendenze npm locali dell’app admin.admin-app/— sorgenti JavaScript, manifest/lock npm e build distribuibile della tab Attività DataViews.assets/corsivo-forms.css— stile pubblico di form, input file, descrizioni, honeypot, feedback e stati disabled/error.assets/corsivo-forms.js— abilita il submit, generarequest_id, inviaFormDatamultipart e gestisce errori/replay UI.changelog.txt— storia delle release e dei contratti Corsivo Forms.corsivo-forms.php— header, costanti, require, activation multisite e bootstrap dei moduli.includes/activity-storage.php— DDL tabella activity, inventory fisico, marker/intent, lock e verifica current-only.includes/activity.php— claim idempotenti, response envelope, redazione, query/purge e handler clear del registro.includes/blocks.php— schema Define Blocks, render form/campi, traversal di reusable/template e registrazione asset.includes/conditions.php— normalizzazione, validazione del grafo, visibilità dei campi e selezione delle notifiche condizionali.includes/editor.php— categoria blocchi, estensione inspector Define Blocks e CSS della preview editor.includes/fields.php— registry degli undici tipi di campo, schema, render accessibile, limiti e validazione server-side.includes/mail.php— provider Corsivo Mail, merge sicuri, destinatari/Reply-To e fallbackwp_mail()per recipient.includes/privacy.php— exporter/eraser, metadati upload, policy text, retention coordinata di submission/file e cron cleanup a batch.includes/settings.php— option unica, tab amministrative, enqueue della build e collection REST dell’attività.includes/submissions.php— CPT privato, scrittura compensata di meta/file, indice email e download dal dettaglio admin.includes/submit.php— route anonima multipart, body/origin guard, fingerprint di parametri/file, replay, token, rate limit, archive/mail e response persistita.includes/token.php— normalizzazione definizione, evidenza policy, source chain e token AES-256-GCM con revoca.includes/uploads.php— registry estensioni/MIME, parsing multipart, validazione contenuto, storage privato attestato, metadati, compensazione, download, privacy e cleanup/uninstall multisite.LICENSE— testo della licenza GPL-2.0-or-later.package.json— pipeline di lint, test, build e allowlist del pacchetto distribuibile.tests/extension-regressions.php— regressioni isolate sui nuovi tipi, condizioni, notifiche e definizioni precedenti.tests/privacy-regressions.php— query reali di export e retention su SQLite in memoria, comprese le richieste nel cestino, i cursori e l'isolamento per indirizzo email.tests/conditions-fixtures.json— casi condivisi per la valutazione delle condizioni PHP e JavaScript.tests/extension-wordpress.php— regressioni nel runtime WordPress con invii simulati e pulizia delle fixture.tests/run.php— suite TAP WordPress su token, validazione, submit E2E, upload multipart/storage/download, idempotenza, mail, retention e privacy.tests/storage-static.php— guardia PHP diretta sul blueprint, installazione fresh-only, lock e verifica fisica.tests/admin-dataviews-static.php— guardia su versioni package, capability, handler di pulizia e completezza degli asset admin.tests/admin-dataviews-wordpress.php— smoke nel runtime reale su collection REST, header di paginazione e asset accodati.uninstall.php— cleanup multisite opt-in di cron, submission, file privati attestati, activity, option e tabella posseduta.wpml-config.xml— configura la traduzione degli attributi testuali dei blocchi form/campi.