Bitcar
A custom vehicle and yacht rental catalog in Thailand
Role
Frontend/Fullstack Developer
Year
2021
Stack
HTMLSCSSJavaScriptGulpPHPWordPressWooCommerce

The task
The client needed an online catalog where users could select a vehicle, dates, and location, and then submit an inquiry to a manager (without online payment integration).
Stages
Architecture & Database Design
- Configured WooCommerce for catalog purposes.
- Created taxonomies, attributes (separate for cars and yachts), and custom meta fields for complex pricing.
- Registered UI strings via
pll_register_stringfor centralized translation in the admin panel, avoiding hardcoded text in templates.
Frontend Build & UI/UX
- Iterative design development with the client. Built the interface using SCSS + Gulp (minified to
app.min.js). - Integrated Swiper with WebP support (via
<picture>), custom select components, and sticky blocks for inquiry forms. - Created a distinct marketing template for the Transfer page (
page-transfer.php).
Backend Logic & Booking
- Implemented AJAX filters with URL state support.
- Integrated FullCalendar in the backend and AirDatepicker on the frontend with cross-language date-blocking logic.
- Configured Contact Form 7 with custom phone validation and localized error messages.
Dynamic Pricing & Wishlist
- Wrote scripts to recalculate rental costs on the fly based on duration.
- Adapted the 5-currency conversion logic for non-standard pricing fields.
- Configured YITH Wishlist to work for unregistered guests via browser sessions.
- Integrated Google Tag and Meta Pixel for conversion tracking.
The process
Under the Hood
Visuals & Design System
The design system (color palette, card composition, responsive breakpoints) was formed in tight, iterative collaboration with the client. Without a strict initial design brief, layouts were refined progressively throughout development.
Catalog Architecture
Vehicles and yachts are implemented as WooCommerce products, leveraging its robust, out-of-the-box system of taxonomies and attributes rather than relying on custom tables:
- Categories/Subcategories: Utilized the standard
product_cattaxonomy (Cars → New/Pickup/Hatchback, etc., Moto, Yachts). - Locations: (Hua Hin, Bangkok, Pattaya, Phuket, Koh Samui) are handled via
product_tag, allowing the location filter to be reused across all catalog sections and on partner/transfer pages. - Vehicle Specs: Managed via native WooCommerce attributes (
pa_brand,pa_transmission,pa_drive-unit,pa_insurance, etc.). Yachts have a distinct, non-overlapping attribute set (capacity, cruising speed, number of cabins, length, build year). - For fields not supported natively (weekly/monthly rates, tier-based deposits, mileage limits, front-page feature flags), custom product meta fields were added via the
woocommerce_product_options_general_product_datahook.
Multilingual Support
Built with Polylang: 3 language versions (RU/EN/TH) for products, categories, and static UI text. Interface strings unattached to content (block headers, filter labels, validation error texts) are registered via pll_register_string and translated centrally in the Polylang admin panel, avoiding hardcoded text in templates.
Multi-currency Integration
Converts across 5 currencies (THB, USD, EUR, RUB, KZT) via a WooCommerce multi-currency plugin. Since the plugin's conversion logic only applies to the base product price, I wrote custom logic to recalculate custom fields (weekly/monthly rates, deposits) based on the user's current currency rate—both on the server (when rendering cards and product pages) and on the client (when recalculating the final booking total in real-time).
Catalog Filtering (~13 Parameters)
Each category (cars, motos, yachts) features a dedicated PHP AJAX filtering handler (WP_Query using a combination of tax_query/meta_query) to prevent page reloads:
- Shared for Cars/Motos: Category, brand, transmission, drive unit, insurance, pickup/return location, capacity (passengers/engine volume), price range (noUiSlider), build year range, location, and language.
- Exclusive for Yachts: Shipyard/manufacturer, capacity, cruising speed, number of cabins, length, build year, and price.
Filter states are synchronized with the URL and localStorage (the selected location persists across catalog navigation), significantly reducing redundant database queries.
Dynamic Pricing
Rental prices are recalculated on the client side based on the selected period:
- Up to 7 days: Daily rate.
- 7–30 days: Weekly rate, prorated by the exact number of days.
- 30+ days: Monthly rate, prorated by the exact number of days (or "price on request" if the rate is undefined).
The final total is dynamically recalculated on the fly when dates are selected in the calendar, instantly updating both the product card and the booking form.
Booking Calendar & Date Availability
- The backend product edit page integrates a custom calendar (FullCalendar). Managers select date ranges to block via AJAX, saving the record to a dedicated database table linked to the product.
- Because each product has language duplicates (RU/EN/TH), bookings are synchronized across all language versions via
pll_get_post_translationsupon creation. This ensures dates remain blocked regardless of which language the product is viewed in. - On the frontend, booking dates are pulled into an AirDatepicker instance. Past and previously booked dates are unselectable, providing clear visual cues to the user.
Vehicle Card & Dedicated Yacht Page
The product card template branches dynamically based on the category. Cars/motos display daily/weekly/monthly rates, deposits, and mileage limits. Yachts utilize a distinct layout featuring an expanded gallery, detailed descriptions, specific specs (capacity, knots, cabins, build year), and a dedicated yacht rental form via Contact Form 7 (with custom fields differing from the car/moto form).
Wishlist Page
Powered by YITH WooCommerce Wishlist, allowing guest users to save items without registration (tied to the browser session). On the wishlist page, prices are dynamically converted to the current currency identically to the catalog, ensuring data consistency across the site.
Transfer Landing Page
A custom page template (page-transfer.php) featuring a standalone marketing structure: the service's Unique Selling Proposition (USP), an "early booking = lower price" section, an estimated pricing table by vehicle type, and a dedicated inquiry form.
Frontend & Layout
- Built using SCSS + Gulp, outputting minified bundle files (
app.min.js). - Product galleries utilize Swiper with WebP support via
<picture>/<source>and lazy loading. - Custom UI components include a price range slider (noUiSlider), enhanced selects (select2 / custom select scripts), and a sticky block for pricing and inquiry forms on product pages.
- Integrated Contact Form 7 with custom phone validation and localized error messages via Polylang.
- Analytics integration (Google tag / gtag.js, Meta Pixel) for tracking booking conversion events.
The results
AJAX filtering parameters operating without page reloads, featuring state synchronization via URL and `localStorage`.
supported currencies (THB, USD, EUR, RUB, KZT) with custom on-the-fly recalculation logic for non-standard pricing fields across both client and server.
distinct catalog branches (Cars, Motos, Yachts) running on a single WooCommerce core, utilizing completely isolated attribute sets and custom card templates.
cross-language synchronization: booking a date automatically and instantly blocks the availability slots across all 3 language versions (RU, EN, TH) via a unified database table.