I Built an AI Fitting Room With a PHP Plugin and Zero Regrets
february 11, 2025
Online fashion has a $400B return problem. I fixed it with PHP, Google Gemini, and a WooCommerce modal. No VC funding was harmed in the making of this project.
I Built an AI Fitting Room With a PHP Plugin and Zero Regrets
The fashion industry loses $400 billion a year to returns. Me: I'll fix it. With PHP.
Look, everyone wants to solve hard problems with flashy tech. Kubernetes clusters. Custom ML pipelines. Billion-parameter vision transformers trained on proprietary data.
I used Google Gemini, a WooCommerce plugin, and a CSS modal.
The fitting room still works.

The Problem Is Actually Real
Online clothes shopping has one fundamental flaw: you cannot tell if it'll look good on you. So you buy three sizes, keep one, return two. The warehouse re-accepts the return, dry-cleans it, restocks it — and the planet loses its mind.
Conversion rates drop. Return rates climb. Customer service handles complaints. The whole thing is a mess with a very obvious solution that somehow costs a fortune if you want the brand-name version of it.
So I built the budget version. It's called tryon-modal.
"It's Just a WordPress Plugin"
Yes. And the back button is "just pressing F1 instead of F5." The container matters less than what's inside it.
WooCommerce runs on 30% of all e-commerce sites. The plugin ecosystem means any store owner can install this in under five minutes without touching a line of code. Targeting WordPress wasn't a compromise — it was the distribution strategy.
Also, if you write condescending tweets about PHP, please know that PHP 8 exists and has named arguments, enums, fibers, and union types. It's fine. You're fine. We're all fine.
The Gemini Part (This Is the Fun Part)
Here's the thing about AI Virtual Try-On: the custom model route would cost you a research team, six months, and a GPU budget. Google Gemini's multimodal API already understands images, garments, and human figures.
So instead of training anything, you send it:
- The user's photo
- The garment image
- A carefully crafted prompt
And it gives you back a try-on composite. The "AI research" was writing a good prompt and a clean API handler class in PHP.
// The whole "AI" is this. Don't overthink it.
$response = $this->gemini->generateContent([
'parts' => [
['text' => $this->buildTryOnPrompt($garmentCategory)],
['inline_data' => ['mime_type' => 'image/jpeg', 'data' => $userPhotoBase64]],
['inline_data' => ['mime_type' => 'image/jpeg', 'data' => $garmentImageBase64]],
]
]);
That's it. That's the AI integration. The model handles the rest.
The Garment Mapper: My Favorite Feature Nobody Will Notice
One of the things that actually matters for result quality is garment categorization. Gemini needs context: is this a top? A dress? Trousers? The prompt changes significantly based on the garment type, and the prompt difference changes the output quality significantly.
So I built an admin-side Garment Mapper — a bulk configuration UI where shop owners can mark their product images as Tops, Bottoms, Dresses, Outerwear, etc. It sounds boring. It makes the AI results noticeably better. Nobody will tweet about it. I'm extremely proud of it.
Security in a Plugin Nobody Asked For
Okay here's where it gets slightly serious for a beat.
Any tool that accepts user-uploaded photos and runs them through an external API has some real attack surfaces. User uploads can be malicious. SQL queries can be injected. CSRF attacks are a thing on every web form ever.
So the plugin does the boring-but-correct stuff:
- Nonces on every AJAX action (CSRF protection)
esc_html()/sanitize_*everywhere output touches the DOM (XSS)$wpdb->prepare()on every database query (SQL injection)- MIME type validation on uploaded photos before they go anywhere
- HTTPS enforcement on all Gemini API calls
Nobody claps for security discipline. The alternative is a CVE. I'll take the silence.
The Modal UI: Invisible Until You Need It
The worst thing a plugin can do is slow down the product page. So the modal loads nothing — no CSS, no JS overhead — until the user clicks the Virtual Try-On button. Then the whole UI bootstraps itself.
The modal supports:
- Drag-and-drop photo upload with a live preview
- A results pane that fades in when Gemini responds
- A download button for the try-on result
- An Add to Cart button right there in the modal — no page leave required
The whole thing is styled with a CSS class namespace (nano-tryon-*) so it can be overridden per-theme without touching plugin files. Because the cardinal sin of WordPress plugin development is !important-ing your styles into the host theme.
Session History: The Feature That Exists Because It Should
Try-on sessions get stored in a custom database table (wp_tryon_sessions) — image paths, garment used, timestamp, user ID. The history view lets users revisit what they tried. It costs two SQL queries and a simple UI loop.
Could I have skipped it? Sure. Users who come back to check "what looked good last time" before buying are genuinely more likely to convert. It's free retention. I kept it.
Does It Work?
Yes. Users upload a photo, pick a product with garment mapping configured, and within a few seconds see themselves wearing it — without leaving the product page, without an account on some third-party app, without paying $99/month for a SaaS that does the same thing.
A WooCommerce store. A Gemini API key. A five-minute plugin install.
That's the whole thing. Sometimes the unsexy tool for the unsexy platform solves a real problem better than the venture-backed alternative. Sometimes the fitting room is a PHP modal.
The code is open source on GitHub. If you run a WooCommerce store and have a Gemini API key, it takes longer to read this post than to get it running.