NoSleepMan
A custom WooCommerce storefront for a UK tracksuit brand — campaign homepage, Nike-style swatches, bag drawer, and guest-to-account favourites — built as a Storefront child theme so checkout and orders stay on WooCommerce.

The problem
Off-the-shelf WooCommerce themes look generic and fight a streetwear brand: the homepage is a blog-shaped stack, the product page is a dropdown-heavy form, and the bag / checkout feel like admin screens. NoSleepMan needed a UK tracksuit shop — hoodies, trousers, and sets — with a campaign homepage, Nike-style swatches, a real bag drawer, and account favourites, without replacing WooCommerce or Storefront’s checkout and order engine.
My role
Solo developer. I designed and built the storefront end to end: Storefront child theme (PHP hooks, not a fork), custom CSS and vanilla JS, WooCommerce catalog / PDP / bag / checkout / account / emails, Customizer-driven homepage content, local XAMPP development, and production on Hostinger with the domain at GoDaddy (https://nosleepman.com).
Tech stack
- WordPress
- WooCommerce
- PHP
- Storefront (parent theme)
- Nosleepman (child theme)
- HTML / CSS
- JavaScript
- MySQL
- Apache (XAMPP locally, Hostinger in production)
- Git / GitHub
- Hostinger
- GoDaddy
WordPress and WooCommerce run the catalog, cart, checkout, and accounts. The Nosleepman child theme extends Storefront through hooks and woocommerce/ template overrides only where the layout must change. Styles live in assets/css/main.css; behaviour in assets/js/main.js. Locally the stack is XAMPP (Apache + MySQL). Production is Hostinger public_html plus a MySQL database; DNS for nosleepman.com is pointed from GoDaddy.
Features
- Campaign homepage: hero, shop-by-category, featured products, brand story video, lookbook, social
- Customizer panel for announcement, hero, story, editorial, and newsletter copy
- Shop catalog with filters, sort, colour dots, and mobile filter sheet
- Product page with colour / size / fit / fabric swatches, size guide, reviews accordion, and Add to bag
- Mini-cart drawer and full bag page with quantity steppers and related products
- Favourites for guests (cookie) and logged-in customers (account endpoint + merge on login)
- Classic checkout (blocks disabled), order receipt, and branded WooCommerce emails
- Header search with product-title inflection so “hoodie” / “hoodies” still match
- Account dashboard, orders, and password rules
- GBP / UK storefront, mobile nav drawer, and responsive layout
Architecture
Shop workflow
- Shopper lands on the homepage or
/shop. - Child theme renders catalog tiles, colour dots, and filters through WooCommerce loops.
- On a variable product, swatches update the hidden selects; WooCommerce matches a variation and enables Add to bag.
- Cart updates via fragments and a custom quantity AJAX endpoint for the mini-cart.
- Checkout stays classic WooCommerce; the theme restyles fields, totals, and the thank-you / receipt view.
- Emails embed product thumbs as CID images so they still show when remote images are blocked.
Challenges & solutions
Extend Storefront without forking it
Challenge: Replacing header, footer, or shop templates would break Storefront and WooCommerce upgrades.
Solution: The child theme only hooks into Storefront’s homepage action and WooCommerce template hooks. Header and footer stay with the parent. Custom markup lives in template-parts/ and inc/*.php.
Variable products with more than three attributes
Challenge: Colour, size, fit, and fabric create more than WooCommerce’s default 30 inlined variations. Custom swatches also have to drive hidden <select>s that WooCommerce’s jQuery variation form actually reads.
Solution: Swatches write the selected value into the native select and dispatch change. Attribute name / id fall back to attribute_{slug} when WooCommerce passes empty args, so the chosen combination is posted with the cart.
Mini-cart quantity without a full reload
Challenge: Storefront’s mini-cart refreshed the whole fragment; stepping quantity felt laggy and could desync the bag page.
Solution: A dedicated nsm_update_mini_cart_qty WooCommerce AJAX endpoint updates qty and returns JSON. The same stepper logic is shared on the bag page so both surfaces stay in sync.
Favourites for guests and accounts
Challenge: Guests needed a heart on the catalog, but those IDs had to survive login without a plugin.
Solution: Guests store IDs in a cookie. Logged-in users store them as user meta. On login or register, cookie IDs are merged and the cookie is cleared. My Account gets a Favourites endpoint.
Product search that understands plurals
Challenge: WooCommerce’s default search missed “hoodies” when the title was “Hoodie”.
Solution: woocommerce-search.php expands each token with simple English inflection variants and rewrites the product search SQL so layered-nav counts stay consistent.
Order emails with missing images
Challenge: Many clients block remote images, so receipt emails showed empty boxes.
Solution: Thumbnails are embedded as CID attachments through PHPMailer. The email HTML swaps src to cid:… so the photo travels with the message.
Local XAMPP to Hostinger
Challenge: The site ran at http://localhost/nosleepman. Git ignores wp-config.php and uploads. A GitHub deploy therefore shipped no media, leftover localhost URLs, and a subfolder .htaccess. Hostinger CDN (cdn.hstgr.net) then sat in front of the domain and produced SSL / Cloudflare 1001 errors.
Solution: Ship a zip that includes uploads, import MySQL, set live wp-config.php, search-replace http://localhost/nosleepman → https://nosleepman.com, and use a root RewriteBase /. Disable Hostinger CDN so the A record points at the origin IP, then install Lifetime SSL on that host.
A closer look.

