<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Anthony Lee — Articles</title>
    <link>https://anthonylee.me/articles</link>
    <description>Technical writing on WordPress, WooCommerce, TypeScript and the systems behind them.</description>
    <language>en</language>
    <atom:link href="https://anthonylee.me/articles/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Customising CS-Cart Without Losing the Ability to Upgrade</title>
      <link>https://anthonylee.me/articles/cs-cart-upgrade-safe-customisation</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/cs-cart-upgrade-safe-customisation</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>An upgrade replaces core files rather than merging them, so a change made in one is not at risk — it is guaranteed to be deleted, silently. How to customise heavily and still stay current.</description>
      <category>CS-Cart</category>
      <category>PHP</category>
      <category>E-commerce</category>
    </item>
    <item>
      <title>Your CSP Says unsafe-inline. Here Is What That Costs.</title>
      <link>https://anthonylee.me/articles/csp-unsafe-inline</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/csp-unsafe-inline</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>Blocking inline scripts is most of what a Content Security Policy is for, because injected XSS is almost always inline. Why so many policies give that up anyway, and the two ways to take it back.</description>
      <category>Security</category>
      <category>Headers</category>
      <category>Web</category>
    </item>
    <item>
      <title>What an NFC Attendance System Actually Has to Handle</title>
      <link>https://anthonylee.me/articles/nfc-attendance-system</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/nfc-attendance-system</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>Reading the card takes a weekend. Modelling identity so cards can be lost, surviving an offline reader, and being honest that a tap records a card rather than a person — that is the project.</description>
      <category>NFC / RFID</category>
      <category>IoT</category>
      <category>Research</category>
    </item>
    <item>
      <title>Prerendering a React Site Without Adopting a Framework</title>
      <link>https://anthonylee.me/articles/prerender-react-without-a-framework</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/prerender-react-without-a-framework</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>A plain Vite build ships an empty div. You can get real HTML out of it in about forty lines, keep your setup, and skip hydration entirely — as long as you know which trade you are making.</description>
      <category>Vite</category>
      <category>React</category>
      <category>Performance</category>
    </item>
    <item>
      <title>Scroll-Driven CSS Animations Without Stranding Your Content</title>
      <link>https://anthonylee.me/articles/scroll-driven-animations-safely</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/scroll-driven-animations-safely</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>animation-timeline replaces a pile of IntersectionObserver code with a few lines of CSS. It also has a failure mode you will never see in your own browser, because unsupported browsers fall back to a time-based clock.</description>
      <category>CSS</category>
      <category>Accessibility</category>
      <category>Performance</category>
    </item>
    <item>
      <title>Your Phone Is Still Downloading the Desktop Effects</title>
      <link>https://anthonylee.me/articles/desktop-only-javascript</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/desktop-only-javascript</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>CSS hides the pixels, not the JavaScript. Gating two decorative libraries behind the breakpoint the stylesheet already used cut this site&apos;s mobile payload by about two thirds — with the real numbers.</description>
      <category>Performance</category>
      <category>CSS</category>
      <category>Mobile</category>
    </item>
    <item>
      <title>99% Accurate and Still Wrong: What Face Recognition Benchmarks Do Not Tell You</title>
      <link>https://anthonylee.me/articles/face-recognition-accuracy</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/face-recognition-accuracy</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>Every model quotes an accuracy figure above 99%. Almost nobody explains why yours will be worse — the threshold you pick, the size of the gallery you search, and whose faces the benchmark was built from.</description>
      <category>Computer vision</category>
      <category>Machine learning</category>
      <category>Python</category>
    </item>
    <item>
      <title>One Good Boundary: Putting a Typed API in Front of a Legacy Platform</title>
      <link>https://anthonylee.me/articles/typed-api-over-legacy</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/typed-api-over-legacy</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>You cannot replace the old system and you cannot let every new service reach into it. What belongs in the layer between — and the temptations that turn it into a second legacy system.</description>
      <category>Architecture</category>
      <category>TypeScript</category>
      <category>APIs</category>
    </item>
    <item>
      <title>Access Control That Holds: Roles, Permissions and Where to Check Them</title>
      <link>https://anthonylee.me/articles/access-control-that-holds</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/access-control-that-holds</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>Permissions have to stay correct in code nobody has written yet. Why capability checks beat role checks, why scoping belongs in the query rather than the view, and the defaults that quietly grant access.</description>
      <category>Security</category>
      <category>Architecture</category>
      <category>Reliability</category>
    </item>
    <item>
      <title>Migrating a Busy WooCommerce Store to HPOS Without Downtime</title>
      <link>https://anthonylee.me/articles/woocommerce-hpos-migration</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/woocommerce-hpos-migration</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>High-Performance Order Storage has been the default for new WooCommerce installs since 8.2 — but an upgraded store keeps the old one, and the version number won&apos;t tell you which you&apos;re on. The order of operations that makes the switch boring.</description>
      <category>WooCommerce</category>
      <category>HPOS</category>
      <category>Migration</category>
    </item>
    <item>
      <title>Building a Multi-Vendor Marketplace: What the Comparison Posts Leave Out</title>
      <link>https://anthonylee.me/articles/multi-vendor-marketplace-reality</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/multi-vendor-marketplace-reality</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>Every guide compares plugins on features and price. Six months in, none of that is what hurts. What actually decides the stack is money that is not yours, shipping that is not one parcel, and the vendors themselves.</description>
      <category>E-commerce</category>
      <category>Marketplace</category>
      <category>Architecture</category>
    </item>
    <item>
      <title>Stopping Contact Form Spam Without a CAPTCHA</title>
      <link>https://anthonylee.me/articles/contact-form-spam-without-captcha</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/contact-form-spam-without-captcha</guid>
      <pubDate>Fri, 14 Aug 2026 00:00:00 GMT</pubDate>
      <description>A honeypot, a minimum fill time and a rate limit stop the overwhelming majority of form spam, cost a real visitor nothing, and send no data to a third party. Including the parts that go wrong — starting with the honeypot that traps screen reader users.</description>
      <category>Security</category>
      <category>Forms</category>
      <category>Accessibility</category>
    </item>
    <item>
      <title>Checkout Bugs Are Not Like Other Bugs</title>
      <link>https://anthonylee.me/articles/payment-and-shipping-correctness</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/payment-and-shipping-correctness</guid>
      <pubDate>Sun, 09 Aug 2026 00:00:00 GMT</pubDate>
      <description>Payment and shipping code fails differently: the customer finds it before you do, the damage is money, and you often can&apos;t just deploy a fix and move on. What that changes about how you write it.</description>
      <category>Payments</category>
      <category>E-commerce</category>
      <category>Reliability</category>
    </item>
    <item>
      <title>Real-Time Without the Mess: What a WebSocket Actually Costs You</title>
      <link>https://anthonylee.me/articles/realtime-without-the-mess</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/realtime-without-the-mess</guid>
      <pubDate>Sun, 09 Aug 2026 00:00:00 GMT</pubDate>
      <description>A WebSocket is easy to open and hard to keep honest. The reconnection, the gap while you were away, and why I&apos;d usually send &apos;something changed&apos; instead of the change itself.</description>
      <category>WebSocket</category>
      <category>TypeScript</category>
      <category>Architecture</category>
    </item>
    <item>
      <title>What Breaks First When a WooCommerce Store Gets Busy</title>
      <link>https://anthonylee.me/articles/woocommerce-at-scale</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/woocommerce-at-scale</guid>
      <pubDate>Sat, 08 Aug 2026 00:00:00 GMT</pubDate>
      <description>WooCommerce handles real traffic fine. What falls over is everything built around the assumption that it wouldn&apos;t — here&apos;s what goes first, and the order I&apos;d fix it in.</description>
      <category>WooCommerce</category>
      <category>WordPress</category>
      <category>Performance</category>
    </item>
    <item>
      <title>Where TypeScript Stops: Keeping a Typed Frontend Honest About an Untyped API</title>
      <link>https://anthonylee.me/articles/typescript-api-boundary</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/typescript-api-boundary</guid>
      <pubDate>Sat, 08 Aug 2026 00:00:00 GMT</pubDate>
      <description>TypeScript checks nothing about what the server actually sent. A practical account of where the types stop being true — especially against a PHP backend — and what belongs at that boundary.</description>
      <category>TypeScript</category>
      <category>APIs</category>
      <category>Architecture</category>
    </item>
    <item>
      <title>Twelve Hours Out of Sync: Working From Bali for Teams in the US and Australia</title>
      <link>https://anthonylee.me/articles/remote-across-time-zones</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/remote-across-time-zones</guid>
      <pubDate>Sat, 08 Aug 2026 00:00:00 GMT</pubDate>
      <description>What actually makes a twelve-hour time difference workable — not tooling, but a handful of habits about how questions get asked and how work gets handed over.</description>
      <category>Remote work</category>
      <category>Process</category>
      <category>Communication</category>
    </item>
    <item>
      <title>Why Your WordPress + Elementor Site Feels Slow (And How to Actually Fix It)</title>
      <link>https://anthonylee.me/articles/wordpress-elementor-performance</link>
      <guid isPermaLink="true">https://anthonylee.me/articles/wordpress-elementor-performance</guid>
      <pubDate>Sun, 26 Jul 2026 00:00:00 GMT</pubDate>
      <description>A practical, no-fluff guide to speeding up WordPress sites built with Elementor — what actually causes the slowdown, and the fixes that make a measurable difference.</description>
      <category>WordPress</category>
      <category>Elementor</category>
      <category>Performance</category>
    </item>
  </channel>
</rss>
