Skip to content

Theme Local Services — Improvement & Growth Plan

Package: capell-app/theme-local-services · Kind: theme · Tier: premium · Product group: Capell Themes · Bundle: themes · Status: Complete

LocalServicesThemeServiceProvider registers theme key local-services (src/LocalServicesThemeServiceProvider.php), with the layout view capell-theme-local-services::page (resources/views/page.blade.php — a token-bound shell + skip link that echoes pre-rendered $content) and 19 package-owned section views under resources/views/sections/ (hero, features, services, service-packages, service-areas, locality-proof, proof, reviews-testimonials, trust-badges, opening-hours, structured-data, content-listing, quote-form, quote-estimator, case-studies, before-after-gallery, resources, contact, cta — navigation + footer are deliberately inherited from foundation, returned as null by isFoundationSection()). The demo command capell:theme-local-services-demo exists and delegates to InstallLocalServicesThemeDemoActionThemeDemoPageInstaller; DemoCommandTest proves it installs ≥7 demo pages idempotently. Optional quote-form/quote-estimator (Form Builder/Bookings) and resources (Blog) sections are guarded via ViewSectionRenderer extra view data with static fallbacks. The marketplace summary/Composer description now use buyer-facing quote-request, service-area, and click-to-call positioning. Health checks verify provider, package file, manifest, and screenshot boundaries. Screenshots: capell.json marketplace.screenshots promotes 4 committed assets (extension-card plus homepage, service-area, and quote-form route captures). docs/screenshots.json declares 9 required PNG captures, all committed under docs/screenshots/.

  • 2026-06-03: Rewrote marketplace/Composer copy, replaced the critical health-check stub with real diagnostics, and documented the intentional split between runtime extends: default and manifest dependency extends: capell-app/foundation-theme.
  • 2026-06-04: Moved service-area defaults into translations, made service-area cards data-driven from section render data, added the default contact anchor, removed dead href="#" links, added fallback/custom render coverage, and hardened manifest tests.
  • 2026-06-05: Replaced the decorative quote-form fallback with a real translated public form, added configurable formAction/formMethod support, and covered fallback/custom render paths in tests.
  • 2026-06-05: Added data-driven contact actions with safe tel:, mailto:, address, and map rendering, translated static fallback states, and focused public render coverage.
  • 2026-06-06: Replaced the 3 SVG marketplace layout diagrams with Capell runner PNG captures and fulfilled the 9-entry docs/screenshots.json contract.
  • 2026-06-07: Added hydrated trust/accreditation badge and before/after gallery sections with translated fallbacks, image attributes, public-output safety checks, and anonymous render-budget coverage.
  • 2026-06-07: Added a handle-gated Form Builder quote-form embed, Bookings handoff CTA, and scoped dark-mode shell tokens with contrast-safe overrides for existing section utilities.
  1. Shipped 2026-06-05: Replace decorative quote-form with a real fallback formquote-form.blade.php now renders a public <form> with translated name, phone, postcode, service, and message fields, a configurable formAction/formMethod, and a default /contact POST target. Focused render tests cover default and hydrated submission targets plus public-output safety. — converts the primary CTA from theatre to function — resources/views/sections/quote-form.blade.php — M
  2. Shipped 2026-06-04: Fix dead service-area links + hardcoded districtsservice-areas.blade.php now renders translated default areas or $section->items entries with label/title/name, url, and optional postcode/postcodePrefix. Empty data renders a translated empty state, real URLs render anchors, default areas point to the contact section anchor, and no-URL entries render static labels. — fixes broken links + i18n on a core local-SEO section — resources/views/sections/service-areas.blade.php — S
  3. Shipped 2026-06-07: dark-mode system — the theme now has scoped .dark .local-services-shell, .local-services-shell.dark, and prefers-color-scheme: dark token layers, with card, field, border, background, and text overrides for existing section utility colours. — prevents partial dark UA styling and keeps the premium theme coherent in dark contexts — resources/css/theme-local-services.css — M
  4. Shipped 2026-06-07: decide and standardise the Tailwind tw: prefix — theme package Blade stays unprefixed because it is compiled through isolated package tailwindImport/tailwindSource assets rather than the host store frontend bundle; a source guard pins that exemption. — prevents class collisions / aligns with house rule — all resources/views/**/*.blade.php — L
  5. Shipped 2026-06-06: hydrate hero image as the LCP element — hero media now resolves informative alt text from hydrated media/image alt, heading, or a translated fallback; emits width/height from render data with stable 1600×1000 defaults; and marks the above-fold image as eager, async decoded, and fetchpriority="high". — improves LCP/CLS and a11y on the money page — resources/views/sections/hero.blade.php, resources/lang/en/generic.php — S
  6. Shipped 2026-06-06: remaining literal section defaults moved to translations — services, case studies, proof metrics, and resources now source fallback cards plus repeated labels from resources/lang/en/generic.php instead of hard-coded English in Blade PHP blocks. — completes translation coverage already started elsewhere — services.blade.php, case-studies.blade.php, proof.blade.php, resources.blade.php, resources/lang/en/generic.php — S
  7. Radius/border consistency accepted for current theme scope. — The shell dark-mode/token slice now normalizes card, field, border, background, and text treatment across the theme. A deeper single-token radius sweep would be visual polish, not an active roadmap blocker. — resources/css/theme-local-services.css + section views — Done

