
TablouriColorate — a WooCommerce photo configurator, from React to 12 KB of vanilla JS
tablouricolorate.ro ↗Context
TablouriColorate is a small business in Târgu Mureș that prints customers' photos on canvas, posters, banners and stickers. The shop runs on WooCommerce, and the heart of it is a configurator where a customer uploads a photo, chooses size and finish and sees the price before adding the product to the cart. I've built and maintained that configurator as a custom plugin since 2018.
The problem
After moving from a limited custom e-commerce platform to WooCommerce, the shop needed much richer product options: photos from the device or Facebook, sizes, finishing, packaging, filters and a design service, all in a pleasant interface. The first version, written in jQuery, slowed to a crawl during photo uploads. The ReactJS + Material-UI rewrite that followed fixed the experience, but over the years it grew into five separate React apps that shipped 520–730 KB of JavaScript per page, with Redux, webpack, Babel and Sentry along for the ride.
What I built
In 2026 I replaced the five React apps with one dependency-free vanilla JavaScript configurator of about 12 KB gzipped. It serves six product types, each behind its own shortcode: canvas, multicanvas, collage, poster, banner and sticker.
- Uploads from the device or Facebook; the Facebook SDK only loads when the upload dialog opens.
- Crop previews and the 8 collage layouts are drawn with
<canvas>and CSS grid instead of extra libraries. - After an upload the server recommends sizes based on the photo's aspect ratio and resolution.
- Multicanvas, a new product: one photo printed across up to 12 canvas pieces. The customer drags the photo over all the pieces, and each order line stores exactly which area of the photo goes on which piece, for the print team.
- In wp-admin: a settings tab per product type, a size picker, product metaboxes, bulk actions and order details showing the photo and options.
Under the hood
- Pricing is computed on the server from the same option list the browser uses for display, so what the customer sees is what lands in the cart.
- Uploads are hardened: a MIME allowlist, image validation, a per-IP rate limit, and remote photos downloaded only from Facebook's CDN domains as SSRF protection.
- Sizes moved from a custom table to product meta parsed from the product title, with a one-time migration that keeps the old table for rollback.
- WordPress Coding Standards, PHPStan level 5 with an empty baseline, and PHPUnit + WP_Mock tests for uploads, prices, sizes and multicanvas.
- GitHub Actions runs PHPCS, PHPStan, PHPUnit and syntax checks, then builds and deploys to staging or production.
Result
The configurator went from 520–730 KB to about 12 KB gzipped per page, with no build step and no third-party runtime. The price shown and the price charged come from one formula, and the new multicanvas product shipped on top of the rewrite. The shop has been on a maintenance plan with me since 2018.
Stack
WordPress, WooCommerce, PHP, vanilla JavaScript, Canvas API, Facebook JS SDK, PHPStan, PHPUnit, GitHub Actions.
Technologies:
- WooCommerce
- PHP
- Vanilla JS
- Canvas API
- PHPStan
- PHPUnit
- GitHub Actions
Share on: