Files
help4bis-com/site/work/tawnytrails.html
T
help4bisandClaude Sonnet 5.5 9e6a41fc5d chore: baseline of the live help4bis.com docroot as of 2026-10-23 (cockpit #168)
Excludes analytics/data, vendor, support, .env, ACME tokens.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 06:45:34 +10:00

540 lines
29 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<!-- Version: 1.2.0 | Created: 2026-05-05 | Updated: 2026-08-16 -->
<html lang="en-AU">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tawny Trails Case Study | HELP4BIS</title>
<meta name="description" content="How Tawny Trails was built: 22 venues, 3 curated itineraries, a custom REST API, a Flutter PWA, and a membership platform for a rural arts and tourism trail in SE Queensland.">
<meta name="author" content="HELP4BIS">
<meta name="publisher" content="Dutch Digital Dynamics Pty Ltd">
<meta name="language" content="en-AU">
<meta name="geo.region" content="AU-QLD">
<link rel="canonical" href="https://help4bis.com/work/tawnytrails.html">
<meta name="robots" content="index, follow">
<meta property="og:type" content="website">
<meta property="og:url" content="https://help4bis.com/work/tawnytrails.html">
<meta property="og:site_name" content="HELP4BIS">
<meta property="og:title" content="Tawny Trails Case Study | HELP4BIS">
<meta property="og:description" content="22 venues, 3 itineraries, a custom Flutter PWA, and a WordPress REST API for a rural arts and tourism trail in the D'Aguilar Range, SE Queensland.">
<meta property="og:image" content="https://help4bis.com/assets/images/tawny-trails.jpg">
<meta property="og:locale" content="en_AU">
<link rel="icon" type="image/jpeg" href="../assets/images/logo-favicon.jpg"> <link rel="stylesheet" href="../assets/css/style.css">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"@id": "https://help4bis.com/work/tawnytrails.html#webpage",
"url": "https://help4bis.com/work/tawnytrails.html",
"name": "Tawny Trails Case Study | HELP4BIS",
"description": "A rural arts and tourism trail platform: 22 venues, 3 curated itineraries, a custom WordPress REST API, Flutter PWA, accessibility map, and PMPro membership, built for tawnytrails.com.",
"isPartOf": {"@id": "https://help4bis.com/#website"},
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [
{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://help4bis.com/"},
{"@type": "ListItem", "position": 2, "name": "Our Work", "item": "https://help4bis.com/#portfolio"},
{"@type": "ListItem", "position": 3, "name": "Tawny Trails", "item": "https://help4bis.com/work/tawnytrails.html"}
]
}
}
</script>
<style>
.cs-hero {
background: linear-gradient(160deg, var(--ink) 0%, #1a1a0d 50%, #1a2a10 100%);
padding: var(--sp-16) 0 var(--sp-12);
position: relative;
overflow: hidden;
}
.cs-hero::before {
content: '';
position: absolute;
top: -30%;
right: -15%;
width: 60%;
height: 200%;
background: radial-gradient(circle, rgba(245,158,11,.06) 0%, transparent 65%);
pointer-events: none;
}
.cs-breadcrumb {
font-size: 13px;
color: rgba(255,255,255,.45);
margin-bottom: var(--sp-5);
display: flex;
align-items: center;
gap: 8px;
}
.cs-breadcrumb a { color: rgba(255,255,255,.45); }
.cs-breadcrumb a:hover { color: var(--white); }
.cs-breadcrumb span { color: rgba(255,255,255,.25); }
.cs-hero h1 { color: var(--white); max-width: 820px; margin-bottom: var(--sp-4); }
.cs-hero-sub {
font-size: clamp(16px, 2vw, 20px);
color: rgba(255,255,255,.65);
max-width: 680px;
line-height: 1.65;
margin-bottom: var(--sp-6);
}
.cs-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.btn-amber {
background: linear-gradient(135deg, var(--amber), #d97706);
color: var(--ink);
border-color: transparent;
box-shadow: 0 4px 14px rgba(245,158,11,.30);
}
.btn-amber:hover {
background: linear-gradient(135deg, #fbbf24, var(--amber));
color: var(--ink);
transform: translateY(-2px);
}
.cs-kpis {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 16px;
margin-top: var(--sp-8);
padding-top: var(--sp-8);
border-top: 1px solid rgba(255,255,255,.08);
}
@media (min-width: 640px) { .cs-kpis { grid-template-columns: repeat(4, 1fr); } }
.cs-kpi { text-align: center; }
.cs-kpi-value {
font-family: var(--font-head);
font-size: clamp(32px, 4vw, 52px);
font-weight: 900;
color: var(--amber);
line-height: 1;
letter-spacing: -0.04em;
}
.cs-kpi-label {
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .12em;
color: rgba(255,255,255,.45);
margin-top: 6px;
}
.cs-feature-grid {
display: grid;
grid-template-columns: 1fr;
gap: 24px;
margin-top: var(--sp-6);
}
@media (min-width: 640px) { .cs-feature-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .cs-feature-grid { grid-template-columns: repeat(3, 1fr); } }
.cs-feature-card {
background: var(--white);
border: 1px solid var(--grey-100);
border-radius: var(--r-lg);
padding: 24px;
box-shadow: var(--shadow-card);
}
.cs-feature-card h4 { font-size: 15px; margin-bottom: 8px; color: var(--ink); }
.cs-feature-card p { font-size: 14px; color: var(--grey-600); line-height: 1.6; margin: 0; }
.cs-feature-icon {
width: 36px;
height: 36px;
background: var(--grey-50);
border-radius: var(--r-md);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 14px;
font-size: 18px;
}
.cs-venue-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
margin-top: var(--sp-5);
}
@media (min-width: 640px) { .cs-venue-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 900px) { .cs-venue-grid { grid-template-columns: repeat(4, 1fr); } }
.cs-venue-chip {
background: var(--grey-50);
border: 1px solid var(--grey-100);
border-radius: var(--r-md);
padding: 10px 14px;
font-size: 13px;
color: var(--grey-800);
font-weight: 500;
line-height: 1.4;
}
.cs-venue-chip span {
display: block;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .08em;
color: var(--amber);
margin-bottom: 3px;
}
.cs-stack { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--sp-4); }
.cs-stack-tag {
background: var(--grey-50);
border: 1px solid var(--grey-100);
border-radius: var(--r-full);
padding: 6px 14px;
font-size: 13px;
font-weight: 500;
color: var(--grey-600);
}
.cs-two-col { display: grid; grid-template-columns: 1fr; gap: var(--sp-8); align-items: start; }
@media (min-width: 768px) { .cs-two-col { grid-template-columns: 1fr 1fr; } .cs-two-col--wide { grid-template-columns: 3fr 2fr; } }
.cs-quote {
border-left: 3px solid var(--amber);
padding: var(--sp-4) var(--sp-5);
background: rgba(245,158,11,.04);
border-radius: 0 var(--r-md) var(--r-md) 0;
margin: var(--sp-5) 0;
}
.cs-quote p { font-size: 17px; line-height: 1.7; color: var(--grey-800); font-style: italic; margin: 0; }
.cs-honest {
background: var(--grey-50);
border: 1px solid var(--grey-100);
border-radius: var(--r-lg);
padding: var(--sp-4) var(--sp-5);
margin: var(--sp-5) 0;
}
.cs-honest-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .12em; color: var(--grey-400); margin-bottom: 8px; }
.cs-honest p { font-size: 14px; color: var(--grey-600); line-height: 1.65; margin: 0; }
.cs-divider { height: 1px; background: var(--grey-100); margin: var(--sp-8) 0; }
.cs-cta {
background: linear-gradient(135deg, var(--ink-mid), var(--ink));
border-radius: var(--r-2xl);
padding: var(--sp-10) var(--sp-8);
text-align: center;
}
.cs-cta h2 { color: var(--white); margin-bottom: var(--sp-4); }
.cs-cta p { color: rgba(255,255,255,.65); max-width: 560px; margin: 0 auto var(--sp-6); font-size: 17px; line-height: 1.7; }
</style>
</head>
<body>
<nav class="nav" role="navigation" aria-label="Main navigation">
<div class="nav__inner">
<a class="nav__logo" href="../index.html" aria-label="HELP4BIS home">
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
</a>
<ul class="nav__links" id="nav-links" role="list">
<li class="nav__dropdown">
<button class="nav__trigger" aria-haspopup="true" aria-expanded="false">Services <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
<ul class="nav__dropdown-menu" role="menu">
<li class="nav__menu-group">WordPress</li>
<li><a href="../managed-wordpress.html" role="menuitem">Tailored Website Management</a></li>
<li><a href="../care-plans.html" role="menuitem">WP Care Plans <span class="menu-price">from $49/mo</span></a></li>
<li><a href="../sos-fix.html" role="menuitem">WP SOS Fix <span class="menu-price">$97 flat</span></a></li>
<li><a href="../ai-integration.html" role="menuitem">AI Integration</a></li>
<li><a href="../plugin-development.html" role="menuitem">Custom Plugin Development</a></li> </ul>
</li>
<li><a href="../about.html">About</a></li>
<li><a href="../index.html#portfolio">Our Work</a></li>
<li><a href="../index.html#pricing">Pricing</a></li>
<li><a href="../blog/index.html">Blog</a></li>
<li><a href="../your-first-week-with-ai.html">AI Guide</a></li>
<li><a href="../contact.html">Contact</a></li>
<li class="nav__cta-mobile" aria-hidden="true">
<a href="../contact.html" class="btn btn-primary">Get Started</a>
<a href="../sos-fix.html" class="btn btn-secondary">SOS Fix, $97</a>
</li>
</ul>
<div class="nav__cta">
<a href="../sos-fix.html" class="btn btn-secondary btn-sm">SOS Fix, $97</a>
<a href="../contact.html" class="btn btn-primary btn-sm">Get Started</a>
</div>
<button class="nav__burger" id="nav-burger" aria-label="Open menu" aria-expanded="false" aria-controls="nav-links">
<span></span><span></span><span></span>
</button>
</div>
</nav>
<!-- HERO -->
<section class="cs-hero" aria-labelledby="cs-heading">
<div class="container">
<div class="cs-breadcrumb">
<a href="../index.html">Home</a><span>›</span>
<a href="../index.html#portfolio">Our Work</a><span>›</span>
<span style="color:rgba(255,255,255,.7);">Tawny Trails</span>
</div>
<p class="eyebrow" style="color:rgba(245,158,11,.9);">Case Study: Tourism &amp; Arts Trail</p>
<h1 id="cs-heading">Tawny Trails.<br>A rural arts trail<br>with a proper platform.</h1>
<p class="cs-hero-sub">22 venues across the D'Aguilar Range and surrounds (art studios, sculpture gardens, horse riding, ceramics, accommodation, and bush walks) all connected through a REST API I built on WordPress, feeding a Flutter PWA and a curated itinerary system.</p>
<div class="cs-hero-actions">
<a href="https://tawnytrails.com" target="_blank" rel="noopener" class="btn btn-amber">Visit tawnytrails.com →</a>
<a href="https://flutter.tawnytrails.com" target="_blank" rel="noopener" class="btn btn-secondary">Open the app</a>
</div>
<div class="cs-kpis">
<div class="cs-kpi"><div class="cs-kpi-value">22</div><div class="cs-kpi-label">Venues on the Trail</div></div>
<div class="cs-kpi"><div class="cs-kpi-value">3</div><div class="cs-kpi-label">Curated Itineraries</div></div>
<div class="cs-kpi"><div class="cs-kpi-value">1.7</div><div class="cs-kpi-label">Custom Plugins Built</div></div>
<div class="cs-kpi"><div class="cs-kpi-value">6.9 MB</div><div class="cs-kpi-label">Flutter PWA</div></div>
</div>
</div>
</section>
<!-- OVERVIEW -->
<section class="section" aria-labelledby="overview-heading">
<div class="container">
<div class="cs-two-col cs-two-col--wide">
<div>
<p class="eyebrow">Overview</p>
<h2 id="overview-heading">What it is</h2>
<p class="large">Tawny Trails is a self guided arts and tourism trail covering the D'Aguilar Range, the Dayboro valley, and the surrounding hinterland northwest of Brisbane. 22 venues, from galleries, studios and sculpture parks to horse trail operators, accommodation, and bush walking areas, connected through a single platform that visitors can use on a phone without needing to install anything.</p>
<p>The brief I got wasn't just a directory with a map. It needed themed itineraries so a day visitor from Brisbane could plan a route without spending twenty minutes reading. It needed opening hours that were current, and with 22 venues it is important keep those current without me touching them. It needed to work as a Flutter app on the phone, not a website that looks like it was designed for a desktop. And it needed a membership layer so venue operators could manage their own listings.</p>
<div class="cs-quote">
<p>"The gap between 'a WordPress site with a map plugin' and 'an actual trail platform' is a custom REST API, a Flutter app, and a decent itinerary system. That's what I built."</p>
</div>
<div class="cs-stack">
<span class="cs-stack-tag">WordPress</span>
<span class="cs-stack-tag">Flutter Web</span>
<span class="cs-stack-tag">Custom REST API</span>
<span class="cs-stack-tag">ACF</span>
<span class="cs-stack-tag">PMPro Membership</span>
<span class="cs-stack-tag">Elementor Pro</span>
<span class="cs-stack-tag">Custom CPT</span>
</div>
</div>
<div>
<img src="../assets/images/tawny-trails.jpg" alt="Tawny Trails arts and tourism trail" style="width:100%;border-radius:var(--r-xl);box-shadow:var(--shadow-lg);" loading="lazy">
</div>
</div>
</div>
</section>
<!-- VENUES -->
<section class="section section--alt" aria-labelledby="venues-heading">
<div class="container">
<p class="eyebrow">The Trail</p>
<h2 id="venues-heading">22 venues, all on one platform</h2>
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;">Each venue is a custom post type (<code>tt_venue</code>) with ACF fields for opening hours, GPS coordinates, category, accessibility notes, and contact details. The Flutter app reads all of it from my REST API. There's no hardcoded content in the app itself.</p>
<div class="cs-venue-grid">
<div class="cs-venue-chip"><span>Art Studio</span>Kylie Farrelly Art</div>
<div class="cs-venue-chip"><span>Art Studio</span>Ann Russell Art</div>
<div class="cs-venue-chip"><span>Art Studio</span>Tatiana Afonina</div>
<div class="cs-venue-chip"><span>Art Studio</span>Christa's Art &amp; Gilding</div>
<div class="cs-venue-chip"><span>Gallery</span>The Artist Cove</div>
<div class="cs-venue-chip"><span>Gallery</span>Dayboro Art Gallery</div>
<div class="cs-venue-chip"><span>Gallery</span>Running Duck Studio</div>
<div class="cs-venue-chip"><span>Ceramics</span>Woodside Ceramics</div>
<div class="cs-venue-chip"><span>Sculpture</span>Phoenix Sculpture Garden</div>
<div class="cs-venue-chip"><span>Heritage</span>Silverwood Butter Factory</div>
<div class="cs-venue-chip"><span>Workshop</span>The Gantry</div>
<div class="cs-venue-chip"><span>Restaurant</span>Rendezvous</div>
<div class="cs-venue-chip"><span>Horse Riding</span>Slickers Horse Riding</div>
<div class="cs-venue-chip"><span>Bush Walk</span>Maiala Rain Forest</div>
<div class="cs-venue-chip"><span>Lookout</span>Dahmongah Lookout Park</div>
<div class="cs-venue-chip"><span>Accommodation</span>Maiala Park Lodge</div>
<div class="cs-venue-chip"><span>Accommodation</span>Laceys Creek Homestead</div>
<div class="cs-venue-chip"><span>Accommodation</span>Cascade Cottage</div>
<div class="cs-venue-chip"><span>Accommodation</span>Walkabout Retreat</div>
<div class="cs-venue-chip"><span>Accommodation</span>Mercure Clear Mountain</div>
<div class="cs-venue-chip"><span>Accommodation</span>Ocean View Estates</div>
<div class="cs-venue-chip"><span>Accommodation</span>Oceanview Estates</div>
</div>
</div>
</section>
<!-- REST API + FLUTTER -->
<section class="section" aria-labelledby="api-heading">
<div class="container">
<p class="eyebrow">Technical Architecture</p>
<h2 id="api-heading">A custom API feeding the Flutter app</h2>
<p style="max-width:640px;color:var(--grey-600);font-size:17px;line-height:1.7;">The TawnyTrails API plugin (tt-api) is the engine of the whole platform. I wrote it to expose venue data, itineraries, and opening hours logic via a custom REST API. The Flutter app has no hardcoded content. Everything it displays is fetched live from WordPress.</p>
<div class="cs-feature-grid">
<div class="cs-feature-card">
<div class="cs-feature-icon">🔌</div>
<h4>TawnyTrails API Plugin (tt-api)</h4>
<p>A WordPress plugin I built specifically for this project. It handles venue data storage, custom field management, the REST API layer, and data caching to keep the Flutter app fast without hitting the database on every request.</p>
</div>
<div class="cs-feature-card">
<div class="cs-feature-icon">📱</div>
<h4>Flutter PWA at flutter.tawnytrails.com</h4>
<p>A Flutter Web app compiled to JavaScript and deployed as static files. 6.9 MB, runs on Android, iPhone (via Safari Add to Home Screen), and desktop. Reads venues and itineraries from the REST API on load. No App Store account required for iOS users.</p>
</div>
<div class="cs-feature-card">
<div class="cs-feature-icon">🗺️</div>
<h4>Live venue map</h4>
<p>Every venue has GPS coordinates stored as ACF fields. The Flutter app renders an interactive map from the API data. Visitors can see all 22 stops, filter by category, and get directions from their current location.</p>
</div>
<div class="cs-feature-card">
<div class="cs-feature-icon">🕐</div>
<h4>Opening hours logic</h4>
<p>Each venue's opening hours are stored as structured data, not free text. The API calculates whether a venue is open right now based on the current time and day. The app shows "Open now" or "Closed, opens at X" without the Flutter app doing any time calculations itself.</p>
</div>
<div class="cs-feature-card">
<div class="cs-feature-icon">🧭</div>
<h4>Three curated itineraries</h4>
<p>A full day on Tawny Trails, a Brisbane scenic drive and arts highlight, and a creative country walk through Dayboro township. Each itinerary is a custom post type with ordered venue stops, timing estimates, and driving directions between them.</p>
</div>
<div class="cs-feature-card">
<div class="cs-feature-icon">♿</div>
<h4>Accessibility map</h4>
<p>A separate view of the trail focused on accessibility, with notes per venue. Flat access, parking proximity, and facility notes for each venue, stored as ACF fields and exposed through the same REST API.</p>
</div>
</div>
<div class="cs-honest">
<div class="cs-honest-label">Why not a standard map plugin</div>
<p>Standard WordPress map plugins (Google Maps, MapPress, etc.) embed a JavaScript widget on a page. They work fine for a simple business locator. They can't serve a Flutter app, they can't calculate opening hours state, and they can't handle itinerary ordering or accessibility data in a structured way. When a Flutter app needs to consume venue data you need a real REST API, not a plugin that renders HTML. I checked the plugin route first and it doesn't get you there.</p>
</div>
</div>
</section>
<!-- MEMBERSHIP + CONTENT -->
<section class="section section--alt" aria-labelledby="membership-heading">
<div class="container">
<div class="cs-two-col">
<div>
<p class="eyebrow">Platform Features</p>
<h2 id="membership-heading">Membership and content management</h2>
<p class="large">Venue operators log in and manage their own listings. Visitors can purchase trail memberships for extended features. The whole thing runs on PMPro, the same membership engine I use across the other platforms we manage.</p>
<p>My tt-pmpro-extensions plugin bridges PMPro and the access rules specific to TawnyTrails: which membership level gets access to which itinerary, gift certificate handling, and member discount logic for venue bookings.</p>
<div class="cs-feature-grid" style="grid-template-columns:1fr 1fr;margin-top:var(--sp-5);">
<div class="cs-feature-card">
<h4>Tour operator portal</h4>
<p>A dedicated page for tour operators listing group experience options, with booking inquiry forms linked to each operator's contact.</p>
</div>
<div class="cs-feature-card">
<h4>Trail blog</h4>
<p>Regular editorial content about venues, seasonal events, new openings, and trail news. Indexed and surfaced in search.</p>
</div>
<div class="cs-feature-card">
<h4>Gift certificates</h4>
<p>Trail membership gift certificates configured in PMPro. Recipients redeem them at checkout for trail access.</p>
</div>
<div class="cs-feature-card">
<h4>Feature flags</h4>
<p>A feature flag system in tt-api lets us enable or disable features for specific membership levels without a code deploy. It's controlled from the WordPress admin.</p>
</div>
</div>
</div>
<div>
<div style="background:var(--ink-mid);border-radius:var(--r-xl);padding:var(--sp-6);color:var(--white);">
<p class="eyebrow" style="color:rgba(245,158,11,.9);">Custom plugins built</p>
<ul style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:20px;">
<li style="border-bottom:1px solid rgba(255,255,255,.07);padding-bottom:18px;">
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-api</strong>
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Core REST API. Registers CPTs, meta fields, routes, CORS, caching. The Flutter app's entire data layer.</p>
</li>
<li style="border-bottom:1px solid rgba(255,255,255,.07);padding-bottom:18px;">
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-pmpro-extensions</strong>
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Membership access rules specific to TawnyTrails: itinerary gating, gift certificates, operator dashboard access.</p>
</li>
<li style="border-bottom:1px solid rgba(255,255,255,.07);padding-bottom:18px;">
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-event-shortcodes</strong>
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Shortcodes for embedding trail events, seasonal listings, and venue availability in standard WordPress pages.</p>
</li>
<li>
<strong style="color:var(--white);font-size:14px;display:block;margin-bottom:6px;">tt-site-tweaks</strong>
<p style="font-size:13px;color:rgba(255,255,255,.55);margin:0;line-height:1.5;">Performance and display adjustments specific to the trail theme: header overrides, lazy load tuning, schema output.</p>
</li>
</ul>
</div>
</div>
</div>
</div>
</section>
<!-- TECH STACK -->
<section class="section" aria-labelledby="stack-heading">
<div class="container">
<p class="eyebrow">Under the Hood</p>
<h2 id="stack-heading">Full technology stack</h2>
<div class="cs-stack" style="margin-top:var(--sp-4);">
<span class="cs-stack-tag">WordPress 6.x</span>
<span class="cs-stack-tag">PHP 8.4</span>
<span class="cs-stack-tag">MariaDB</span>
<span class="cs-stack-tag">Flutter 3.x</span>
<span class="cs-stack-tag">Dart</span>
<span class="cs-stack-tag">Flutter Web</span>
<span class="cs-stack-tag">REST API (custom)</span>
<span class="cs-stack-tag">Advanced Custom Fields</span>
<span class="cs-stack-tag">PMPro Membership</span>
<span class="cs-stack-tag">Elementor Pro</span>
<span class="cs-stack-tag">Custom CPT (tt_venue)</span>
<span class="cs-stack-tag">Custom CPT (tt_itinerary)</span>
<span class="cs-stack-tag">Redis cache</span>
<span class="cs-stack-tag">CleanTalk spam protection</span>
<span class="cs-stack-tag">DirectAdmin</span>
</div>
<div class="cs-divider"></div>
<div class="cs-honest">
<div class="cs-honest-label">What is still being built</div>
<p>The platform is live and functional. A few pages aren't published yet. Some shortcode driven content sections are still being completed, and the Gift Certificate flow is in draft. The REST API, Flutter app, venue directory, itineraries, and membership system are all fully operational. I'd call this a normal state for a growing platform, not abandoned and not broken.</p>
</div>
</div>
</section>
<!-- CTA -->
<section class="section section--dark" aria-labelledby="cta-heading">
<div class="container">
<div class="cs-cta">
<p class="eyebrow" style="color:rgba(245,158,11,.9);justify-content:center;">What I can build for you</p>
<h2 id="cta-heading">Got a trail, a precinct, or a cluster of venues?</h2>
<p>I can build the same architecture (custom REST API, Flutter PWA, itinerary system, opening hours logic, accessibility map, and membership layer) for any arts trail, tourism precinct, or cluster of venues. The venue count doesn't matter. The complexity doesn't matter. The pattern is proven, because it's already running.</p>
<div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap;">
<a href="../contact.html" class="btn btn-primary">Talk to us about your project</a>
<a href="../index.html#portfolio" class="btn btn-secondary">See more of our work</a>
</div>
</div>
</div>
</section>
<footer class="footer" aria-label="Site footer">
<div class="container">
<div class="footer__grid">
<div class="footer__brand">
<img src="../assets/images/logo-cropped.jpg" alt="HELP4BIS" width="140" height="38">
<p>Managed WordPress hosting and maintenance for Australian small businesses. Brisbane based, personal service, WordPress specialist.</p>
<p style="font-size:13px; color:rgba(255,255,255,.4);">Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</p>
</div>
<div class="footer__col">
<h4>Services</h4>
<ul class="footer__links">
<li><a href="../managed-wordpress.html">Tailored Website Management</a></li>
<li><a href="../care-plans.html">WP Care Plans</a></li>
<li><a href="../sos-fix.html">WP SOS Fix</a></li>
<li><a href="../ai-integration.html">AI Integration</a></li>
<li><a href="../plugin-development.html">Plugin Development</a></li> </ul>
</div>
<div class="footer__col">
<h4>Company</h4>
<ul class="footer__links">
<li><a href="../about.html">About Us</a></li>
<li><a href="../index.html#portfolio">Our Work</a></li>
<li><a href="../index.html#testimonials">Client Feedback</a></li>
<li><a href="../blog/index.html">Blog</a></li>
<li><a href="../contact.html">Contact</a></li>
</ul>
</div>
<div class="footer__col">
<h4>Contact</h4>
<ul class="footer__links">
<li><a href="mailto:project@help4bis.com">project@help4bis.com</a></li>
<li><a href="../contact.html">Submit a Brief</a></li>
<li><a href="../sos-fix.html">Emergency Fix</a></li>
</ul>
<p style="margin-top:1rem; font-size:13px; color:rgba(255,255,255,.4);">Brisbane, Queensland<br>Response within 24 business hours</p>
</div>
</div>
<div class="footer__bottom">
<span>© 2026 HELP4BIS, a trading name of Dutch Digital Dynamics Pty Ltd · ABN 86 081 237 087</span>
<span><a href="../privacy.html">Privacy Policy</a> · <a href="../terms.html">Terms</a></span>
</div>
</div>
</footer>
<button id="back-to-top" aria-label="Back to top" style="position:fixed;bottom:24px;right:24px;width:44px;height:44px;background:var(--red);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .3s ease;box-shadow:var(--shadow-md);">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
</button>
<script src="../assets/js/main.js"></script>
<script src="../analytics/tracker.js" defer></script>
</body>
</html>