<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[My Publication]]></title><description><![CDATA[My Publication]]></description><link>https://mrpsiho.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>My Publication</title><link>https://mrpsiho.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 19 Sep 2026 07:40:34 GMT</lastBuildDate><atom:link href="https://mrpsiho.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Build branded WordPress email templates in the block editor — and test them without spamming a real inbox]]></title><description><![CDATA[The default WordPress form notification is unmistakable: plain white background, a monospace dump of every field, the site URL at the bottom. It delivers the information and tells the recipient they'r]]></description><link>https://mrpsiho.hashnode.dev/build-branded-wordpress-email-templates-in-the-block-editor-and-test-them-without-spamming-a-real-inbox</link><guid isPermaLink="true">https://mrpsiho.hashnode.dev/build-branded-wordpress-email-templates-in-the-block-editor-and-test-them-without-spamming-a-real-inbox</guid><category><![CDATA[WordPress]]></category><category><![CDATA[webdev]]></category><category><![CDATA[email]]></category><category><![CDATA[Testing]]></category><dc:creator><![CDATA[Vitalii Kiiko]]></dc:creator><pubDate>Mon, 29 Jun 2026 09:44:17 GMT</pubDate><content:encoded><![CDATA[<p>The default WordPress form notification is unmistakable: plain white background, a monospace dump of every field, the site URL at the bottom. It delivers the information and tells the recipient they're dealing with a site running on defaults. For a contact form, fine. For a booking confirmation or an order receipt — the first thing a customer gets <em>after paying you</em> — it's a missed impression.</p>
<p>The usual fix is to reach for a transactional email SaaS and start templating in their dashboard, away from WordPress, with their own merge-tag syntax. I wanted the template to live where the form lives, and — more importantly as a developer — I wanted to <strong>iterate on it without sending half-finished emails to a real address.</strong></p>
<h2>Templating in the editor you already know</h2>
<p>The approach that stuck: design the email as <strong>blocks</strong> in the native Gutenberg editor — headings, columns, buttons, images, spacers — and let the plugin compile that to email-safe HTML on save (CSS inlined so Gmail/Outlook/Apple Mail render it correctly). No separate editor, no hand-written table-based HTML, no inlining CSS by hand.</p>
<p>Personalisation is dynamic tags dropped into text blocks:</p>
<pre><code>Hi {{email.first_name}},

Your booking at {{site.name}} is confirmed.

