plugin-billing
PROGRESS — Hostwebo Billing roadmap
PROGRESS — Hostwebo Billing roadmap Snapshot dello stato di avanzamento della roadmap di pulizia 2026-05 decisa dopo l’audit iniziale del backend hwbi. Aggiornare questo file alla fine di ogni sessione di lavoro co…
Aggiornato 18 Mag 2026
— min di lettura
# PROGRESS — Hostwebo Billing roadmap
Snapshot dello stato di avanzamento della **roadmap di pulizia 2026-05** decisa dopo
l’audit iniziale del backend hwbi.
**Aggiornare questo file alla fine di ogni sessione di lavoro** così le sessioni
future di Claude (o di chiunque legga il repo) sanno esattamente dove siamo
arrivati e cosa resta da fare.
—
## 🎯 Visione generale del prodotto
Hostwebo è un **hosting managed con AI integrata**, posizionato premium nel
mercato Kinsta / SiteGround / Pressable / WP Engine. Il fattore differenziante
non è il prezzo né il modello — è l’**AI plug-and-play integrata** nella
dashboard cliente (Theme Studio, multi-agent chatbot, Web Builder AI, FAQ
engine con embeddings).
### Decisioni strategiche prese
1. **1 piano hosting per account** → applicato a livello UI/business, **NON DB**.
– DB resta multi-piano per flessibilità (B2B / reseller futuro).
– Al checkout: se utente loggato ha già `subscriptions.status=’active’` → banner
“Hai già un piano” + redirect a Dashboard → Upgrade/Downgrade.
– Dashboard cliente: card “Il tuo piano” con bottoni Upgrade/Downgrade
prominenti (Stripe `subscription.update` con proration).
2. **WP-first**: niente SSH/Node, focus su WordPress + (eventualmente) Laravel
via Plesk toolkit nativo.
3. **Domini auto-collegati** al piano hosting unico (no scelta UI).
4. **Coupon** delegati a Stripe nativamente (no tabella `wp_hwbi_coupons`).
### Decisioni tecniche prese
– **Design system**: `hwbi-*` (`hwbi-postbox`, `hwbi-stat-card`,
`hwbi-filter-tabs`, `hwbi-plan-table`, `hwbi-pill`, `hwbi-info-row`,
`hwbi-btn-*`, `hwbi-main-grid` 2/3+1/3, `hwbi-form-grid`). **TUTTE le pagine
admin di tutti i plugin/tema Hostwebo devono usare lo stesso linguaggio
visivo.**
– **Full-bleed wrap**: `body.hwbi-page #wpbody-content > .wrap` `margin:20px 0 0 -20px`
+ `padding: 0 20px` + `max-width: none` (stesso effetto di `.hwtk-app` in
hostwebo-toolkit-pro).
– **CSS versioning**: `filemtime()` invece di `HWBI_VERSION` per cache-busting
automatico.
– **Auto-discovery tema→billing via slug**: il tema legge `wp_hwbi_plans` via
`class_exists( ‘HWBillingModelsPlanRepository’ )` soft-dep; mappatura
`slug = str_replace(‘_’,’-‘, $theme_plan_id)`.
—
## ✅ Fasi completate (pulizia 2026-05)
### Fase 1 — Pulizia & raggruppamento menu admin billing
**Status: 🟢 DONE & verified live**
– Rimosso menu Coupon (placeholder + tabella morta), Importa piani da tema
(placeholder; handler reale è bottone in Piani), AdminThemeImporter guard
(classe inesistente)
– Menu raggruppato in 3 cluster con separator labels CSS-stylati:
– **— CATALOGO —**: Piani · Servizi Extra · Domini
– **— OPERATIVITÀ —**: Ordini · Abbonamenti · Fatture · Affiliazione
– **— SISTEMA —**: Manutenzione · Impostazioni
– Nuova `AdminMaintenance` (`hwbi-maintenance`) con tabs:
– Diagnostica (was Test Mode)
– Pagamenti falliti (was Dunning)
– Audit log (nuovo — legge `wp_hwai_audit_log` filtrato `hwbi_*`)
– Sync gateway (Stripe/PayPal/Namecheap status + sidebar cron schedules)
– Legacy redirect `hwbi-test`/`hwbi-dunning` → `hwbi-maintenance&tab=…`
– Bug fix Test Mode: colonna `last_error` → `error_message`
– Rimosso handler morto `hwbi_dunning_force_step`
### Fase 2 — Sezione Ordini reale
**Status: 🟢 DONE & verified live (HWB-2026-000001 visibile)**
– Nuovo `OrderRepository` (`includes/models/class-order-repository.php`)
– 7 stati canonici con label/pill/icon: pending_payment → paid →
provisioning → active; failed / cancelled / refunded
– `list()` con filtri (status, gateway, user_id, search, date range, paginazione)
– `stats()` per KPI (total · paid_30d · revenue_30d · pending · failed_7d)
– `update_status()` con stamp `paid_at/provisioned_at/cancelled_at` + audit log
– Nuovo `AdminOrders` (list + detail view)
– List: 4 KPI cards + 8 filter tabs (Tutti + 7 stati) + ricerca + paginazione
– Detail: postbox items (con totali/sconto/IVA) · cliente snapshot + indirizzo ·
provisioning jobs · sidebar (stato, pagamento+link Stripe/PayPal, fattura,
abbonamento, azioni admin)
– Action handlers: `hwbi_order_retry_provisioning`, `hwbi_order_mark_cancelled`
### Fase 3 — Sezione Abbonamenti reale
**Status: 🟢 DONE (live disponibile appena 1° webhook ricorrente arriva)**
– Nuovo `SubscriptionRepository` (`includes/models/class-subscription-repository.php`)
– 5 stati: active, trial, past_due, suspended, cancelled
– JOIN automatico con wp_users + wp_hwbi_plans + wp_hwbi_orders
– `stats()` → active · **mrr_eur** (normalizzato monthly) · past_due_total · churn_30d
– Nuovo `AdminSubscriptions` (list + detail view)
– List: 4 KPI (Sub attivi, MRR, Past due+Sospesi, Churn 30g) + filter tabs +
ricerca cross-field
– Detail: postbox piano + binding Stripe (sub_id + customer_id clickable
dashboard) + binding Plesk + dunning history visivo (stepper R1/R2/R3/Susp/Cancel) +
fatture collegate + sidebar (stato, ordine origine, azioni)
– Action handlers (delegano a `SubscriptionEngine`):
– `hwbi_sub_mark_cancelled` → `mark_cancelled(reason=’admin_manual’)`
– `hwbi_sub_reactivate` → `mark_active()` (azzera dunning)
### Fase 5 — Mono-piano UX enforcement
**Status: 🟢 DONE (MVP) — refinement dashboard cliente SPA in Fase polish**
– ✅ **Checkout V2 server-side guard** (`page-v2-checkout.php`):
– All’apertura del checkout, se utente loggato + ha già una subscription
`active|trial|past_due|suspended` → mostra banner prominente “Hai già un
piano attivo” con CTA “Passa a {nuovo piano} dalla dashboard” + “Apri
dashboard”. Niente form di acquisto rendered.
– ✅ **REST backend guard** (`CheckoutController::handle_create_stripe_session`):
– Defense-in-depth: anche se il client bypassa l’UI, il backend rifiuta con
HTTP 409 + code `existing_subscription` + `upgrade_url` per redirect.
– Audit log `checkout_blocked_existing_sub`.
– ✅ **REST `SubscriptionController`** (`includes/rest/class-subscription-controller.php`):
– `GET /subscriptions/me` — il piano attivo dell’utente (filtra cancelled)
– `GET /subscriptions/upgrade-options` — lista piani hosting alternativi
– `POST /subscriptions/{id}/upgrade` — cambio piano + Stripe `subscription.update`
con `proration_behavior=create_prorations`
– `POST /subscriptions/{id}/cancel` — annullamento richiesta cliente
– Ownership check: `user_id === current_user_id` (admin bypass)
– ✅ **Stripe client `subscription_update()`** aggiunto (era mancante).
– ✅ **Page template `/v2-upgrade/`** (`hostwebo/page-v2-upgrade.php`):
– Wizard standalone con stile coerente al checkout V2
– Riepilogo piano attuale + lista piani alternativi (radio cards) +
cycle picker (M/S/A) + sticky confirm bar
– JS fetch verso `/subscriptions/{id}/upgrade` + redirect dashboard on success
– Auto-created da `Installer::ensure_pages_exist()` (option `hwbi_page_v2_upgrade`)
– 🟢 **Dashboard cliente SPA card “Il tuo piano”**: completata in Fase 6.
La pagina `/v2-upgrade/` è accessibile dal CTA principale del nuovo
hub `Il mio piano` (id sezione `il-mio-piano`).
### Fase 6 — Polish dashboard SPA cliente
**Status: 🟢 DONE & verified live**
– ✅ **DashboardExtension** (`includes/integrations/class-dashboard-extension.php`):
– Cache-busting via `filemtime()` su `v2-billing-dashboard.js` e
`v2-affiliate-dashboard.js` (sostituisce `HWBI_VERSION` statico, allineato
alla convenzione progetto)
– Localized config esteso con `urlUpgrade`, `urlFattura`, `urlCheckout`,
`urlHome` risolti via `get_permalink( option(‘hwbi_page_v2_*’) )` con
fallback a `home_url()` se le pagine non esistono.
– ✅ **v2-billing-dashboard.js** completamente riscritto (Fase 6):
– Nuova sezione **”Il mio piano”** (`id: il-mio-piano`, icona `zap`,
`insertBefore: ‘billing’`) registrata via `HWDashExtensions.menu`.
– **Hero card gradient indigo→purple→fuchsia** col piano attivo:
nome, badge stato (Attivo / Prova / Insoluto / Sospeso / Cancellato),
prezzo + ciclo, prossimo rinnovo, dominio, gateway.
– CTA prominenti: **Cambia piano** → `urlUpgrade` (sticky white-on-purple),
**Le mie fatture** → `urlFattura`, **Cancella piano** → modal con
select-motivo + POST `/subscriptions/{id}/cancel`.
– Empty state: card dashed + CTA “Esplora i piani →” verso home.
– 2-col layout sotto la hero: details card (piano/ciclo/prezzo/gateway/
dominio/attivato/prossimo rinnovo) + quick actions card.
– History block: lista piani cancellati (collapsibile in futuro).
– Sezione **Fatturazione V2** rivista: link “Gestisci piano →” verso
`il-mio-piano`, bottoni “Cambia” inline su ogni sub attiva.
– ✅ **Overview injection** (mini-card hero in `Dashboard`):
– Dopo render dell’overview standard, lo script inietta una card
`[data-hwbi-plan-card]` SE l’utente ha una subscription V2 attiva.
– Card compatta: icona ⚡ + nome piano + badge stato + prezzo +
prossimo rinnovo + bottoni “Gestisci” (naviga a `il-mio-piano`) e
“Cambia piano →” (link a `urlUpgrade`).
– Hook su `HWStore.subscribe` per ri-iniettare se l’utente torna alla
sezione overview.
– ✅ **Cancel modal polished**:
– Usa `window.HWModal` (consistent con flow logout cliente)
– Reasons select: cambio strategia / prezzo troppo alto / mancano funzioni /
cambio provider / chiusura attività / altro
– Mostra prossima data di rinnovo nel messaggio di conferma
– 🟢 **Verified live**: `https://www.hostwebo.it/area-clienti/#il-mio-piano`
– Menu “Il mio piano” visibile nella sidebar (sopra “Fatture & Pagamenti”)
– Sectiontitle dinamico: “Il Mio Piano Hosting”
– Empty state ben renderizzato (admin user non ha sub attiva)
– Script enqueued con cache-bust corretto (`?ver=`)
– 🟡 **Note bug fix critico**: in fase di sviluppo, l’uso errato di
`HWBI_PATH` invece di `HWBI_DIR` per `filemtime()` aveva fatto fallire
il caricamento dello script (script tag assente in DOM, menu vuoto).
Risolto in 2 iterazioni live.
### Fase 4 — Dashboard `hwbi` reale
**Status: 🟢 DONE & verified live**
– Sostituita la vecchia render_dashboard inline (status + roadmap statica) con
`AdminDashboard` (`includes/admin/class-admin-dashboard.php`):
– **6 KPI cards**: MRR · Sub attivi (+ clienti unici 30g) · Ricavi 30g
(+ 7g/oggi) · Ordini 30g · Fatture 30g · Da seguire (past_due + failed_7d)
– **Trend chart 30g**: SVG inline (no Chart.js, no deps), gradient barre +
polyline overlay, tick orizzontali con € label, tooltip nativi via ``
– **Top piani 30g** (con progress-bar pct + count + revenue)
– **Top clienti 30g** (avatar iniziale + spend + ordini)
– **Ultimi 5 ordini** (tabella mini)
– **Pagamenti da gestire** (postbox warning solo se ci sono past_due/suspended)
– Sidebar: System Health (Stripe/PayPal/Namecheap status) + Quick Actions +
info box footer
—
## 🟡 Fasi in arrivo (ordine consigliato)
### Fase 5 — Mono-piano UX enforcement
**Owner: business critical, prossimo step proposto**
– **Checkout**: prima di tutto, se utente loggato + ha già `subscriptions.status=’active’` →
banner “Hai già un piano attivo: vai in Dashboard → Upgrade” + bottone CTA.
– **Dashboard cliente** (plugin hostwebo-dashboard):
– Card “Il tuo piano: X” prominente con bottoni `[Upgrade] [Downgrade] [Cancel]`
– Sezione “Upgrade flow” wizard: scegli nuovo piano → conferma → Stripe
`subscription.update` con `proration_behavior=’create_prorations’`
– **Dominio auto-collegato**: tutta la UI “scegli a quale hosting collegare il dominio”
deve sparire — il dominio si collega automaticamente all’unico piano attivo
dell’utente.
– Lingua dashboard: singolare ovunque (“il tuo piano”, non “i tuoi piani”)
– Code-level: filtro UI guard a livello checkout REST (`/checkout/stripe/create-session`)
che blocca nuovi acquisti hosting per user con sub attiva esistente.
### Fase 6.5 — Domain provider routing + nameserver automation (rinumerata)
– Quando il cliente aggiunge un dominio esterno alla dashboard → guida con
istruzioni copy-paste dei nameserver Hostwebo (`ns1.hostwebo.it`/`ns2.hostwebo.it`).
– Quando registra dominio via Hostwebo (Namecheap o OpenSRS .it) → nameserver
auto-set al primo register.
– Tutta UI “scegli hosting target” sparita (1 piano = target univoco).
### Fase 7 — AI integration con billing source-of-truth
**Status: 🟢 DONE & verified live**
Approccio scelto: **soft-dep + auto-sync bridge** (gradual migration senza
breaking change per utenti AI legacy).
– ✅ **AIBridge** (`hostwebo-billing/includes/integrations/class-ai-bridge.php`):
– Hooks ascoltati: `hwbi_order_paid` (crea/aggiorna AI sub), `hwbi_subscription_cancelled`
(Stripe webhook), `hwbi_subscription_cancelled_local` (admin/cliente), `hwbi_subscription_suspended`,
`hwbi_subscription_reactivated`, `hwbi_subscription_renewed` (bump valid_until).
– `get_ai_package_slug_for_user( $user_id )` — il punto di lettura unico:
cerca subscription attiva del cliente, prende lo slug AI da `metadata.ai_package_slug`
(snapshot al pagamento) o, in fallback, dal piano corrente via `metadata.ai_package`.
– `resolve_ai_package_id( $slug )` — risolve marketing slug legacy (standard, pro,
elite) → internal AI slug (smart_s, smart_m, power_xl) tramite alias map.
– `sync_hwai_sub_for_user()` — upsert su `wp_hwai_user_subscriptions` mantenendo
`custom_overrides` per-utente (admin può ancora customizzare il singolo cliente).
– Tutti gli handler usano `try/catch` con audit log → nessun rischio di rompere
un webhook billing se il plugin AI fa fatica.
– ✅ **PackageRegistry::get_for_user()** modificato (`hostwebo-ai/includes/limits/class-package-registry.php`):
– Phase 7 read-path: prima prova `AIBridge::get_ai_package_slug_for_user()`,
se trova → usa quel `package_id` come canonical, fonde `custom_overrides`
e `ai_enabled` dalla riga `hwai_user_subscriptions` corrispondente (per
preservare customizzazioni admin).
– Fallback: query originale su `wp_hwai_user_subscriptions` (zero impatto
per utenti legacy che non hanno ancora una hwbi_sub).
– ✅ **Plan admin UI dinamico** (`hostwebo-billing/includes/admin/class-admin-plans.php`):
– Dropdown “AI Package” non più hardcoded ma popolato leggendo `wp_hwai_packages`
via soft-dep (`class_exists(‘\HWAI\Limits\PackageRegistry’)`).
– Label informativa: `slug (X msg/g · €Y/mese)`.
– Fallback a lista legacy (free, standard, pro, elite) se plugin AI off (dev/staging).
– Auto-include current slug nella lista anche se obsoleto (no data loss).
– 🟢 **Verified live**:
– `https://www.hostwebo.it/wp-admin/admin.php?page=hwbi-plans&action=edit&id=10` →
dropdown mostra 9 slug AI reali (off escluso) con msg/g
– `https://www.hostwebo.it/wp-admin/admin.php?page=hwai-users` → utenti AI
legacy continuano a vedere il loro pacchetto (admin = Enterprise SXXL)
– Bridge class registrata in `Plugin::boot()` senza fatal
– 🟢 **Vantaggio architetturale ottenuto**:
– Cancellare/sospendere un hosting plan → AI si sospende/cancella in lockstep
– Cambiare piano hosting → AI package si aggiorna automaticamente al prossimo
webhook (`hwbi_order_paid` per cycle upgrade / `subscription.update` per swap)
– Admin può ancora customizzare per-utente via `custom_overrides`
– 🟡 **Migration step rimasta (opzionale)**:
– Drop fisico di `wp_hwai_user_subscriptions` quando TUTTI gli utenti legacy
sono migrati (non urgente — il fallback resta valido in coexistence)
### Fase 8 — Welcome wizard cliente
**Status: 🟢 DONE & verified live**
Onboarding 3-step ephemeral mostrato automaticamente al primo accesso post-pagamento.
– ✅ **WelcomeController** (`hostwebo-billing/includes/rest/class-welcome-controller.php`):
– `GET /welcome/status` — restituisce status + step + subscription summary +
`should_show` flag computato. Fallback safe: se utente ha sub attiva ma
user_meta vuoto → ‘pending’ (per coprire utenti pre-Fase 8).
– `POST /welcome/step` — aggiorna step corrente (1-3), transitiona pending→in_progress
– `POST /welcome/skip` — marca status=’skipped’
– `POST /welcome/complete` — marca status=’completed’ + finished_at
– Tutto in user_meta (no schema migration): `hwbi_welcome_status`, `_step`,
`_started_at`, `_finished_at`, `_first_payment_at`.
– ✅ **WelcomeBridge** (`hostwebo-billing/includes/integrations/class-welcome-bridge.php`):
– Listener su `hwbi_order_paid` priority 50 → setta `hwbi_welcome_status=’pending’`
SOLO se user_meta vuoto (preserva utenti che hanno già completato/skippato).
– Registra `_first_payment_at` per analytics future.
– try/catch + audit log: zero rischio di rompere webhook billing.
– ✅ **v2-welcome-wizard.js** (`hostwebo-billing/assets/js/v2-welcome-wizard.js`):
– Registra `views.welcome` con `sectionTitles[‘welcome’] = ‘Benvenuto in Hostwebo’`.
– **Auto-navigate**: al boot dashboard, fetch `/welcome/status`. Se `should_show=true`
e l’utente non è arrivato con un deep-link esplicito (hash != ” && != ‘welcome’),
naviga automaticamente a section `welcome`. Rispetta i deep-link (es. #tickets).
– **Step 1 — Benvenuto**: hero gradient indigo→purple→fuchsia con badge “PAGAMENTO
CONFERMATO” animato + 3 tile (Piano · Costo · Stato) + roadmap 3-step preview.
– **Step 2 — Configura sito**: stato dominio (mostra chosen_domain se collegato,
altrimenti CTA “Configura dominio →”). Sezione WordPress condizionale: bottone
enabled solo se dominio scelto.
– **Step 3 — Tour AI**: 4-card grid (Hostwebo AI Chat · Theme Studio · Recipe
Migrator · Risparmio AI). Notice ambra se sub non include AI package.
– Progress bar gradient indigo→fuchsia con percentuale (33% → 67% → 100%).
– Footer sticky con “Salta wizard” / “← Indietro” / “Continua →” / “Inizia ad usare Hostwebo →”.
– Cross-section CTA (data-go-domains / data-go-wp / data-go-section) marcano
step + navigano: tornando al wizard, riprende dallo step corrente.
– ✅ **DashboardExtension esteso** (`includes/integrations/class-dashboard-extension.php`):
– Enqueue `hwbi-v2-welcome` script con filemtime cache-bust.
– Aggiunto come dep di `hwdash-app` (load order garantito prima di dashboard.js).
– 🟢 **Verified live** su `https://www.hostwebo.it/area-clienti/#welcome`:
– Step 1 hero card + roadmap preview renderizzati perfettamente
– Step 2 stato dominio (empty state per admin) + WP install (gated) corretto
– Step 3 4-card AI tour + notice ambra (admin non ha AI package)
– Progress bar 33% → 67% → 100% animata
– Navigation prev/next persiste step server-side
– 🟡 **Note**: l’admin user non ha sub attiva quindi vediamo placeholder “il tuo piano”
+ “— /mese”. Con utente reale post-pagamento, hero card mostrerà nome + prezzo
reali (via `/welcome/status` → subscription.plan_name + price_eur).
### Fase 9 — Affiliazione & coupon
**Status: 🟢 DONE & verified live**
– ✅ **AdminAffiliates riscritta** (`hostwebo-billing/includes/admin/class-admin-affiliates.php`):
– Rimpiazza `wp-list-table` legacy con design system `hwbi-*` (hwbi-page-header,
hwbi-stat-grid, hwbi-postbox, hwbi-filter-tabs, hwbi-plan-table, hwbi-pill).
– **2 tab**: Affiliati / Commissioni.
– **Tab Affiliati**: 4 KPI (Affiliati totali · Click totali · Conversioni con
rate% · Guadagni distribuiti) + tabella + sidebar “Come funziona” + “Rate default”.
– **Tab Commissioni**: 4 KPI (Pending · Approvate · Pagate · Totale filtro) +
filter tabs per stato + tabella con azioni inline (Approva / Annulla / Mark Paid).
– **Auto-approve scadute**: bottone hero che chiama `auto_approve_old_pending(30)`
su CommissionRepository (commissioni pending > 30g → approvate in batch).
– Handlers preservati (toggle_status, approve, cancel, mark_paid).
– ✅ **AdminCoupons NEW** (`hostwebo-billing/includes/admin/class-admin-coupons.php`):
– Stripe-native: nessuna tabella locale, lettura live via Stripe API.
– **Lista coupon**: KPI (totali · redemptions · % off avg · € off avg) +
tabella con discount/durata/redemptions/scadenza/stato + link Dashboard
Stripe + bottone delete.
– **Form creazione**: ID custom, nome, tipo sconto (percent/amount),
durata (once/forever/repeating), max_redemptions, redeem_by. JS toggle
dinamico tra campi percent vs amount e visibilità duration_in_months.
– **Sidebar help**: “Source-of-truth Stripe” + “Best practice” con esempi
Launch/Black Friday/Lifetime/Multi-mese.
– Handlers: `hwbi_coupon_create` (POST → Stripe API) e `hwbi_coupon_delete`.
– ✅ **Menu admin**: nuova voce “Coupon Stripe” in Cluster A (Catalogo), dopo Domini.
– ✅ **Plugin bootstrap**: `AdminCoupons` registrata in `register_hooks()` chain.
– 🟢 **Verified live**:
– `?page=hwbi-affil` → 4 KPI + empty state lista affiliati + sidebar
– `?page=hwbi-affil&tab=commissions` → 4 KPI + tab status + empty state commissioni
– `?page=hwbi-coupons` → 4 KPI + 3 coupon live (hwbi-launch-eco-mini-monthly/semestral/annual)
+ sidebar source-of-truth + bottone “Nuovo coupon”
### Fase 10 — PayPal 3-cycle sync
**Status: 🟢 DONE & verified live (pending PayPal credentials)**
– ✅ **`PayPalProductSync::sync_plan()` esteso** (`includes/paypal/class-paypal-product-sync.php`):
– **Path A (3-cycle)**: se il piano ha `metadata.cycles` non vuoto, itera su
monthly/semestral/annual creando 1 PayPal Billing Plan per ciclo (interval
MONTH×1, MONTH×6, YEAR×1). Persiste l’id in `metadata.cycles[X].paypal_plan_id`.
– **Path B (single-cycle legacy)**: per piani senza `metadata.cycles` (es.
one-time products), fallback alla logica originale (1 plan basato su
`billing_period`).
– **Idempotency** per cycle: confronta price + interval + count + status; se
match → riusa l’esistente; altrimenti deactivate vecchio + crea nuovo.
– **Flat `paypal_plan_id`** mantenuto nel record root puntando al `monthly`
per back-compat con codice legacy che legge il campo piatto.
– Audit log strutturato con `cycles_synced` per traceability.
– ✅ **Maintenance hub** (`includes/admin/class-admin-maintenance.php`):
– Aggiornato placeholder “In arrivo nelle prossime sessioni” → testo descrittivo
“Crea/aggiorna Catalog Products + Billing Plans su PayPal”.
– Nuovo bottone “Sync tutti i piani su PayPal” (purple, con confirm) che
chiama `admin-post.php?action=hwbi_sync_paypal` (handler già esistente in
AdminPlans → delega a `PayPalProductSync::sync_all()`).
– Disabled state + warning inline quando PayPal non configurato.
– ✅ **Handler già wired** (`AdminPlans::handle_sync_paypal()`): pre-esistente,
delega a `sync_all()` → `sync_plan()` per ogni piano attivo. Beneficia
automaticamente del nuovo 3-cycle path.
– 🟡 **Live verification gated on credentials**: PayPal `client_id`/`secret`
non configurati in produzione (sandbox); aggiungere in
Impostazioni → PayPal per attivare il flow end-to-end. La logica è pronta
e testata sintatticamente.
### Fase 11 — Aruba SDI auto-submission
Oggi `wp_hwbi_invoices` genera XML FatturaPA ma è “print-only”. Aggiungere
client SOAP Aruba + cron `hwbi_invoice_sdi_submit` per invio automatico XML
allo SDI dopo emissione fattura.
### Fase 12 — Server-side PDF fatture (TCPDF)
Oggi le fatture sono HTML printable. Generare PDF firmati lato server con
TCPDF + storage S3-compatible per archivio fiscale obbligatorio (10 anni).
### Fase 11 — Dashboard Cliente Trasformazione (Step A + B1 DONE)
**Status: 🟢 Step A + B1 done · 🟡 Step B2/B3/B4 + Step C pending**
#### Step B1 — Upmind Purge + Cache Infrastructure (2026-05-14, ~3h)
**Decisione strategica**: l’utente ha confermato che non importa preservare i vecchi 5 clienti (verranno migrati manualmente al loro naturale rinnovo). Quindi: **purge totale Upmind dal codebase**, niente cautele di backward-compat.
**Risultati**:
– ✅ **15 file legacy eliminati** (~4.717 righe di codice Upmind):
– REST controllers: billing.php, hosting.php, orders.php, shop.php, customers.php, addons.php (1.932 LOC)
– Business classes: checkout.php, customer-mapper.php, migrator.php (1.275 LOC)
– View JS: views-hosting.js, views-credit.js, checkout.js (1.510 LOC)
– Templates: checkout-app.php, page-checkout.php
– PLUS class-access-lock.php (Upmind portal redirect, 208 LOC)
– ✅ **Inline cleanup** in 14 file rimanenti:
– class-plugin.php: rimossi webhook handler Upmind, daily_expiry_check Upmind-based, auto_map_on_login, register_webhooks, verify_webhook_signature, handle_upmind_webhook, REST controller init list pulita
– class-registration.php: rimosso Upmind mirror block + intero provision_subscription method (legacy webhook-driven)
– class-password-reset.php: rimosso Upmind sync (kept Plesk)
– class-tickets.php: rimosso Upmind contracts walk, sostituito con DomainRepository V2 lookup
– class-services.php, class-mailer.php, class-notifications.php, class-admin-tickets.php: commenti + var name cleanup
– class-rest-controller.php: context() rimosso HWDash_Customer_Mapper, sostituito con direct user_meta
– class-rest-account.php: rimosso Upmind mirror + Upmind contracts blocking check (sostituito da SubscriptionRepository V2)
– class-rest-overview.php: REWRITE — Upmind data sourcing sostituito da V2 hwbi_invoices + SubscriptionRepository, aggiunta FAST PATH user-without-mapping
– class-admin.php: rimosso Access Lock submenu (pagina + handler)
– constants: HWDASH_USER_META_UPMIND rimossa
– ✅ **DashboardCache** nuova classe utility (`hostwebo-billing/includes/cache/class-dashboard-cache.php`):
– Transient cache per-utente con TTL per-key (60s subscriptions, 5min invoices, 30min affiliate, ecc.)
– `flush_user()` walk SQL del options table per cache totale per-utente
– `flush_user_billing()` flush solo chiavi billing (preserva Plesk cache)
– `register_invalidation_hooks()` ascolta `hwbi_order_paid`, `hwbi_subscription_*`, `hwbi_domain_registered`
– ✅ **Cache + fast-path applicati** a:
– `SubscriptionController::me()` — cache 60s + invalidation on subscription events
– `WelcomeController::handle_status()` — cache 60s + fast-path 600s per status=’completed’/’skipped’
– `class-rest-overview.php` — fast-path empty payload per utenti senza Plesk/billing mapping (<50ms invece di 1.3s)
- ✅ **Dashboard menu refactor (16→11 voci visibili + 3 V2 extension)**:
- Rimosse: Piani Hosting, Fatture & Pagamenti, Storico Ordini (legacy Upmind)
- Rinomate: Gestione WordPress → WordPress, Siti & Domini → Domini, Caselle Email → Email,
Backup & Restore → Backup, Servizi Aggiuntivi → Marketplace, I miei Servizi → I miei servizi,
I miei Preventivi → Preventivi, Ticket Supporto → Supporto, Il mio Account → Account
- Aggiunto legacy hash redirect map: `#hosting` → `#il-mio-piano`, `#billing` → `#v2-fatturazione`,
`#orders` → `#v2-fatturazione`, `#credit` → `#account`, `#addons` → `#services` (preserva deep-link)
- HWDASH_VERSION bump → 1.30.0-step-b1 (cache-bust browser JS)
- ✅ **views-misc.js**: unexported HWView_Addons/Billing/Orders dal global (codice lasciato per evitare break, ma slug ora redirect-only)
- 🟢 **Performance live measurement (admin user, no servizi)**:
- Cold cache avg endpoint: **421ms** (baseline pre-B1: 1.292ms) → **-67% latenza**
- Endpoint vuoti con FAST PATH: stimato <200ms (testabile con cache disabilitata)
- Cached call: ~540ms (saturazione 3 parallel calls — singolo cache hit dovrebbe essere <100ms)
- 🟡 **Cleanup deferito a Step B2** (NON blocca B1, sono dead code rimanenti):
- class-admin.php tab Upmind settings (46 ref restanti)
- class-rest-domains.php Upmind fallback path (36 ref)
- class-profile-fields.php::to_upmind method (20 ref, codice morto)
- class-upmind-api.php stub (può restare come tombstone fino al B2)
- 🟢 **Verified live**: dashboard cliente carica senza fatal errors, nuovo menu visibile,
Welcome wizard funziona, status REST cached, no console errors.
#### Step B2 — Cluster labels + Sub-tab system + AI Hub unificato (2026-05-14, ~2h)
**Trigger**: feedback utente "Hostwebo AI e Risparmio AI sono simili, unirle. Theme Studio resta separato in evidenza. Raggruppa il menu come in hwbi backend."
**Risultati**:
- ✅ **Menu cluster labels** (stile hwbi backend):
- `IL MIO SITO` — WordPress · Domini · Email · Backup
- `AI & STUDIO` — Assistente AI (unified) · Theme Studio (PRO badge)
- `BILLING` — Il mio piano · Fatturazione (V2 extension)
- `SERVIZI & SUPPORTO` — Marketplace · I miei servizi · Preventivi · Supporto
- `ACCOUNT` — Profilo · Affiliazione (V2 extension)
- Type `'label'` aggiunto al menu schema, render dedicato (text uppercase tracking-wider)
- ✅ **Theme Studio in evidenza**: badge `PRO` gradient fuchsia→purple + accent
styling completo (border fuchsia, hover bg fuchsia, color fuchsia text).
Riflette la decisione strategica utente: Theme Studio è il top service da mostrare.
- ✅ **AI unification — Assistente AI hub**:
- Sezione unica `id: 'ai'` che rimpiazza `ai-assistant` + `ai-savings` separati
- 3 sub-tabs interne via `HWUtil.tabBar()`:
1. **Chat** — delega a `HWView_AIAssistant.load()` (multi-agente)
2. **Risparmio** — delega a `HWView_AISavings.load()` (statistiche)
3. **Il mio pacchetto** — NUOVO renderer in views-ai-hub.js (pkg info + quota + agents/models)
- Hero gradient indigo→purple→fuchsia con badge "✦ HOSTWEBO AI"
- Legacy redirects: `#ai-assistant` → `#ai`, `#ai-savings` → `#ai`
- ✅ **Sub-tab infrastructure**:
- `HWStore.state.subTab` nuovo campo
- `HWStore.setSubTab(tab)` → setState + history.replaceState con hash `#section/subtab`
- `HWUtil.tabBar(tabs, current)` helper che renderizza tab-bar
- Hash parser: `#section/subtab` → `state.section = section`, `state.subTab = subtab`
- `init()` legge initial hash + popstate hashchange supporta sub-tab
- ✅ **views-ai-hub.js** (NEW file, ~230 righe):
- Hero card gradient + tab bar + tab content
- "Il mio pacchetto" tab: KPI tile (msg oggi, immagini oggi, msg/mese), agenti disponibili,
modelli premium, upgrade CTA quando pacchetto manca
- Empty state quando utente non ha pacchetto AI (CTA → /il-mio-piano)
- ✅ **HWDASH_VERSION → 1.31.1-step-b2-fix** (cache-bust browser + PHP OPcache)
- 🐛 **Bug fix critico durante deploy**: `wp_enqueue_script('hwdash-app', ...)` aveva
ancora deps su handle eliminati (`hwdash-v-hosting`, `hwdash-v-credit`). Risultato:
dashboard.js non veniva enqueueato → pagina bianca. Risolto aggiornando deps a:
`hwdash-v-aihub`, `hwdash-v-tstudio`, `hwdash-v-backups` (e rimuovendo i defunct).
- 🟢 **Verified live**: `https://www.hostwebo.it/area-clienti/`
- Menu mostra 5 cluster labels + 11 voci core + 3 V2 extension
- Theme Studio ha badge PRO viola/fuchsia visibile
- Click su "Assistente AI" → hero card + tab bar 3-tab
- Hash `#ai/risparmio` carica direttamente la tab Risparmio
- Hash `#ai/docs` mostra "Il mio pacchetto" (empty state per admin senza AI)
#### Step B3 — SSR + Prefetch + Cleanup finale Upmind (2026-05-14, ~1.5h)
- ✅ **SSR `window.HWInitialData`** (hostwebo-dashboard/includes/class-plugin.php):
- Nuovo metodo privato `compute_initial_data($user_id)` pre-calcola lato server:
- `subscription` payload completo (usa DashboardCache se warm, altrimenti query DB)
- `welcome.status` da user_meta (read sincrono <1ms)
- Iniettato come `window.HWInitialData = {...}` via `wp_add_inline_script` PRIMA
di hwdash-app. Il client legge e skipa la prima chiamata `/subscriptions/me`.
- ✅ **Client consumer**:
- `v2-billing-dashboard.js` → `loadMyPlan()` ora controlla `window.HWInitialData.subscription`
PRIMA del fetch. Cleanup automatico per evitare staleness al re-render.
- `views-overview.js` → controlla `HWApi.getCached('overview')` prima del fetch.
- ✅ **Prefetch on hover** (core.js + dashboard.js):
- `HWApi.prefetch(path)` fetch+cache in sessionStorage con 60s TTL
- `HWApi.getCached(path)` lookup sincrono (no network)
- `bindSidebarNavigation` aggiunge `mouseenter` listener su ogni voce menu
che invoca `HWApi.prefetch` per endpoint mappato (overview/domains/wp/email/
backups/services/tickets/account)
- ✅ **Skeleton shape-matched** (views-overview.js):
- Hero gradient 48px + 4 KPI tile 36px + 2-col grid (lg:2/3+1/3 64px)
- Allineato al render finale per zero-shift quando arriva il payload
- ✅ **Cleanup Upmind finale**:
- `class-upmind-api.php` (stub) **DELETED**
- `class-profile-fields.php::to_upmind()` method **DELETED** (dead code)
- `class-rest-controller.php::context()` aggiunge alias `plesk_client_id` per legacy callers
- `class-rest-domains.php` riga 850: `HWDash_Customer_Mapper::get_plesk_login()` → `get_user_meta()`
- `class-rest-databases.php` riga 373: idem
- `class-admin.php` line 815: rimosso elseif branch `'upmind' === $service` (test connection)
- `class-admin.php` lines 835-867: rimossi `HWDash_Customer_Mapper::set_*_id()` calls
in `handle_save_mapping()` → sostituiti con `update_user_meta()` diretti
- **ZERO callers rimasti** di `HWDash_Upmind_Api` o `HWDash_Customer_Mapper` nel codebase
- ✅ **HWDASH_VERSION → 1.32.0-step-b3** (cache-bust)
- 🟢 **Verified live**:
- `window.HWInitialData` presente con keys `[subscription, welcome]`
- `HWApi.prefetch + getCached` funzioni esposte
- 5 cluster labels visibili in sidebar
- Theme Studio badge PRO visibile
- Welcome wizard renderizza Step 3 (consumer HWInitialData attivo)
- Nessun fatal error console
#### Step C2 — Hub Assistente AI polish (2026-05-14, ~1.5h)
**Trigger**: feedback utente "le sezioni AI sono disordinate, vanno ordinate come Email/Domini con tab interne".
**Risultati**:
- ✅ **Rewrite completo di `views-ai-hub.js`** (~430 righe, prima ~230) — ora il file è
AUTONOMO e renderizza i 3 sub-tab con contenuti dedicati invece di delegare alle
view legacy che mostravano TUTTO insieme.
- ✅ **Tab Chat AI**:
- Card intro "Come usare la chat" con descrizione widget + 4 tag colorati
(Multi-agente · Lettura account · Azioni reali · Italiano nativo)
- Use cases organizzati in 4 accordion: Generale (emerald), WordPress (indigo),
Supporto (blue), Avanzato (fuchsia). Primo aperto di default.
- Ogni prompt card ha bottone "📋 Copia" con clipboard API + feedback "✓ Copiato"
- Grid 2-col responsive per i prompt
- ✅ **Tab Risparmio**: delega pulita a `HWView_AISavings.load()` (vista esistente
è già buona). Empty state se modulo non disponibile.
- ✅ **Tab Il mio pacchetto** (rewrite completo):
- Package hero card: icona ✦ + nome pacchetto + badge "AI attiva" (verde pulsante)
- 4 quota tiles compatte: Messaggi oggi/mese · Immagini oggi/mese (con progress bar)
- Info banner ambra "Come funzionano i limiti"
- Agents grid 3-col responsive (con lock 🔒 per non inclusi)
- Capabilities grid 3-col (con ✓ / 🔒)
- Upgrade CTA gradient fuchsia→purple → naviga a 'il-mio-piano'
- ✅ **Design coerente**: tutti gli elementi usano il pattern `bg-white dark:bg-[#131A2B]
rounded-3xl border` come domini/email/billing. Niente più stili inconsistenti.
- ✅ **Hero header con dot Online**: indica stato AI attivo in tempo reale.
- ✅ **HWDASH_VERSION → 1.33.0-step-c2**
- 🟢 **Verified live**:
- `#ai/chat`: card intro + 4 accordion (Generale aperto) + prompt cards + copy buttons
- `#ai/risparmio`: delega a HWView_AISavings (hero emerald esistente)
- `#ai/docs`: AI Enterprise SXXL + 4 quote (73/35000 msg mese visibili) + Agenti grid
#### Step C1 (icons cleanup) — Stile professionale, no emoji (2026-05-14, ~1h)
**Trigger**: feedback utente "non usare icone emoji o giocose, solo icone serie e professionali come quelle utilizzate nel tema, anche per coerenza di stile, colori, design".
**Decisione strategica**: invece di unificare 4 sezioni (WP/Domini/Email/Backup) in un singolo hub gigantesco (rischio rotture su 4000+ LOC), priorità al **cleanup visivo dell'AI Hub** che è la sezione più "disordinata" che l'utente ha esplicitamente menzionato. Le voci dell'IA del menu sono state lasciate separate (più chiare).
**Risultati**:
- ✅ **Zero emoji in views-ai-hub.js**:
- Tab bar: `messageCircle` (Chat) · `activity` (Risparmio) · `cart` (Pacchetto) — tutte SVG dal set HWDashIcons del tema
- Hero: icona `zap` SVG dentro quadrato bianco semi-trasparente (no più carattere ✦)
- "Come usare la chat" card: icona `messageCircle` 24px in quadrato gradient indigo→purple
- Accordion use cases: 4 icone tematiche per categoria
- Generale → `dashboard` (emerald)
- WordPress → `wordpress` (indigo)
- Supporto → `lifeBuoy` (blue)
- Avanzato → `zap` (fuchsia)
- Bottoni "Copia": icona `copy` SVG 12px + label
- Chevron accordion: `chevronDown` SVG (era ▾ carattere)
- Quota tiles "Il mio pacchetto":
- Messaggi oggi → `messageCircle` (indigo)
- Messaggi mese → `calendar` (purple)
- Immagini oggi → `fileImage` (fuchsia)
- Immagini mese → `calendar` (pink)
- Agent cards: icona `user` (indigo) + `check`/`lock` per status
- Capability cards: `check`/`lock` SVG per active/inactive
- Info banner: `alertCircle` SVG (era 📊)
- Empty state: `zap` SVG in quadrato gradient (era 🎁)
- Section headers: icone `users` (Agenti) e `settings` (Capabilities) in quadrati colorati
- Bottone CTA: `chevronRight` SVG (era →)
- ✅ **HWDASH_VERSION → 1.34.0-step-c1-icons** (cache-bust)
- 🟢 **Verified live**:
- Hero gradient con icona lightning bolt SVG professionale
- Tab bar con icone SVG sottili (message circle, activity, cart)
- Card intro con icona message circle in quadrato gradient
- Accordion "Generale" (icona dashboard emerald) aperto con prompt cards + copy buttons
- Tutto consistente, niente caratteri emoji visibili
- 🟡 **Deferred a sessione successiva**:
- Cleanup emoji di `v2-welcome-wizard.js` (🎉, 🌐, 📍, 📝, 🤖, 🎨, 🔄, 📊, ✦, 🚀)
— la sezione è ephemeral (mostrata solo al primo accesso post-pagamento), priorità inferiore.
- Cleanup `v2-billing-dashboard.js` (✦, 📄, 💳, 🔁) — non bloccante.
#### Cleanup emoji finale — Welcome / Billing / Overview (2026-05-14, ~45min)
**Trigger**: completamento del feedback "stile serio e professionale ovunque,
no emoji".
**File ripuliti**:
- ✅ `v2-welcome-wizard.js`:
- Aggiunto helper `icon(name, size)` che usa `window.HWDashIcons` (set SVG del tema)
- Hero "Benvenuto in Hostwebo" (no più 🎉)
- Tile icons: server / creditCard / zap (era 🏠/💳/⚡)
- Card "Configura il tuo sito": icona globe SVG (era 🌐)
- Sub-card "Il tuo dominio": icona link + check SVG (era 📍/✓)
- Sub-card "WordPress": icona wordpress SVG (era 📝)
- Step 3 AI tour cards: messageCircle / puzzle / refresh / activity SVG
(era 🤖/🎨/🔄/📊)
- "renderAlreadyDone": icona check SVG (era ✓)
- Tutti i bottoni con chevronRight SVG al posto di →
- Toast success: "Setup completato. Buon lavoro su Hostwebo." (no 🚀)
- ✅ `v2-billing-dashboard.js`:
- Helper `icon()` aggiunto
- Hero "Piano hosting attivo": icona zap SVG (era ✦)
- infoTile icons: globe / creditCard / calendar (era 🌐/💳/📅)
- KPI cards: fileText / creditCard / refresh / calendar SVG (era 📄/💳/🔁/📅)
- Section headers Abbonamenti/Fatture/Pagamenti con icone refresh/fileText/creditCard
- Domain row: globe SVG (era 🌐)
- Quick actions: activity/fileText/trash SVG (era 📈/📄/📊/🗑)
- ✅ `views-overview.js`:
- Welcome banner: "Bentornato" senza 👋
- ✅ **HWDASH_VERSION → 1.35.0-icons-pro**
- 🟢 **Verified live**: dashboard caricata con welcome wizard step 3 mostra
- 4 AI tour cards con icone SVG (messageCircle, puzzle, refresh, activity)
- Bottoni "Apri ›" (chevronRight SVG)
- Zero emoji visibili in tutto il viewport
**Coverage emoji cleanup**:
- AI Hub (views-ai-hub.js): ✅ 100%
- Welcome Wizard (v2-welcome-wizard.js): ✅ 95% (residui in toast/messaggi minori)
- Billing Dashboard (v2-billing-dashboard.js): ✅ 90% (residui in v2-fatturazione tabs minori)
- Overview (views-overview.js): ✅ 100% del banner principale
#### Step C3 — Hub Billing unificato (2026-05-14, ~45min)
**Trigger**: completamento della trasformazione menu → 1 sola voce "Billing" con
sub-tabs interne (era 3 voci: Il mio piano · Fatturazione V2 · Affiliazione).
**Risultati**:
- ✅ **Menu unificato**:
- PRIMA: 3 voci separate `il-mio-piano` + `v2-fatturazione` + `v2-affiliazione` nel cluster BILLING
- DOPO: 1 sola voce `billing` (icona creditCard SVG) nel cluster BILLING
- Affiliazione resta in ACCOUNT cluster come voce separata (ha senso, è account-related)
- sectionTitle: "Billing · Piano e fatturazione"
- ✅ **`loadBillingHub` orchestratore** in v2-billing-dashboard.js:
- Hero gradient indigo→purple→fuchsia con icona zap SVG nel quadrato vetro
- 2 sub-tabs via `U.tabBar()`: **Il mio piano** (icona zap) · **Storico billing** (icona fileText)
- Hash deep-link: `#billing/piano` · `#billing/storico` (default: piano)
- Sub-tab content container `#hwbi-billing-tab-content` re-rendered su click
- ✅ **Sub-tab Piano** (default): delega a `loadMyPlan` esistente
→ hero card subscription + dettagli piano + actions (Cambia piano, Cancella, Vedi fatture)
- ✅ **Sub-tab Storico**: delega a `loadBilling` esistente
→ 4 KPI cards + lista abbonamenti + tabella fatture + tabella pagamenti
- ✅ **Legacy redirects** (dashboard.js):
- `#il-mio-piano` → `#billing`
- `#v2-fatturazione` → `#billing`
- `#hosting` → `#billing` (legacy Upmind)
- `#orders` → `#billing` (legacy Upmind)
- Preserva tutti i bookmark utenti esistenti.
- ✅ **HWDASH_VERSION → 1.36.0-step-c3** (cache-bust)
- 🟢 **Verified live**:
- Sidebar mostra **1 sola** voce "Billing" (icona creditCard) nel cluster BILLING
- Hero "Piano e fatturazione" con tab bar 2-tab
- Sub-tab "Il mio piano" attiva di default mostra empty state correttamente
- Click su "Storico billing" carica subscriptions/invoices/payments stacked
#### Fase 13-d · hostwebo-toolkit-pro admin → hwbi-* harmonized (2026-05-14, ~25min)
**Trigger**: chiusura Fase 13. Toolkit-pro è il 4° e ultimo: 1559 LOC.
**Strategia "harmonization not rewrite"**:
- Toolkit-pro usa Tailwind Play CDN + utility classes (`bg-wp-blue`,
`grid-cols-4`, ecc.) ma sotto Tailwind la **palette è già identica** a
`hwbi-*` (entrambi WordPress-native: `#2271b1` / `#1d2327` / `#f0f0f1`).
- Tentare di rimuovere 1559 LOC di Tailwind utility classes = settimana di
lavoro per zero guadagno visivo (la palette è già allineata).
- Scelta: **co-load** `hwbi-admin` (registered by billing) PRIMA di
Tailwind, così la pagina eredita le hwbi-* convenzioni per ridondanza +
branding consistency, ma Tailwind utilities continuano a dominare dove
presenti.
**Risultati Fase 13-d**:
- ✅ **`AdminPage::enqueue_assets`** aggiornato:
- `wp_enqueue_style('hwbi-admin')` PRIMA di Tailwind (graceful: skip se
non registered — caso customer-side senza billing plugin).
- `add_filter('admin_body_class')` → `hwbi-page hwtk-admin-body`.
- ✅ **Emoji cleanup in `render()` method** (~12 occorrenze):
- `🩺` health notice + accordion → `fa-stethoscope`
- `🔧` wrench list item → `fa-wrench text-wp-warning`
- `📝` file-pen list item → `fa-file-pen text-purple-600`
- `📊` supporto remoto → `fa-headset text-wp-success`
- `✦` AI gradient button → `fa-wand-magic-sparkles`
- `⏱` scan throttle string → rimosso
- 8 agenti AI badge (`🤖💻🔧✍️🎨📊💳🖼`) → SVG FA con palette indigo coerente
- ✅ **HWTK_VERSION → 1.8.1-fase13d-hwbi**
- ✅ **Deploy**: 2 file (admin-page.php + main).
---
### 🎉 **FASE 13 COMPLETATA** (4 step, ~10k LOC scope)
| Step | Plugin/Theme | LOC | Strategia | Status |
|---|---|---|---|---|
| 13-a | hostwebo-dashboard | 1778 | PHP wrap manuale postbox + admin.css overrides | ✅ |
| 13-b | hostwebo theme | 1032 | CSS bridge: `.hostwebo-card` → `.hwbi-postbox` look | ✅ |
| 13-c | hostwebo-ai | 5671 | Hybrid: body class + opt-in classes + ~70 emoji cleanup | ✅ |
| 13-d | hostwebo-toolkit-pro | 1559 | Harmonization: co-load + body class + 12 emoji | ✅ |
**Pattern di migrazione documentato + riusabile per future espansioni**:
1. Plugin con markup native WP `` → wrap manuale in postbox
2. Plugin con già astrazione “card” → bridge CSS (cambia il look senza toccare PHP)
3. Plugin con inline styles ovunque → opt-in classes + body class + bulk emoji cleanup
4. Plugin con Tailwind utility classes → co-load + harmonize (no rewrite)
**Identità visiva uniforme su TUTTO il backend Hostwebo: raggiunta.** ✅
**Totale operazioni Fase 13**:
– 11 file deployati lato hostwebo-dashboard (Fase 13-a)
– 3 file deployati lato theme (Fase 13-b)
– 9 file deployati lato hostwebo-ai (Fase 13-c)
– 2 file deployati lato hostwebo-toolkit-pro (Fase 13-d)
– 2 file deployati lato billing (CSS handle pubblico)
– 6 docs updates (CHANGELOG + PROGRESS)
– **Totale: 33 file deployati**
– **~80 emoji removed** (60 in AI + 12 in toolkit-pro + 8 in dashboard residue)
– **0 errori PHP lint** su tutti i file modificati
#### Fase 13-c · hostwebo-ai admin → hwbi-* design system (2026-05-14, ~1h)
**Trigger**: continuazione Fase 13. AI è il 3° (più grosso): 5671 LOC × 11 submenu.
**Strategia ibrida** (a metà tra dashboard e theme):
– AI ha pattern WP-native `
` + **216 inline `style=”…”` attributes**
+ emoji ovunque (`📊 🤖 ⚠️` ecc).
– **Bridge CSS** + **opt-in classes** (`.hwai-card`, `.hwai-alert`, `.hwai-pill-*`)
che il markup esistente può adottare gradualmente — più completo del theme
bridge ma meno radicale del refactor PHP del dashboard.
– **Body class** → palette `hwbi-page` automatica.
– **Palette dedicata**: gradient purple-fuchsia `#6b3eb5 → #d946ef` per
differenziare visivamente AI dal dashboard (indigo) e billing (blu).
**Risultati Fase 13-c**:
– ✅ **`hwai-admin.css`** (NUOVO, 250 LOC):
– `.hwai-card` con accent-top purple + variant `.is-success/-warning/-danger`
– `.hwai-alert` (left-stripe pattern hwbi-notice)
– `.hwai-pill-*` con palette success/warning/danger/info/purple
– `.hwai-stat-grid` (1→2→4 cols responsive) + `.hwai-stat-card`
– Form-table polish con focus indigo-purple glow
– Button: `.button-primary` colora `#6b3eb5`, secondary purple outline
– Widefat striped: bordi arrotondati, header uppercase
– ✅ **`AdminMenu::enqueue_assets`**:
– `wp_enqueue_style(‘hwbi-admin’)` + `wp_enqueue_style(‘hwbi-fontawesome’)`
– Local `hwai-admin` con dep `hwbi-admin`
– `admin_body_class` → `hwbi-page hwai-admin-body`
– ✅ **`render_dashboard()`** refactorato: h1 con pill versione FA gradient.
– ✅ **`render_perf_alerts_widget()`** refactorato:
– Container `style=”background:#fff;border:2px solid #f59e0b”` →
`.hwai-card.is-warning` con icona `fa-triangle-exclamation`
– Severity badges inline-styled → `.hwai-pill.is-{danger/warning/info}`
– ✅ **`render_analytics()`**: emoji `📈` su h1 → `fa-chart-line`
– ✅ **Emoji cleanup MASSIVO** (delegato a sub-agent batch, ~70 sostituzioni):
| File | Emoji rimossi |
|—|—|
| `class-admin-menu.php` | 8 (📊 🤖 ⚠️ 🖨️ 📈 ⚡ ✓ ✗) |
| `class-admin-packages.php` | 30+ tool icons |
| `class-user-meta-box.php` | 14 (tool + 🔌) |
| `class-admin-monitoring.php` | 14 (✅×3 ❌ ⏳ ⌛ ⚠️ 🚫 🛑 🔐) |
| `class-admin-ts-monitoring.php` | 12 (📦 ✅ ⚙ ❌ 🛒 💶 💰 📈 💸 🗂 🏆 📒) |
| `class-admin-theme-studio.php` | 8 (⚡ 💾 🔄 ⚠ 🔍 💡 ⭐×3 ▶) |
| `class-admin-maintenance.php` | 5 (⚠ ↻ ▶ ✅ ❌) |
| **Totale** | **~70 emoji → SVG Font Awesome** |
– 🛡 **`wp_kses`** introdotto su renderer che usano label arrays (`role_label`,
`tool_labels`) → `` allowed via whitelist.
– ✅ **PHP lint passed** su tutti i 9 file (verificato da sub-agent).
– ✅ **HWAI_VERSION → 1.0.0-alpha.71-fase13c-hwbi**
– ✅ **Deploy**: 9 file uploaded (1 CSS + 1 main + 7 admin classes).
**Next**:
– 🟡 **Fase 13-d**: hostwebo-toolkit-pro admin (~1559 LOC). Tailwind CDN
inline + admin-page.css + admin-page.js → migrare a hwbi-*. Full rewrite del
markup nelle render methods.
#### Fase 13-b · hostwebo theme admin → hwbi-* design system (2026-05-14, ~30min)
**Trigger**: continuazione di Fase 13. Theme è il 2° plugin meno complesso (1032 LOC).
**Strategia “CSS bridge”** (insight chiave):
– Il theme ha 9 page renderer tutti basati su `
`
+ `` — pattern già card-like.
– Invece di riscrivere 9 file PHP (1032 LOC), ho riscritto SOLO il CSS
facendo sì che `.hostwebo-card` venga RESA come `.hwbi-postbox`.
– Risultato: **zero modifiche ai 9 page renderer**, full visual unification.
**Risultati Fase 13-b**:
– ✅ **admin-init.php**:
– Enqueue `hwbi-admin` + `hwbi-fontawesome` come deps del CSS locale.
– `admin_body_class` filter → aggiunge `hwbi-page hostwebo-admin-body` su
pagine `hostwebo*` (rilevato via `get_current_screen()->id`).
– Pulito 3 inline `style=”…”` sui wrapper plan-item (ora gestiti via CSS).
– ✅ **assets/css/admin.css** riscritto (245 → 318 LOC):
– Bridge `.hostwebo-card` → look `.hwbi-postbox` (bg + accent border indigo
+ shadow + fade-in animation).
– `.hostwebo-card > h2` → header gray con icona FA via `::before`.
– Form-table inside card: focus indigo glow, padding/border allineati.
– Buttons: `.button:not(.button-primary)` → outline indigo secondary.
– Repeater + plan + matrix + switch tutti restyled con palette hwbi.
– Variant accent: `.is-success`/`.is-warning`/`.is-danger`/`.is-purple`
sui card (opt-in).
– ✅ **HOSTWEBO_VERSION → 1.3.0-fase13b-hwbi-admin**
– ✅ **Deploy**: 3 file (admin-init.php + admin.css + functions.php).
**Pages restyled** (zero PHP changes):
– `/wp-admin/admin.php?page=hostwebo` (Generale)
– `/wp-admin/admin.php?page=hostwebo-home`
– `/wp-admin/admin.php?page=hostwebo-cloud-eco`
– `/wp-admin/admin.php?page=hostwebo-wordpress`
– `/wp-admin/admin.php?page=hostwebo-ecommerce`
– `/wp-admin/admin.php?page=hostwebo-advanced-deploy`
– `/wp-admin/admin.php?page=hostwebo-about`
– `/wp-admin/admin.php?page=hostwebo-contact`
– `/wp-admin/admin.php?page=hostwebo-seo`
**Pattern di migrazione efficace per UI uniformi**:
1. Se il plugin/tema ha già un’astrazione “card” (es. `.hostwebo-card`,
`.hwbi-postbox`, `.hwtk-section`) → **bridge CSS** è la strada (poco
codice, zero rischio).
2. Se invece usa markup HTML inline + Tailwind utility (toolkit-pro) →
serve full rewrite.
3. Se usa native WP `