A software developer who is particularly good at turning strong design and business requirements into finished products.
Scope
Nirup Island is a private island in Indonesia's Riau Archipelago, forty-five minutes by ferry from Singapore. On it sit three separate hospitality operators: The Westin Nirup Island Resort & Spa, run by Marriott; the Riahi Residences, private villas under Swiss-belHotel; and ONE°15 Marina. Around them are five restaurants, four experience programmes, a ferry service and villas for sale.
I designed the site and built the theme, at Lumios Digital. It is a custom WordPress theme written by hand: 68 PHP templates, around 25,000 lines, with per-feature stylesheets and vanilla JavaScript. No page builder, no starter theme, no build step.
The problem
An island is not a website with a homepage and some subpages. Nirup is several businesses sharing an address. The resort runs on its own inventory, the marina takes berthing enquiries, the villas are both rentable and for sale, the restaurants have their own identities and none of it means anything to a visitor who cannot work out how to get there.
It also serves two audiences who want nothing in common. Somebody planning a weekend needs rooms, dining, experiences and ferry times. Somebody considering buying a villa needs floor plans, pricing and a sales contact. The same site has to do both without either journey feeling like an afterthought, in English and Bahasa Indonesia.
And the site does not own the whole transaction. Marriott keeps its own booking funnel for the resort, so half the accommodation on the island is booked somewhere else entirely.
Modeling the island
The shortcut is to build pages. Each thing on the island gets a page, someone writes the content into it, and the site looks finished. It also stops being true the first time a restaurant changes its hours.
Instead the theme models what is actually there, as nine content types: villas, Westin rooms, experiences, restaurants, events and offers, ferry schedules, private charters, media coverage, and the sales units for villa ownership. Each is a real kind of thing on the island rather than a page about one, so a villa can appear in an availability result, on a map, in a carousel and in the sales section without being written four times.
Editing that model is done through 36 meta box groups on the content types and 328 Customizer settings across 29 sections, which is where the copy, imagery and arrangement of every front-end section live.
Booking, when you only own half of it
A guest arriving at the site wants to stay on the island. Whether that means a Marriott room or a Swiss-belHotel villa is an operator distinction, not a guest one.
But the resort books through Marriott and always will, while the villas book here. Pretending otherwise produces the worst outcome: a booking flow that looks unified and then dead-ends. So the site names the split instead of hiding it. Booking presents both options as equals, each with its own inventory and its own destination, and the villa calendar states in plain words that it covers the Riahi Residences only. A guest who ends up on marriott.com meant to.
The half that is ours runs on booking calendars the theme searches directly, then intercepts the plugin's result markup and rebuilds it: each calendar maps back to its villa through a stored ID, so the card carries the real image, the real starting price and the real link rather than plugin defaults. Payment runs through WooCommerce with the checkout and confirmation templates overridden, so the transaction never drops the guest into a stock store page.
The map, and who moves the pins
Two maps do real work here. One is the ferry route, which answers the first question anybody asks, with Singapore and Batam routes switchable on the same view. The other is the island itself: where the resort sits relative to the marina, the beach club, the villas.
The island map is a set of labelled points, and the obvious way to build it is to write the coordinates into the code.
The obvious way is also the version where every change is a developer ticket. So the map has an editor behind it. Pins are dragged into place on a preview of the island in the WordPress admin, positions save as they move, and the same screen handles bulk edits, filtering, and import and export of the whole pin set.
It is a small tool, and it is the difference between a map that stays accurate and a map that quietly goes stale.
Built to be handed over
There is no build step. Styles are plain CSS split per feature, scripts are vanilla JavaScript, and the PHP is organised into focused files for post types, meta boxes, Customizer sections, AJAX handlers and asset loading.
That is deliberate. A hospitality site outlives the person who wrote it, and the next developer should be able to open a file and read it rather than reconstruct a toolchain from a lockfile that stopped installing two years ago. Nothing here rots when a dependency does.
API keys for maps, captcha and the newsletter are read through a single accessor rather than written into templates, so nothing sensitive lives in the repository.
Also in the build
Status
Delivered and live. The site has run the island's bookings, enquiries and content since launch, edited by the team rather than by me.