[{"data":1,"prerenderedAt":932},["ShallowReactive",2],{"meta-profile":3,"command-palette-about":18,"meta-contacts":403,"project-b2b-quote-builder":421},{"id":4,"extension":5,"logo_name":6,"meta":7,"name":8,"roles":9,"stem":16,"__hash__":17},"profile/meta/profile.yml","yml","giovanni-manara",{},"Giovanni Manara",[10,11,12,13,14,15],"Full Stack Developer","WordPress Developer","Frontend Developer","GSAP Enthusiast","Tennis Lover","Gamer Appassionato","meta/profile","3BmX-xwCGwakpBF7rjsHDYIpXj8I89zWKoP32P9_MxE",[19,44,63,81,100,122,144,187,220,247,300,326,378],{"id":20,"title":21,"body":22,"description":28,"extension":36,"meta":37,"navigation":38,"order":39,"path":40,"seo":41,"stem":42,"__hash__":43},"about/competencies/ai-nel-workflow.md","ai-nel-workflow",{"type":23,"value":24,"toc":32},"minimark",[25,29],[26,27,28],"p",{},"Uso quotidianamente strumenti come Claude Code e Cursor, ma con regole precise: la spec e il piano vengono prima del codice, ogni modifica passa da una review, e ogni repository ha le sue convenzioni scritte che anche gli agenti devono rispettare. L'AI accelera l'esecuzione; le decisioni — architettura, priorità, cosa entra in produzione — restano mie.",[26,30,31],{},"Quando ho voluto imparare React sul serio, ho ribaltato i ruoli: sul mio progetto personale l'AI poteva solo fare da reviewer, mai scrivere. Ogni riga l'ho scritta io. Saper usare bene questi strumenti significa anche sapere quando spegnerli.",{"title":33,"searchDepth":34,"depth":34,"links":35},"",2,[],"md",{},true,4,"/competencies/ai-nel-workflow",{"title":21,"description":28},"competencies/ai-nel-workflow","TX_bURb05LSO0o517DTADGBpxuILgJN3MNd2uxE6qZw",{"id":45,"title":46,"body":47,"description":51,"extension":36,"meta":57,"navigation":38,"order":58,"path":59,"seo":60,"stem":61,"__hash__":62},"about/competencies/code-quality.md","code-quality",{"type":23,"value":48,"toc":55},[49,52],[26,50,51],{},"Mi piace scrivere codice pulito e mantenere codebase leggibili e facili da manutenere — sia su personalizzazioni WordPress (temi/plugin) sia su progetti custom.",[26,53,54],{},"La qualità, per me, non è un dettaglio estetico: è logica, ordine e attenzione ai dettagli, così che un progetto prenda forma passo dopo passo e regga in produzione.",{"title":33,"searchDepth":34,"depth":34,"links":56},[],{},3,"/competencies/code-quality",{"title":46,"description":51},"competencies/code-quality","WVyPz6M7BXq1MiXLLc4nXEwS_MEpymEmdCSifEoF1Ms",{"id":64,"title":65,"body":66,"description":70,"extension":36,"meta":76,"navigation":38,"order":34,"path":77,"seo":78,"stem":79,"__hash__":80},"about/competencies/collaboration.md","collaboration",{"type":23,"value":67,"toc":74},[68,71],[26,69,70],{},"Ho fatto sport a diversi livelli fin da giovane, e questo mi ha lasciato una cosa utilissima nel lavoro: saper stare in squadra, comunicare in modo chiaro e contribuire senza \"rumore\".",[26,72,73],{},"Su progetti reali e codebase già in produzione, collaborare significa allinearsi sul problema, condividere contesto e consegnare in modo affidabile — non solo scrivere codice in isolamento.",{"title":33,"searchDepth":34,"depth":34,"links":75},[],{},"/competencies/collaboration",{"title":65,"description":70},"competencies/collaboration","CiCBh3JZXfzxe54qjCmGI8FdUVPskd571f84dOpak3U",{"id":82,"title":83,"body":84,"description":88,"extension":36,"meta":94,"navigation":38,"order":95,"path":96,"seo":97,"stem":98,"__hash__":99},"about/competencies/problem-solving.md","problem-solving",{"type":23,"value":85,"toc":92},[86,89],[26,87,88],{},"Quando qualcosa non torna, vado a fondo: studio, provo, documento e arrivo alla soluzione con costanza.",[26,90,91],{},"Nel lavoro quotidiano applico lo stesso approccio: capire il problema, scomporlo in parti gestibili, e farlo funzionare davvero — senza scorciatoie che poi costano in produzione.",{"title":33,"searchDepth":34,"depth":34,"links":93},[],{},1,"/competencies/problem-solving",{"title":83,"description":88},"competencies/problem-solving","_y34cpLrt3OqbL7_xHC_feokuoDThzESXsqrDOfmULo",{"id":101,"title":102,"body":103,"description":107,"extension":36,"meta":117,"navigation":38,"order":95,"path":118,"seo":119,"stem":120,"__hash__":121},"about/experiences/megiston.md","megiston",{"type":23,"value":104,"toc":115},[105,108],[26,106,107],{},"Dal 2022 lavoro come sviluppatore web, con un focus pratico su progetti reali e codebase già in produzione.",[26,109,110,114],{},[111,112,113],"strong",{},"2025 - oggi | Megiston S.r.l."," — Full stack web developer in un team piccolo, dove si tocca un po' di tutto. Mi sono occupato del frontend di una piattaforma di biglietteria online (Nuxt su API REST, interfacce costruite da Figma con Tailwind, carrello e pagamenti online), di personalizzazioni WordPress profonde — plugin custom per preventivi multi-step, dati strutturati JSON-LD, integrazioni con booking engine, ecc. — e attualmente del backend del nuovo sito aziendale con Payload CMS.",{"title":33,"searchDepth":34,"depth":34,"links":116},[],{},"/experiences/megiston",{"title":102,"description":107},"experiences/megiston","30UBT7QbA9xQo9Vrb9OritBBGpQLwd_4g3epIiFz3LQ",{"id":123,"title":124,"body":125,"description":138,"extension":36,"meta":139,"navigation":38,"order":34,"path":140,"seo":141,"stem":142,"__hash__":143},"about/experiences/websonica.md","websonica",{"type":23,"value":126,"toc":136},[127,133],[26,128,129,132],{},[111,130,131],{},"2022 - 2025 | Websonica S.r.l."," — Prima come stage web developer (2022-2023), poi come junior web developer (2023-2025). Ho lavorato su gestione e personalizzazione di siti WordPress e Magento2, su software custom in Laravel e Next.js, e su CRM come vTiger.",[26,134,135],{},"Mi piace tenere un approccio ordinato: capire il problema, scomporlo, e farlo funzionare davvero (senza magia nera… o almeno provandoci).",{"title":33,"searchDepth":34,"depth":34,"links":137},[],"2022 - 2025 | Websonica S.r.l. — Prima come stage web developer (2022-2023), poi come junior web developer (2023-2025). Ho lavorato su gestione e personalizzazione di siti WordPress e Magento2, su software custom in Laravel e Next.js, e su CRM come vTiger.",{},"/experiences/websonica",{"title":124,"description":138},"experiences/websonica","dVGZo1BJjKJRXpZU7gBpp2M0iuKv_52-qjEPKsA1GnA",{"id":145,"title":146,"body":147,"description":181,"extension":36,"meta":182,"navigation":38,"order":95,"path":183,"seo":184,"stem":185,"__hash__":186},"about/hobbies/favorite-games.md","favorite-games",{"type":23,"value":148,"toc":179},[149,156],[26,150,151,152,155],{},"Nei videogiochi mi sento a casa nei ",[111,153,154],{},"GDR",", soprattutto quelli story-driven: mi piace immergermi nelle storie, nei personaggi e nelle scelte (quelle che poi ti fanno pensare \"ok, questa me la porto dietro\").",[26,157,158,159,162,163,166,167,170,171,174,175,178],{},"Il mio primo \"innesco\" è stato ",[111,160,161],{},"Final Fantasy X",", e da lì ho continuato a cercare esperienze simili. Tra i miei preferiti ci sono la trilogia di ",[111,164,165],{},"Mass Effect"," (su Andromeda sorvoliamo), ",[111,168,169],{},"Baldur's Gate 3",", la saga di ",[111,172,173],{},"Persona"," (3, 4 e 5) e ",[111,176,177],{},"Clair Obscur 33",", probabilmente il mio preferito degli ultimi anni.",{"title":33,"searchDepth":34,"depth":34,"links":180},[],"Nei videogiochi mi sento a casa nei GDR, soprattutto quelli story-driven: mi piace immergermi nelle storie, nei personaggi e nelle scelte (quelle che poi ti fanno pensare \"ok, questa me la porto dietro\").",{},"/hobbies/favorite-games",{"title":146,"description":181},"hobbies/favorite-games","RjYRAf75mnYJgFIdt-pf1Wf3zXT7Y7Sum_s4AIaBdck",{"id":188,"title":189,"body":190,"description":194,"extension":36,"meta":215,"navigation":38,"order":34,"path":216,"seo":217,"stem":218,"__hash__":219},"about/hobbies/sports.md","sports",{"type":23,"value":191,"toc":213},[192,195,206],[26,193,194],{},"Ho praticato diversi sport (con una breve parentesi tra calcio e basket), ma i due che mi hanno formato di più sono stati scherma e tennis.",[26,196,197,198,201,202,205],{},"Per ",[111,199,200],{},"sei anni"," ho fatto agonismo nella ",[111,203,204],{},"scherma",", ottenendo buoni risultati a livello regionale e nazionale. Più che i piazzamenti, mi porto dietro ciò che conta davvero: fiducia costruita nel tempo, disciplina, ambizione e la capacità di lavorare in squadra anche quando la pressione sale.",[26,207,208,209,212],{},"Oggi il mio sport è il ",[111,210,211],{},"tennis",": è l'unico che pratico con continuità e che seguo davvero, anche in TV e streaming. Federer è stato il mio riferimento, e adesso mi godo con entusiasmo Alcaraz e (inevitabilmente) Sinner.",{"title":33,"searchDepth":34,"depth":34,"links":214},[],{},"/hobbies/sports",{"title":189,"description":194},"hobbies/sports","OjIveNcZF2yHP6pEJ4krecf72toMAa6nhMecOCA20Io",{"id":221,"title":222,"body":223,"description":33,"extension":36,"meta":242,"navigation":38,"order":95,"path":243,"seo":244,"stem":245,"__hash__":246},"about/personal-life/bio.md","bio",{"type":23,"value":224,"toc":239},[225,230,233,236],[226,227,229],"h2",{"id":228},"about-me","About me",[26,231,232],{},"Mi chiamo Giovanni Manara e lavoro come sviluppatore web dal 2022: prima uno stage, poi un percorso da junior, oggi full stack con propensione al frontend in una piccola web agency vicino Padova.",[26,234,235],{},"Mi muovo soprattutto su due binari: applicazioni web in Vue/Nuxt, dove mi sono occupato a lungo del frontend di una piattaforma di vendita online in produzione, e WordPress fatto sul serio — temi custom e plugin scritti da zero quando i builder non bastano. Ultimamente sto costruendo il backend del nuovo sito aziendale con Payload CMS.",[26,237,238],{},"Il filo conduttore: partire dal design, tenere la logica separata dalla UI, e quando un flusso mi serve più di una volta trasformarlo in uno strumento riusabile.",{"title":33,"searchDepth":34,"depth":34,"links":240},[241],{"id":228,"depth":34,"text":229},{},"/personal-life/bio",{"title":222,"description":33},"personal-life/bio","PXadkOSxGExPpohcY-s6KWcyBI_LvG_4DFW3s-eBhdg",{"id":248,"title":249,"body":250,"description":33,"extension":36,"meta":295,"navigation":38,"order":58,"path":296,"seo":297,"stem":298,"__hash__":299},"about/personal-life/education.md","education",{"type":23,"value":251,"toc":292},[252,256,259],[226,253,255],{"id":254},"educazione","Educazione",[26,257,258],{},"Un percorso non lineare: dalle biotecnologie allo sviluppo web, passando per la bioinformatica.",[260,261,262,269,275,286],"ul",{},[263,264,265,268],"li",{},[111,266,267],{},"2010-2015"," — Diploma al Liceo Scientifico Enrico Fermi (Padova).",[263,270,271,274],{},[111,272,273],{},"2015-2019"," — Laurea Triennale in Biotecnologie, Università del Piemonte Orientale (Novara).",[263,276,277,280,281,285],{},[111,278,279],{},"2019-2021"," — Laurea Magistrale in Bioinformatica, Università Tor Vergata (Roma). Qui mi sono avvicinato allo sviluppo web grazie a un corso di ",[282,283,284],"em",{},"Applicazioni web per la Bioinformatica",": con il contesto del COVID e una passione crescente, ho scelto di mettere in pausa l'università per concentrarmi sulla programmazione.",[263,287,288,291],{},[111,289,290],{},"2022"," — Corso professionalizzante in Full Stack Web Development (600 ore, riconosciuto MIUR), Accademia delle Professioni (Noventa Padovana), concluso con ottimi risultati.",{"title":33,"searchDepth":34,"depth":34,"links":293},[294],{"id":254,"depth":34,"text":255},{},"/personal-life/education",{"title":249,"description":33},"personal-life/education","zKz_U6qhxDUbh3tCI3bf5XcUlJLHsE-Ea0mDOJhN4ro",{"id":301,"title":302,"body":303,"description":33,"extension":36,"meta":321,"navigation":38,"order":34,"path":322,"seo":323,"stem":324,"__hash__":325},"about/personal-life/interests.md","interests",{"type":23,"value":304,"toc":318},[305,309,312,315],[226,306,308],{"id":307},"interessi","Interessi",[26,310,311],{},"Mi piace la tecnologia in senso ampio: dal web alle soluzioni \"ben costruite\", fino a tutto ciò che migliora processi e prodotti.",[26,313,314],{},"Amo il tennis (lo seguo e lo pratico da anni) e quando posso mi piace vivere i tornei dal vivo.",[26,316,317],{},"Mi piace anche viaggiare e cucinare: scoprire posti nuovi e provare sapori diversi è un ottimo modo per tenere la curiosità allenata.",{"title":33,"searchDepth":34,"depth":34,"links":319},[320],{"id":307,"depth":34,"text":308},{},"/personal-life/interests",{"title":302,"description":33},"personal-life/interests","E7rdK_OqdaU42uR_g8l-MRvUfHXlF0Mkjw6fiZzEkkw",{"id":327,"title":328,"body":329,"description":333,"extension":36,"meta":373,"navigation":38,"order":95,"path":374,"seo":375,"stem":376,"__hash__":377},"about/skills/hard-skills.md","hard-skills",{"type":23,"value":330,"toc":371},[331,334],[26,332,333],{},"Mi muovo tra front-end e back-end, con il frontend come casa.",[26,335,336,339,340,343,346,347,349,352,353,355,358,359,361,364,365,367,370],{},[111,337,338],{},"Fondamentali:"," HTML, CSS, JavaScript, TypeScript.",[341,342],"br",{},[111,344,345],{},"Frontend:"," Vue 3 / Nuxt, React / Next.js, Pinia.",[341,348],{},[111,350,351],{},"Stili:"," Tailwind, Sass, DaisyUI, design token da Figma.",[341,354],{},[111,356,357],{},"WordPress:"," temi child e plugin custom OO, ACF, WooCommerce, WPML.",[341,360],{},[111,362,363],{},"Backend:"," PHP, Payload CMS, MySQL, PostgreSQL.",[341,366],{},[111,368,369],{},"Strumenti:"," Git, GSAP, Stripe, i18n, sviluppo AI-assisted (Claude Code, Cursor) con workflow spec-first.",{"title":33,"searchDepth":34,"depth":34,"links":372},[],{},"/skills/hard-skills",{"title":328,"description":333},"skills/hard-skills","eFu6VaeKB7pA6op62PTPLV3PIMfwNP9blrWwzkBQMq8",{"id":379,"title":380,"body":381,"description":397,"extension":36,"meta":398,"navigation":38,"order":34,"path":399,"seo":400,"stem":401,"__hash__":402},"about/skills/soft-skills.md","soft-skills",{"type":23,"value":382,"toc":395},[383,389],[26,384,385,388],{},[111,386,387],{},"Teamwork:"," ho fatto sport a diversi livelli fin da giovane, e questo mi ha lasciato una cosa utilissima nel lavoro: saper stare in squadra, comunicare in modo chiaro e contribuire senza \"rumore\".",[26,390,391,394],{},[111,392,393],{},"Tenacia e affidabilità:"," le sfide mi stimolano. Quando qualcosa non torna, vado a fondo: studio, provo, documento e arrivo alla soluzione con costanza. Mi piace prendermi responsabilità su quello che consegno, perché il codice in produzione non perdona (ma insegna parecchio).",{"title":33,"searchDepth":34,"depth":34,"links":396},[],"Teamwork: ho fatto sport a diversi livelli fin da giovane, e questo mi ha lasciato una cosa utilissima nel lavoro: saper stare in squadra, comunicare in modo chiaro e contribuire senza \"rumore\".",{},"/skills/soft-skills",{"title":380,"description":397},"skills/soft-skills","QyBwnFi9-ZYJc-xGJ0-L1syIeASIp61uVcI2WBJ_HZo",{"id":404,"direct":405,"extension":5,"meta":410,"social":411,"stem":419,"__hash__":420},"contacts/meta/contacts.yml",{"title":406,"sources":407},"contacts",{"email":408,"phone":409},"giovanni@megiston.com","+39 375 890 5337",{},{"github":412,"linkedin":416},{"title":413,"url":414,"user":415},"Github profile","https://github.com/GioManara96","GioManara96",{"title":417,"url":418,"user":8},"Linkedin account","https://www.linkedin.com/in/giovanni-manara-80b3b324a/","meta/contacts","i0Q8Qe7rb0Tu8tqyz-9qGrPI7w8qOijxquLhi5vFgUU",{"id":422,"title":423,"body":424,"description":908,"extension":36,"img":909,"liveUrl":910,"meta":911,"navigation":38,"path":912,"projectId":58,"seo":913,"slug":914,"stack":915,"stem":928,"tech":929,"url":910,"__hash__":931},"projects/projects/b2b-quote-builder.md","Quote Builder B2B",{"type":23,"value":425,"toc":901},[426,432,436,439,443,446,450,484,491,715,718,722,732,870,876,882,886,897],[427,428,429],"blockquote",{},[26,430,431],{},"Progetto che ho sviluppato in agenzia per un cliente B2B e seguito in prima persona, dall'architettura alle migrazioni. Niente nomi e niente codice reale: gli snippet sono riscritti e semplificati per illustrare l'approccio.",[226,433,435],{"id":434},"cosè","Cos'è",[26,437,438],{},"Un e-commerce B2B che non espone prezzi non può avere un carrello classico. Questo plugin lo sostituisce con una \"lista progetti\": il cliente naviga il catalogo WooCommerce, aggiunge prodotti e quantità da qualsiasi pagina, e invia il tutto come richiesta di quotazione. Il commerciale riceve una email con PDF allegato e risponde direttamente al cliente.",[226,440,442],{"id":441},"il-problema","Il problema",[26,444,445],{},"Le richieste di preventivo arrivavano come email libere (\"mi servirebbero quei connettori, quelli grigi\"), senza codici prodotto né quantità. Serviva un flusso strutturato che non obbligasse nessuno a registrarsi, funzionasse su un sito Elementor esistente e non aggiungesse una build pipeline al deploy.",[226,447,449],{"id":448},"come-funziona","Come funziona",[260,451,452,466,472,478],{},[263,453,454,457,458,462,463],{},[111,455,456],{},"Store cross-page senza backend",": la lista vive in ",[459,460,461],"code",{},"localStorage"," con un envelope versionato, e resta sincronizzata tra tab aperte combinando un evento custom con l'evento nativo ",[459,464,465],{},"storage",[263,467,468,471],{},[111,469,470],{},"Vue 3 senza build step",": i componenti (toggle sui prodotti, pannello off-canvas, pagina lista) montano l'ESM build di Vue tramite una import map nativa — niente bundler, niente npm nel deploy",[263,473,474,477],{},[111,475,476],{},"Invio protetto",": nonce, honeypot, reCAPTCHA v3 e ri-validazione server-side di ogni campo; la richiesta finisce in una tabella custom e parte l'email con PDF (mPDF) o CSV allegato",[263,479,480,483],{},[111,481,482],{},"PDF brandizzato dal back-office",": logo scelto dalla media library e footer editabile dall'admin, senza toccare codice",[26,485,486,487,490],{},"Il dettaglio che preferisco: ",[111,488,489],{},"i link condivisibili sono stateless",". L'intera lista viaggia nell'URL come base64 URL-safe, quindi un preventivo si gira su WhatsApp o via email e si apre in una pagina read-only — con PDF scaricabile — senza che esista alcun record sul server.",[492,493,497],"pre",{"className":494,"code":495,"language":496,"meta":33,"style":33},"language-js shiki shiki-themes one-dark-pro","// La lista viaggia nell'URL: niente DB, niente account, niente link che scadono.\nfunction encodeSharePayload(items) {\n  const json = JSON.stringify(items.map(({ sku, qty }) => ({ sku, qty })))\n  const bytes = new TextEncoder().encode(json)\n  return btoa(String.fromCharCode(...bytes))\n    .replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '')\n}\n","js",[459,498,499,507,528,590,619,647,709],{"__ignoreMap":33},[500,501,503],"span",{"class":502,"line":95},"line",[500,504,506],{"class":505},"sV9Aq","// La lista viaggia nell'URL: niente DB, niente account, niente link che scadono.\n",[500,508,509,513,517,521,525],{"class":502,"line":34},[500,510,512],{"class":511},"seHd6","function",[500,514,516],{"class":515},"sVbv2"," encodeSharePayload",[500,518,520],{"class":519},"sn6KH","(",[500,522,524],{"class":523},"s_ZVi","items",[500,526,527],{"class":519},") {\n",[500,529,530,533,537,541,544,547,550,552,554,556,559,562,565,568,571,574,577,580,583,585,587],{"class":502,"line":58},[500,531,532],{"class":511},"  const",[500,534,536],{"class":535},"sU0A5"," json",[500,538,540],{"class":539},"sjrmR"," =",[500,542,543],{"class":535}," JSON",[500,545,546],{"class":519},".",[500,548,549],{"class":515},"stringify",[500,551,520],{"class":519},[500,553,524],{"class":535},[500,555,546],{"class":519},[500,557,558],{"class":515},"map",[500,560,561],{"class":519},"(({ ",[500,563,564],{"class":523},"sku",[500,566,567],{"class":519},", ",[500,569,570],{"class":523},"qty",[500,572,573],{"class":519}," }) ",[500,575,576],{"class":511},"=>",[500,578,579],{"class":519}," ({ ",[500,581,564],{"class":582},"sVyAn",[500,584,567],{"class":519},[500,586,570],{"class":582},[500,588,589],{"class":519}," })))\n",[500,591,592,594,597,599,602,605,608,611,613,616],{"class":502,"line":39},[500,593,532],{"class":511},[500,595,596],{"class":535}," bytes",[500,598,540],{"class":539},[500,600,601],{"class":511}," new",[500,603,604],{"class":515}," TextEncoder",[500,606,607],{"class":519},"().",[500,609,610],{"class":515},"encode",[500,612,520],{"class":519},[500,614,615],{"class":582},"json",[500,617,618],{"class":519},")\n",[500,620,622,625,628,630,633,635,638,641,644],{"class":502,"line":621},5,[500,623,624],{"class":511},"  return",[500,626,627],{"class":515}," btoa",[500,629,520],{"class":519},[500,631,632],{"class":535},"String",[500,634,546],{"class":519},[500,636,637],{"class":515},"fromCharCode",[500,639,640],{"class":519},"(...",[500,642,643],{"class":582},"bytes",[500,645,646],{"class":519},"))\n",[500,648,650,653,656,658,662,664,667,670,672,674,677,679,682,684,687,689,692,696,699,702,704,707],{"class":502,"line":649},6,[500,651,652],{"class":519},"    .",[500,654,655],{"class":515},"replaceAll",[500,657,520],{"class":519},[500,659,661],{"class":660},"subq3","'+'",[500,663,567],{"class":519},[500,665,666],{"class":660},"'-'",[500,668,669],{"class":519},").",[500,671,655],{"class":515},[500,673,520],{"class":519},[500,675,676],{"class":660},"'/'",[500,678,567],{"class":519},[500,680,681],{"class":660},"'_'",[500,683,669],{"class":519},[500,685,686],{"class":515},"replace",[500,688,520],{"class":519},[500,690,691],{"class":582},"/=",[500,693,695],{"class":694},"sVC51","+",[500,697,698],{"class":511},"$",[500,700,701],{"class":582},"/",[500,703,567],{"class":519},[500,705,706],{"class":660},"''",[500,708,618],{"class":519},[500,710,712],{"class":502,"line":711},7,[500,713,714],{"class":519},"}\n",[26,716,717],{},"Lato server il payload è trattato come completamente ostile: decodifica strict, massimo 200 righe, e ogni campo ri-sanitizzato uno per uno prima di toccare qualsiasi cosa.",[226,719,721],{"id":720},"dettagli-di-cui-vado-fiero","Dettagli di cui vado fiero",[26,723,724,727,728,731],{},[111,725,726],{},"Il fix del BCC che spariva."," I plugin SMTP agganciano ",[459,729,730],{},"phpmailer_init"," a priorità 10 e riscrivono i destinatari, cancellando i BCC passati come header. La soluzione: aggiungere il BCC in un hook a priorità 99, e rimuovere l'hook subito dopo l'invio per non inquinare le mail successive della stessa richiesta.",[492,733,737],{"className":734,"code":735,"language":736,"meta":33,"style":33},"language-php shiki shiki-themes one-dark-pro","$add_bcc = function ($phpmailer) use ($bcc) {\n  $phpmailer->addBCC($bcc);\n};\n// Priorità 99: dopo che il plugin SMTP ha già riscritto i destinatari.\nadd_action('phpmailer_init', $add_bcc, 99);\nwp_mail($to, $subject, $body, $headers, $attachments);\nremove_action('phpmailer_init', $add_bcc, 99);\n","php",[459,738,739,768,786,791,796,819,851],{"__ignoreMap":33},[500,740,741,744,746,749,752,755,758,761,763,766],{"class":502,"line":95},[500,742,743],{"class":582},"$add_bcc",[500,745,540],{"class":539},[500,747,748],{"class":511}," function",[500,750,751],{"class":519}," (",[500,753,754],{"class":582},"$phpmailer",[500,756,757],{"class":519},") ",[500,759,760],{"class":511},"use",[500,762,751],{"class":519},[500,764,765],{"class":582},"$bcc",[500,767,527],{"class":519},[500,769,770,773,776,779,781,783],{"class":502,"line":34},[500,771,772],{"class":582},"  $phpmailer",[500,774,775],{"class":519},"->",[500,777,778],{"class":515},"addBCC",[500,780,520],{"class":519},[500,782,765],{"class":582},[500,784,785],{"class":519},");\n",[500,787,788],{"class":502,"line":58},[500,789,790],{"class":519},"};\n",[500,792,793],{"class":502,"line":39},[500,794,795],{"class":505},"// Priorità 99: dopo che il plugin SMTP ha già riscritto i destinatari.\n",[500,797,798,801,803,806,809,812,814,817],{"class":502,"line":621},[500,799,800],{"class":515},"add_action",[500,802,520],{"class":519},[500,804,805],{"class":660},"'phpmailer_init'",[500,807,808],{"class":519},",",[500,810,811],{"class":582}," $add_bcc",[500,813,808],{"class":519},[500,815,816],{"class":694}," 99",[500,818,785],{"class":519},[500,820,821,824,826,829,831,834,836,839,841,844,846,849],{"class":502,"line":649},[500,822,823],{"class":515},"wp_mail",[500,825,520],{"class":519},[500,827,828],{"class":582},"$to",[500,830,808],{"class":519},[500,832,833],{"class":582}," $subject",[500,835,808],{"class":519},[500,837,838],{"class":582}," $body",[500,840,808],{"class":519},[500,842,843],{"class":582}," $headers",[500,845,808],{"class":519},[500,847,848],{"class":582}," $attachments",[500,850,785],{"class":519},[500,852,853,856,858,860,862,864,866,868],{"class":502,"line":711},[500,854,855],{"class":515},"remove_action",[500,857,520],{"class":519},[500,859,805],{"class":660},[500,861,808],{"class":519},[500,863,811],{"class":582},[500,865,808],{"class":519},[500,867,816],{"class":694},[500,869,785],{"class":519},[26,871,872,875],{},[111,873,874],{},"Una rinomina fatta come una migrazione vera."," A metà vita il plugin ha cambiato nome e concetto (da \"wishlist\" a \"progetti\"): rename della tabella, remap delle opzioni, riscrittura one-shot degli shortcode già salvati nelle pagine, migrazione della chiave localStorage — e retrocompatibilità permanente sui vecchi link condivisi. Zero downtime, invisibile per gli editor.",[26,877,878,881],{},[111,879,880],{},"Ogni errore ha il suo status code."," Gli endpoint AJAX rispondono 403 per nonce non valido, 400 per lo spam, 422 per la validazione, 500 per i guasti veri — così il client distingue cosa dire all'utente e i log raccontano storie leggibili.",[226,883,885],{"id":884},"cosa-ho-imparato","Cosa ho imparato",[260,887,888,891,894],{},[263,889,890],{},"Si può portare reattività moderna in uno stack WordPress/Elementor legacy senza imporre una toolchain: le import map native sono sottovalutate",[263,892,893],{},"Un payload che parte dal tuo stesso frontend va comunque trattato come input ostile",[263,895,896],{},"Le migrazioni contano più delle feature: la rinomina è la parte del progetto che rifarei identica",[898,899,900],"style",{},"html pre.shiki code .sV9Aq, html code.shiki .sV9Aq{--shiki-default:#7F848E;--shiki-default-font-style:italic}html pre.shiki code .seHd6, html code.shiki .seHd6{--shiki-default:#C678DD}html pre.shiki code .sVbv2, html code.shiki .sVbv2{--shiki-default:#61AFEF}html pre.shiki code .sn6KH, html code.shiki .sn6KH{--shiki-default:#ABB2BF}html pre.shiki code .s_ZVi, html code.shiki .s_ZVi{--shiki-default:#E06C75;--shiki-default-font-style:italic}html pre.shiki code .sU0A5, html code.shiki .sU0A5{--shiki-default:#E5C07B}html pre.shiki code .sjrmR, html code.shiki .sjrmR{--shiki-default:#56B6C2}html pre.shiki code .sVyAn, html code.shiki .sVyAn{--shiki-default:#E06C75}html pre.shiki code .subq3, html code.shiki .subq3{--shiki-default:#98C379}html pre.shiki code .sVC51, html code.shiki .sVC51{--shiki-default:#D19A66}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":33,"searchDepth":34,"depth":34,"links":902},[903,904,905,906,907],{"id":434,"depth":34,"text":435},{"id":441,"depth":34,"text":442},{"id":448,"depth":34,"text":449},{"id":720,"depth":34,"text":721},{"id":884,"depth":34,"text":885},"Plugin WordPress per un catalogo B2B senza prezzi pubblici - i clienti compongono una lista prodotti cross-page e la inviano come richiesta di preventivo, con PDF generato server-side e link condivisibili senza database.","/icons/projects/quote-builder-wide.webp",null,{},"/projects/b2b-quote-builder",{"title":423,"description":908},"b2b-quote-builder",[916,919,922,924,926],{"icon":917,"label":918},"cib:wordpress","WordPress",{"icon":920,"label":921},"cib:vue-js","Vue 3",{"label":923},"WooCommerce",{"label":925},"mPDF",{"label":927},"reCAPTCHA v3","projects/b2b-quote-builder",[930],"wordpress","57LUg45FthOAtb9-F2YbH3ofKpnU4r02iJymLiiXgrc",1786039355223]