← All playbooks · Raw API
location-pages
# Location pages — HopSkipDrive
Playbook for **city / market location pages** at `/drive/{slug}/` (CareDriver geography), backed by the Contentful **`location`** content type — **not** a normal `page` entry.
## URL patterns
| Pattern | Examples |
|---------|----------|
| Location detail | `/drive/los-angeles-ca/`, `/drive/denver-co/` (slug style `{city}-{st}`) |
| CareDriver hub (not a location entry) | `/drive` — use `audience-hubs` |
There are on the order of **~38** location URLs in production. Sitemap paths are `/drive/{slug}/`.
## Content model (important)
| Concept | Value |
|---------|-------|
| Contentful type | **`location`** |
| Public URL | `/drive/{slug}/` |
| Template | **Location page template** (or Denver variant) — required field on the entry |
| Primary editors | Location fields (city, state, hero overrides) + optional alternate content |
cms-edit’s page-centric flows (`--page-slug`, `task-create-page`) target **`page`** entries. For locations:
1. Prefer **`open --id <locationEntryId>`** after looking up the entry in Contentful or via Delivery/index
2. Scalar/RTF fields on the location entry are first-class (`set`, `rtf`, `diff`, `save`)
3. Creating **net-new** markets → `cms-edit://customer/task-create-location` (may still require Contentful UI/CMA if create-from-json does not support `location`) — **do not** fake a `page` with slug `drive/city`
4. JobPosting / hiring schema → `cms-edit://customer/task-location-jobposting-schema`
## Key fields
| Field | Role |
|-------|------|
| `city` | City name (required) |
| `state` | State (required) |
| `slug` | URL segment under `/drive/` |
| `title` | Page title override |
| `breadcrumbTitle` | Breadcrumb label override |
| `description` | SEO description |
| `cities` / `areas` | Extra cities / areas served (areas feed Locations components elsewhere **without** new URLs) |
| `template` | Location page template link |
| `active` | Whether the market is active |
| `heroHeading` / `heroImage` / `specificHeroCopy` | Hero overrides |
| `laptopHeading` / `laptopImage` / `laptopCopy` | Secondary visual/copy overrides |
| `appImage` | App visual |
| `servingHeading` / `servingCopy` | “Serving …” section overrides |
| `alternativeContents` | Alternate page content links for layout variants |
| `structuredData` | Optional override schemas. For optimized JobPosting, link the **shared** schema only |
| `meta` | JSON text merged over the Location template `meta`. Per-metro JobPosting tokens |
Hero **image is required** on the type — always supply a real CMS asset.
## How rendering works (editors)
The site builds a page-like model from the location entry + **template** + fixups (navigation, assets, Mustache schema context with `city` / `state` / `slug` / `areas`). Editors should:
- Change **market-specific** copy and media on the **location** entry
- Leave shared template chrome alone unless product asks for global location layout changes
- Understand that **hub** `/drive` is a separate **page** with its own stack
## Reference locations
| Slug (example) | Use when |
|----------------|----------|
| `los-angeles-ca` | Large market; common verification slug in repo scripts |
| An active mid-size city already published | New markets — clone field patterns (title formula, hero style, areas list) |
Peek via entry id after listing in Contentful. Public check: `https://www.hopskipdrive.com/drive/{slug}/`.
## SEO / schema
- Titles/descriptions should include city + state and CareDriver context
- **Default JobPosting** comes from the shared location **template** schema links
- **Optimized JobPosting** is the **same** schema on every optimized location (`structuredData` → shared optimized schema). Per-metro facts live in location `meta`. The location JobPosting **replaces** the template JobPosting by `@type`
- **Do not clone** a JobPosting per city
- Do **not** invent JSON-LD in free text on components — use Schema entries only
- Current customer policy: **schema-only** (no page-body edits unless product re-opens that)
- Tasks, live inventory, and **periodic hiring-wave updates**: `cms-edit://customer/task-location-jobposting-schema`
- County slugs (`/drive/frederick-county/` etc.) redirect to `/drive/maryland/` — not location entries
### Useful IDs
| Item | ID |
|------|-----|
| Location page template (shared) | `6giibBl8cPHV6rRbTSis2F` |
| Default (short) JobPosting schema | `5YCdby8QnTkiweZuw2y43c` |
| Shared optimized JobPosting schema | `7g1YmIvX07P75e5xXGFVPA` |
## Workflow
### Edit existing location
1. Read this playbook + `cms-edit://customer/task-location-pages`
2. Confirm the slug is a **location** entry, not a marketing page
3. Open by **entry id**; snapshot/read location fields
4. Update city/state/SEO, hero overrides, areas; keep `cmsLabel`s tidy on any linked components
5. If `alternativeContents` are used, edit those linked entries with normal component rules
6. `diff` → `save`
7. Preview path `/drive/{slug}/`
8. `task-publish-handoff`
### Create location / JobPosting
- New market: `cms-edit://customer/task-create-location`
- JobPosting setup or hiring-cycle update: `cms-edit://customer/task-location-jobposting-schema`
## Out of scope
- Editing the **CareDriver marketing hub** `/drive` → `audience-hubs`
- Creating blog posts about cities → `articles`
- Changing global nav Location pickers without checking which Locations collections pull `areas` vs linked entries
- Bypassing `active` / indexing rules without product approval
- Git production branch deploys (SE process; not an editor task)
## Related
- Edit location fields: `cms-edit://customer/task-location-pages`
- Create location: `cms-edit://customer/task-create-location`
- JobPosting schema: `cms-edit://customer/task-location-jobposting-schema`
- CareDriver hub: `cms-edit://customer/audience-hubs`
- General pages: `cms-edit://customer/pages`
- Media upload: `cms-edit://customer/task-media-reuse-and-upload`