capabilities[] is only ["theme-local-services","theme-local-services-frontend"] because this package is a renderer-only theme. Against a local-services site, the table-stakes renderer surfaces are now present:

  • Shipped 2026-06-07: LocalBusiness structured data (JSON-LD)structured-data renders LocalBusiness, Service, OfferCatalog, FAQPage, and opening-hours JSON-LD from hydrated render data. Differentiator.
  • Shipped 2026-06-05: Click-to-call / contact actions — the contact section now renders hydrated phone, email, address, and map data as real safe links where possible, with translated non-clickable states when data is missing or unsafe. Mobile local-services traffic is call-driven. Table stakes.
  • Shipped 2026-06-07: Opening hours sectionopening-hours renders hydrated hours and an optional open/closed-now state. Table stakes for trades/salon/clinic.
  • Shipped 2026-06-07: Reviews / testimonialsreviews-testimonials renders quote/star/source testimonial cards from hydrated data. Table stakes (trust).
  • Shipped 2026-06-07: Trust / accreditation badgestrust-badges renders Gas Safe / NICEIC / DBS / insurance / guarantee-style credentials from hydrated data. Differentiator for trades verticals.
  • Shipped 2026-06-07: Before/after gallerybefore-after-gallery renders image-pair project proof with service and location context. Differentiator.
  • FAQ schema shipped 2026-06-07structured-data supports FAQPage JSON-LD from hydrated faqs; a visible FAQ section can still be added as optional future content depth. Table stakes.
  • Shipped 2026-06-07: Cross-sell hooksquote-form now has a handle-gated Form Builder embed branch and a Bookings handoff CTA when the Bookings package is installed and a booking URL/route is available. Blog resources integration remains a static/copy-aware fallback. Tie future visible package support to supports[] when those dependencies become first-class theme install recommendations.
  • Local SEO depth: JSON-LD, service-area content, address/map/contact actions, and NAP-style content can now render from hydrated data. Dedicated per-area landing generation and SEO Suite hooks remain future package depth.
  • Dual extends meaning is documented, but should stay tested — capell.json declares the package dependency ("extends": "capell-app/foundation-theme") while definition() uses the Theme Studio runtime inheritance key (extends: 'default'). The provider now documents the distinction; keep tests around both boundaries so this does not regress. — src/LocalServicesThemeServiceProvider.php, capell.json, tests/Unit/LocalServicesThemeDefinitionTest.php
  • Health check shipped, keep expanding diagnostics as the package growsThemeLocalServicesHealthCheck now verifies provider, package file, manifest, and screenshot boundaries. Add any future sections/assets to those diagnostics instead of letting the critical check drift back into a shallow compatibility-only assertion. — src/Health/ThemeLocalServicesHealthCheck.php, capell.json
  • Surfaces aligned.capell.json declares ["frontend", "console"], matching the README/overview and demo command surface. — capell.json, README.md
  • Shipped 2026-06-06: screenshot contract fulfilled — 9 declared PNG capture paths now exist under docs/screenshots/, each with runner fixture URL metadata. — docs/screenshots.json
  • Shipped 2026-06-06: marketplace SVG placeholders replaced — the 3 hand-drawn .svg layout diagrams have been removed from the marketplace gallery and replaced with real Capell runner PNG captures for homepage, service-area, and quote-form workflows. — capell.json, docs/screenshots/
  • WCAG: hero/quote/cta/proof contain many aria-hidden decorative bar-charts (acceptable), service-area cards now avoid dead anchors, hero media has an informative translated alt fallback, and the carousel prev/next buttons are hidden by default with no documented JS to reveal them (data-carousel-* hooks present, no shipped controller in package). — service-areas.blade.php, proof.blade.php, services.blade.php, case-studies.blade.php, resources.blade.php
  • Carousel JS provenance — every carousel relies on data-carousel/data-carousel-track/data-carousel-prev/next and .theme-carousel-button but the package ships no JS; it assumes foundation-theme provides it. If foundation drops it, every carousel silently degrades to an overflow-scroll with invisible buttons. Document the dependency and add a render/no-JS test. — resources/views/sections/* (all carousels)
  • Public-output safety: good. PublicOutputSafetyTest asserts no DB calls / no admin metadata in Blade + lang, and views echo pre-rendered $content with no queries — compliant with the public-output rule. Keep this guard and extend it to any new section.
  • Performance budget covered. — Manifest frontendRenderBudgetMs: 20, adminQueryBudget: 0, and no-query public rendering are covered by anonymous per-section render tests. — capell.json, tests/Unit/LocalServicesThemeDefinitionTest.php
  • Anonymous render coverage shipped. — Local Services-owned sections render anonymously with public-output safety and zero select-query coverage; foundation-owned navigation/footer remain inherited. — tests/Unit/LocalServicesThemeDefinitionTest.php, tests/Unit/PublicOutputSafetyTest.php

The manifest and Composer description now use this buyer-facing 1-sentence summary:

A conversion-first Capell theme for local trades, clinics, and service businesses — built around quote requests, service-area coverage, and click-to-call trust.

The manifest marketplace description now uses this buyer-facing product story:

Theme Local Services turns visitors into booked jobs. It ships hero, services, service-area, locality-proof, quote-estimator, case-study, and contact sections tuned for plumbers, electricians, salons, cleaners, and clinics, with a teal/amber palette and a quote desk front-and-centre. Optional Form Builder and Blog integrations upgrade the enquiry form and resources feed when those packages are installed, and the theme inherits foundation navigation, footer, and SEO. Drop in your services and coverage areas and launch a credible local-business site in minutes.

Media status: The 3 SVG placeholder diagrams have been replaced with route-backed PNG captures, and the 9-entry docs/screenshots.json capture plan is fulfilled. Remaining media depth is optional polish: add a darker theme variation and mobile-specific marketplace crops if marketplace media needs more variation.

Differentiation / target buyer: Among the 10 sibling themes (theme-agency, -commerce, -corporate, -education, -healthcare, -knowledge, -nonprofit, -portfolio, -saas), this is the only lead-capture / quote-led theme. Target buyer: a solo-operator or small local trade/services business (or the agency building for them) that needs phone calls and quote forms, not a brochure. Lean into the quote-desk + coverage + trust story to separate from theme-corporate/theme-agency.

Completed 2026-06-07. Every prioritized roadmap row is closed. Theme Local Services now has aligned frontend/console surfaces, buyer-facing marketplace copy, route-backed captures, health diagnostics, public quote form/Form Builder/Bookings branches, click-to-call/contact/map output, structured data, reviews, opening hours, trust badges, before/after gallery, translations, LCP image hints, dark tokens, Tailwind-prefix exemption coverage, anonymous per-section render/no-query guards, and dual-extends tests.

Keywords/tags: local business, trades, plumber, electrician, salon, cleaner, quote form, service area, click to call, lead generation, local SEO, LocalBusiness schema.

ItemBucketEffortImpactSection ref
Replace decorative quote-form with a real fallback <form>DoneMHigh§2.1 — closed 2026-06-05: fallback quote form now renders translated name/phone/postcode/service/message fields with configurable submission target.
Add click-to-call / address / map to contact sectionDoneMHigh§3 — closed 2026-06-05: contact cards now render safe tel:, mailto:, address, and map links from hydrated section data with translated static fallbacks.
Fix surfaces mismatch (manifest vs README)DoneSLow§4 — closed 2026-06-05: capell.json now declares both frontend and console, matching the README and demo command surface.
Remove orphan dark-mode utilitiesDoneMMed§2.3 — closed 2026-06-07: scoped shell dark tokens now cover card, field, border, background, and text utilities across the theme.
Add LocalBusiness + Service + FAQPage JSON-LD (render-data driven)DoneMHigh§3 — closed 2026-06-07: structured-data renders LocalBusiness, Service, OfferCatalog, FAQPage, and opening-hours JSON-LD from hydrated section data only.
Add reviews/testimonials section + lang keysDoneMHigh§3 — closed 2026-06-07: reviews-testimonials ships translated headings, rating labels, empty state, and hydrated review card rendering.
Add opening-hours section (“open now”)DoneMMed§3 — closed 2026-06-07: opening-hours renders hydrated hours, by-request fallback copy, and optional open/closed-now status.
Move remaining literal English to generic.php lang fileDoneSMed§2.6
Hero image LCP/CLS + required altDoneSMed§2.5
Resolve tw: prefix convention question across all viewsDoneSMed§2.4 — closed 2026-06-07: theme package Blade stays unprefixed because it is compiled through isolated tailwindImport/tailwindSource package assets; a source guard pins that exemption.
Replace SVG placeholders with real screenshots; fulfil/prune screenshots.jsonDoneMHigh§4, §5 — closed 2026-06-06: 9 route-backed PNG captures are committed and marketplace SVG diagrams were replaced with real workflow screenshots.
Add anonymous render test per section + 0-query/20ms budget guardDoneMMed§4 — closed 2026-06-07: every Local Services-owned section renders anonymously under the manifest frontend budget with zero select queries.
Add trust/accreditation badge strip + before/after gallery sectionsDoneMMed§3 — closed 2026-06-07: trust-badges and before-after-gallery render hydrated credentials and image-pair project proof with translated empty states and public-output coverage.
Real Form Builder / Bookings embed in quote-form (cross-sell) + dark-mode systemDoneLHigh§3, §2.3 — closed 2026-06-07: quote-form supports handle-gated Form Builder embedding, Bookings handoff CTAs, and scoped shell dark-mode tokens with test coverage.
Shipped 2026-06-06: Keep dual extends semantics explicitly covered by testsDoneSMed§4 — ManifestRequirementsTest pins manifest dependency capell-app/foundation-theme, LocalServicesThemeDefinitionTest pins runtime extends: default, and the provider documents the split.