Check-in:  {{email.checkin_date}}
Check-out: {{email.checkout_date}}
Total:     {{email.price}} {{email.currency}}
</code></pre>
<p><code>{{site.*}}</code> tags are always available; <code>{{email.field_name}}</code> tags resolve to whatever the user submitted in the named field (including calculated values exposed from the form). Tags work in the subject line too. They render as literal text while editing and get substituted at send time.</p>
<h2>The part that matters: test against a sandbox, not a colleague's inbox</h2>
<p>This is the workflow I actually came to recommend. Before a template touches a real address, point it at <strong>Mailtrap's free sandbox</strong> — a catch-all SMTP server that intercepts every send and shows you the full HTML render, raw source, headers, and a spam score in a browser inbox. Nothing escapes to a real recipient.</p>
<p>Add it as an SMTP server once:</p>
<pre><code>Host:     sandbox.smtp.mailtrap.io
Port:     2525
Username: &lt;your sandbox inbox username&gt;
Password: &lt;your sandbox inbox password&gt;
</code></pre>
<p>Then submit the form as a visitor would. The email lands in Mailtrap in a couple of seconds, fully rendered. Layout wrong? Edit the template, save, submit again. Because every send is caught, you can iterate as many times as you like with zero risk of a "test 47" email reaching a customer. The free plan covers 1,000 test emails/month across five inboxes — far more than any template needs.</p>
<p>When the render is right, flip the SMTP server on that send action from the Mailtrap sandbox to your production sender. Same template, same tags — only the transport changes.</p>
<h2>Confirm delivery instead of guessing</h2>
<p>The last piece that closed the loop for me: an <strong>email log</strong> that records every outgoing message regardless of transport — date, which server sent it, success/failed status, the full body, and the error string on failure (wrong password, port blocked by the host firewall, rate limit). Diagnosing a bad send by <em>reading the log row</em> beats chasing a missing email with no trail.</p>
<hr />
<p>I wrote the <strong>full walkthrough</strong> — building the template block by block, the complete Dynamic Data tag reference, wiring the Send Email Template action, and the Mailtrap setup with screenshots — on my blog:</p>
<p>👉 <strong><a href="https://craftformswp.com/build-branded-email-templates-in-wordpress/">Build Branded Email Templates in WordPress (and Test Them with Mailtrap)</a></strong></p>
<p><em>Disclosure: I build <a href="https://craftformswp.com">CraftForms</a>, the plugin with the block-based email builder shown here. The Mailtrap-sandbox testing workflow applies to any WordPress mail setup.</em></p>
]]></content:encoded></item><item><title><![CDATA[WordPress is an underrated form-and-data backend — here's the architecture]]></title><description><![CDATA[Whenever a developer mentions using WordPress as a backend, someone in the thread brings up why it's a bad idea. It's PHP. It's bloated. It's not a "real" API.
They're not entirely wrong about the blo]]></description><link>https://mrpsiho.hashnode.dev/wordpress-is-an-underrated-form-and-data-backend-here-s-the-architecture</link><guid isPermaLink="true">https://mrpsiho.hashnode.dev/wordpress-is-an-underrated-form-and-data-backend-here-s-the-architecture</guid><category><![CDATA[WordPress]]></category><category><![CDATA[webdev]]></category><category><![CDATA[JAMstack]]></category><category><![CDATA[api]]></category><dc:creator><![CDATA[Vitalii Kiiko]]></dc:creator><pubDate>Sun, 28 Jun 2026 19:11:45 GMT</pubDate><content:encoded><![CDATA[<p>Whenever a developer mentions using WordPress as a backend, someone in the thread brings up why it's a bad idea. It's PHP. It's bloated. It's not a "real" API.</p>
<p>They're not entirely wrong about the bloat. But they're wrong about the conclusion — at least for one specific use case.</p>
<p>Used as a <em>form and data backend</em> for web projects — not a CMS you expose to the public — a single WordPress install is genuinely hard to beat, especially when you're managing more than one site.</p>
<h2>What you actually need to process a form submission</h2>
<p>Building a backend to handle form submissions sounds simple. It isn't. Here's what you actually need:</p>
<ul>
<li>Somewhere to store submissions and query them later</li>
<li>Transactional email that reliably arrives (not <code>mail()</code> on shared hosting)</li>
<li>A file upload handler with storage management</li>
<li>An admin interface to review, filter, and export data</li>
<li>Spam protection</li>
<li>User auth and roles if you need them</li>
<li>A REST endpoint to receive POST data from your frontend</li>
</ul>
<p>WordPress ships all of this. The database and schema, the SMTP-pluggable <code>wp_mail()</code> layer, the Media Library, the admin panel (including a full users and roles system), nonce-based CSRF protection, and the REST API — present, production-tested, on millions of sites.</p>
<p>Building this yourself gives you a cleaner architecture and full control. A form SaaS gives you an endpoint but your data lives on their servers. WordPress gives you the whole stack, pre-configured, for the cost of a cheap shared VPS.</p>
<h2>The architecture</h2>
<p>One WP install. Locked down to a single REST namespace. Shared as the backend for as many projects as you want.</p>
<pre><code>Project A (static site)  ──┐
Project B (Next.js app)  ──┼──▶  WP REST API  ──▶  DB / Storage / Email
Project C (mobile app)   ──┘
</code></pre>
<p>Each project POSTs to the same endpoint. WordPress handles validation, storage, email, and file management. None of your frontends need to know it's PHP behind the wall — they just see a REST endpoint that returns JSON.</p>
<p>The lock-down is a must-use plugin: four filters, about 20 lines of PHP. It blocks the public frontend entirely, restricts the REST API to your one namespace (killing <code>/wp/v2/users</code>, route discovery, and the standard WP REST exploits), kills XML-RPC, and optionally relocates the login page to a non-guessable path. I posted the full mu-plugin in <a href="https://dev.to/mrpsiho/using-a-locked-down-wordpress-as-the-form-backend-for-my-static-sites-4d9c">a previous article on dev.to</a> if you want to copy it verbatim.</p>
<h2>The embed option most people miss</h2>
<p>Here's the part that took me a while to find useful: WordPress can also <em>serve the form HTML</em> to any frontend.</p>
<p>Your form plugin exposes an embed endpoint:</p>
<pre><code>GET /wp-json/craftforms/v1/embed/YOUR_FORM_KEY
</code></pre>
<p>It returns the rendered form HTML, CSS, and initialisation JS as a single response. Your frontend drops in a <code>&lt;div&gt;</code> and a <code>&lt;script&gt;</code> tag. The form renders. Validation, file uploads, multi-step logic, CAPTCHA — all managed from the backend, all delivered to whatever site loads the snippet.</p>
<p>This means a static site with literally no server of its own can run a multi-step booking form, a product configurator with price calculation, or a payment-enabled order form. The backend does the work; the frontend just displays the output.</p>
<pre><code class="language-html">&lt;!-- On any page, on any host --&gt;
&lt;div id="cf-form"&gt;&lt;/div&gt;
&lt;script src="https://your-backend.com/wp-json/craftforms/v1/embed/contact?target=cf-form"&gt;&lt;/script&gt;
</code></pre>
<h2>When this trade-off is worth making</h2>
<p>This architecture wins when:</p>
<ul>
<li>You manage several sites and want one data layer instead of separate backends</li>
<li>Your forms need file uploads, complex conditional logic, or WooCommerce integration</li>
<li>You want to own your submission data and control the email infrastructure</li>
<li>You don't want to build a backend from scratch or pay a per-submission SaaS fee</li>
</ul>
<p>It's not the right call if you need a fully provider-agnostic API layer, if you're already running a Node/Go/Python server that handles this cleanly, or if submission volume makes a single-site WordPress instance a bottleneck.</p>
<p>For the common pattern — one to several sites, a small team, forms that need to do more than just email you — it's the most pragmatic stack I've settled on.</p>
<hr />
<p>I wrote the <strong>full walkthrough</strong> — the lock-down mu-plugin in full, multi-project configuration, the embed setup, file upload handling, and SMTP routing — on my blog:</p>
<p>👉 <strong><a href="https://craftformswp.com/how-to-use-wordpress-as-a-form-backend-for-static-sites-and-web-apps/">How to Use WordPress as a Form Backend for Static Sites and Web Apps</a></strong></p>
<p><em>Disclosure: I build <a href="https://craftformswp.com">CraftForms</a>, the form plugin used in the examples. The lock-down pattern and REST architecture work with any plugin that exposes a consistent REST namespace.</em></p>
]]></content:encoded></item></channel></rss>