Something Else

cms-edit · HopSkipDrive

← All playbooks · Raw API

articles

# Articles — HopSkipDrive

## Routing (multi-type)

HopSkipDrive is **not** a single-base blog. Article **types** map to different public URL prefixes. Primary blog is the largest surface (~575 URLs).

| Concept | Value |
|---------|-------|
| Primary articles slug | `blog` |
| Primary public base | `/blog` |
| Tags hub | `/tags` (index) |
| All-types tag listings | `/tags/{slug}/` (Tag chips / View All internals) |
| Blog-only tag listings | `/blog/tag/{slug}/` |
| Primary tag in article URL | **No** — flat article slugs under the type base |
| Article type index pages | **Enabled** (`enableArticleTypeIndex`) |

| Article type slug | Public base (typical) | Notes |
|-------------------|----------------------|--------|
| `blog` | `/blog/{slug}/` | Editorial posts — `generateArticlePage` + template `contentContainer` |
| `clients` | `/clients/…` | Client stories — same blog article template |
| `report` | `/report/…` | Reports — `generateArticlePage` + Article Template container |
| `webinar` | `/webinar/…` | Webinars (index also `/webinars`); dedicated article template (not the index template) |
| `event` | `/event/{slug}/` (index `/events/`) | Events |
| `featured-press-item` | `/featured-press/…` | Press items |
| `caredriver-event` | `/caredriver-events/…` | CareDriver events |
| `newsletter` | type-specific | Newsletter archive items |
| `article-lab` | `/article-lab/{slug}/` (index `/article-labs/`) | **Lab only** — noindex; standard handlers + template `contentContainer` |

Always set **`articleType`** to the correct type before publish. Wrong type → wrong URL family.

**URL freeze:** public path shapes are documented in `docs/family-a-phase2/url-structure.md`. Do not rename live prefixes.

### Target shell (all detail types)

Use **standard** `generateArticlePage` with:

1. Template **`preContent`**: **Article description** shell — renderer binds **title**, **first tag**, and **featured image** from the article (no hardcoded hero text on the template entry).  
2. Template **`contentContainer`** (blog, clients, report) → **Article layout** whose **contents** include:
   - **Share icons** (desktop left)
   - **One related collection** (blog/clients) — desktop right; mobile under body  
   - Article body is **injected** by core  
3. Template **`postContent`** — footer only (e.g. newsletter), **not** related/share. Reports may keep a CTA collection here.

Do **not** add Article description / share / related on the article (`topContent` or `content`) when the template already provides them.

There is **no code fallback** that invents Article description / share / related — they must be in the template (or article content).  

Do **not** add new custom page helpers per type. Webinar **index** template is shared — never put the article hero on it; use a dedicated webinar **article** template.

Read `cms-edit://customer/routing` for pack-generated constants. Markdown access for primary articles: `/blog/{slug}.md` (other types may differ).

### Tags

| Path | Role |
|------|------|
| `/tags/` | Tags hub index |
| `/tags/{slug}/` | **Canonical** tag listing (every article with that tag) |
| `/blog/tag/{slug}/` | Blog-only listing (injected BlogList) |

When linking a Tag entry, the site uses **`/tags/{slug}/`**. Use `/blog/tag/{slug}/` only for blog-scoped indexes.

## Article type vs tags

| Field | Contentful type | Usage |
|-------|-----------------|--------|
| `articleType` | `articleType` | **Required.** Chooses URL family and listing index. |
| `tags` | `tag` (many) | Topics/filters for blog and related content. |
| `authors` / `author` | `person` | Prefer **`authors`** array; see `people` playbook. |

Do not confuse **article type** (blog vs webinar vs report) with **tags** (topic labels).

## Common article components

High-usage types from the CMS audit — see `components-index`:

| Role | Typical type |
|------|----------------|
| Article hero / dek | **Article description** |
| Body | **Blog content** (and related rich-text article body types) |
| Quotes | **Large Quote**, **Small Quote** |
| Share / utility | Site-specific share components on templates |

Prefer cloning a recent article of the **same article type** rather than inventing a new stack.

## Listing and discovery

```bash
cms-edit list --type article --sort date -n 20
cms-edit list --type article --has-field tags
cms-edit list --type tag
cms-edit list --type articleType
```

Articles sort by publication `date`, not `sys.updatedAt`.

## Reading article fields

```bash
cms-edit open --article-slug <slug>
cms-edit read @root
cms-edit read @root tags
cms-edit read @root articleType
```

Use `@root` for the article entry itself (not a content component).

## Setting tags on an article

Tags are an **array of entry links**. Resolve tag slugs to entry IDs first:

```bash
cms-edit list --type tag --json
```

Then open the article and replace the full `tags` array:

```bash
cms-edit open --id <article-entry-id>
cms-edit set @root tags <tagId1>,<tagId2>,<tagId3> --links
cms-edit diff
cms-edit save
```

Use comma-separated **entry IDs** (no spaces). Empty value clears tags: `cms-edit set @root tags --links` with no IDs.

## Creating articles

1. Read `cms-edit://customer/task-create-article` (and this playbook)
2. Confirm **article type** and public URL family
3. Set `title`, `slug`, `date`, `description`, `featuredImage`, `articleType`
4. Build body components; set `cmsLabel` after each add
5. Link `authors` to person entries when bylines are required
6. `diff` → `save` → preview

**Featured images:** Read `cms-edit://customer/defaults` (site default asset when no custom image). Prefer authentic HSD photography already in CMS.

## SEO

- `title` / `description` specific to the piece; include brand terms correctly (CareDriver, RouteWise AI™)
- `featuredImage` for social
- Do not invent safety or outcome statistics — pull from published reports / approved copy

## Publish handoff

`save` creates **drafts only**. Publish in Contentful UI when approved. See `cms-edit://customer/task-publish-handoff`.

## Out of scope

- Marketing **pages** (hubs, offerings, programs) → `pages` / `audience-hubs`
- **Location** city entries → `location-pages`
- Legal documents masquerading as blog posts