# tools/

## content_index.py

Reads the `content/` source tree (front-matter) as structured data. Its
`load_dates()` builds the article date registry consumed by `seo_inject.py`,
so **adding a post no longer needs a manual `ARTICLE_DATES` edit** — the date
lives in the post's front-matter (`date` / `date_type`). See
`docs/content-model.md`.

## build_site.py

One command to build the whole site from `content/`, in dependency order
(content pages -> listings -> SEO/sitemap -> bot links -> search index). This is
what CI runs before deploying. `--check` verifies without writing; `--images`
also runs image optimisation. Idempotent. See `docs/local-preview.md`.

## build_content.py

Renders the `content/` source files into the blog/news/event detail pages
(`--check` verifies the output matches the current site; `--write` emits pages).
See `docs/content-model.md` and the no-code CMS plan in `docs/plans/`.

## seo_inject.py

Injects a technical-SEO block into every language page (`en|mk|si/**/index.html`)
and regenerates `sitemap.xml` + `robots.txt`. Safe to re-run — the block lives
between `<!-- SEO:START -->` and `<!-- SEO:END -->` and is replaced in place.

The block adds: `meta description` (auto-extracted from the page's lead/subtitle
where available), `canonical`, `hreflang` alternates (en / mk / **sl** / x-default),
Open Graph, Twitter Card, and an Organization JSON-LD.

All absolute URLs point at the **final** domain `https://msosorg.com` (not the
temporary host), so nothing needs rewriting at launch. Note: the Slovene folder
is `/si/` but the ISO code is `sl` — the script maps `si → sl` for hreflang/locale.

### Usage

```sh
python tools/seo_inject.py            # dry run: print the block for pilot pages
python tools/seo_inject.py --all      # write the block into every page
python tools/seo_inject.py --all --sitemap   # also rebuild sitemap.xml + robots.txt
```

Run `--all --sitemap` after adding, renaming, or deleting any page so canonical
tags, hreflang alternates, and the sitemap stay in sync.
