# 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`  
