A software developer who is particularly good at turning strong design and business requirements into finished products.

Nirup Island

Hospitality · Design and development · WordPress, PHP, WooCommerce · Lumios Digital · nirupisland.com

My role
Designer and sole developer, at Lumios Digital.
What I delivered
A custom WordPress theme written by hand, 68 templates and around 25,000 lines, with nine content types, villa booking through WooCommerce, an admin-editable island map and a bilingual English and Bahasa Indonesia front end.
Why it mattered
Three hospitality operators and two unrelated audiences share one address. The theme models the island rather than describing it, so the team edits content instead of filing developer tickets.
Current status
Delivered and live. It has run the island’s bookings, enquiries and content since launch, edited by the client’s team rather than by me.
The Nirup Island homepage hero

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.

Book your stay Two options, presented as equals OURS Villa calendars Riahi Residences, searched by date Results, remapped Calendar ID to villa, theme markup Checkout WooCommerce, overridden NOT OURS The Westin Marriott booking funnel

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.

The island map, with its labelled points across the resort, marina and villas

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.