GEO: Schema-Slot {{schema_jsonld}} in templates/base.html + render.sh #9

Closed
opened 2026-04-29 13:27:39 +00:00 by mAi · 1 comment
Collaborator

Hintergrund

Guideline: docs/geo-seo-guideline.md (Section 5.1).

Aktuell hat onepager keinen Schema-Markup-Mechanismus. Templated Sites kommen mit Standard-Struktur, Custom Sites werden roh kopiert.

Aufgabe

1. Template-Slot

templates/base.html um Schema-Slot ergänzen:

<head>
  ...
  {{schema_jsonld}}
</head>

2. site.yaml Schema-Block

schema:
  type: Person
  name: "..."
  sameAs:
    - https://msbls.de/
    - https://linkedin.com/in/...

Unterstützte Types: Person, Organization, Article, Product, FAQPage, LocalBusiness.

3. render.sh

Liest schema: Block aus site.yaml und generiert JSON-LD:

<script type="application/ld+json">
{"@context": "https://schema.org", ...}
</script>

Falls schema: fehlt: leerer Slot (kein Tag).

4. Defaults pro Template

Manche Templates können sinnvolle Defaults haben (z.B. person-dark.html → Person-Type). Über templates/<name>.defaults.yaml oder hard-coded — Worker entscheidet.

5. Custom Sites

Für template: custom: Schema muss manuell in index.html eingebaut werden — Template-Slot greift dort nicht. Im Issue-Body Hinweis dokumentieren.

QA

  • ./build.sh durch (59 sites)
  • Min. 3 templated Sites haben gültiges JSON-LD im Output (Schema.org Validator)
  • Custom Sites unverändert
  • Doku: README oder docs/ ergänzen mit Schema-Konvention

Folge-Sites (separate Issues)

Nach Merge: pro kommerzieller / persönlicher Site einen Schema-Block in site.yaml einfügen — ichbinotto, mai-otto, lexsiebels, heygoldi, smartin3, martinsiebels.

Nicht im Scope

  • Custom Sites (separates Issue pro Site).
  • Satire-KI-Sites — bewusst kein Schema (siehe Guideline).

Priorität

p2 — Infrastruktur-Voraussetzung für viele weitere GEO-Schritte.

## Hintergrund Guideline: `docs/geo-seo-guideline.md` (Section 5.1). Aktuell hat onepager keinen Schema-Markup-Mechanismus. Templated Sites kommen mit Standard-Struktur, Custom Sites werden roh kopiert. ## Aufgabe ### 1. Template-Slot `templates/base.html` um Schema-Slot ergänzen: ```html <head> ... {{schema_jsonld}} </head> ``` ### 2. site.yaml Schema-Block ```yaml schema: type: Person name: "..." sameAs: - https://msbls.de/ - https://linkedin.com/in/... ``` Unterstützte Types: Person, Organization, Article, Product, FAQPage, LocalBusiness. ### 3. render.sh Liest `schema:` Block aus site.yaml und generiert JSON-LD: ```html <script type="application/ld+json"> {"@context": "https://schema.org", ...} </script> ``` Falls `schema:` fehlt: leerer Slot (kein Tag). ### 4. Defaults pro Template Manche Templates können sinnvolle Defaults haben (z.B. person-dark.html → Person-Type). Über `templates/<name>.defaults.yaml` oder hard-coded — Worker entscheidet. ### 5. Custom Sites Für `template: custom`: Schema muss manuell in index.html eingebaut werden — Template-Slot greift dort nicht. Im Issue-Body Hinweis dokumentieren. ## QA - ./build.sh durch (59 sites) - Min. 3 templated Sites haben gültiges JSON-LD im Output (Schema.org Validator) - Custom Sites unverändert - Doku: README oder docs/ ergänzen mit Schema-Konvention ## Folge-Sites (separate Issues) Nach Merge: pro kommerzieller / persönlicher Site einen Schema-Block in site.yaml einfügen — ichbinotto, mai-otto, lexsiebels, heygoldi, smartin3, martinsiebels. ## Nicht im Scope - Custom Sites (separates Issue pro Site). - Satire-KI-Sites — bewusst kein Schema (siehe Guideline). ## Priorität p2 — Infrastruktur-Voraussetzung für viele weitere GEO-Schritte.
mAi self-assigned this 2026-04-29 13:27:39 +00:00
Author
Collaborator

Erledigt — Schema-Slot in Templates + render.sh

Branch: mai/hermes/issue-9-geo-schema-slot (push only, head merged)
Commit: 29965c11

Was umgesetzt ist

  1. templates/base.html{{schema_jsonld}} Slot im <head>, direkt nach {{fonts}}.
  2. site.yaml Schema-Block — optional, Form aus dem Issue:
    schema:
      type: Person                # -> @type
      name: "Erika Mustermann"
      url: "https://example.de/"
      jobTitle: "Patentanwältin"
      sameAs:
        - https://www.linkedin.com/in/...
        - https://github.com/...
    
  3. render.sh — liest .schema via yq -o=json, transformiert mit jq (type@type, @context: https://schema.org automatisch), emittiert als <script type="application/ld+json">…</script>. Fehlt schema: → leerer Slot, kein Tag.
  4. Template-Defaults — wenn schema: da ist aber type: fehlt:
    • person-dark, person-lightPerson
    • product-darkProduct
    • editorialArticle
    • fun, minimal → kein Default (type: muss explizit gesetzt werden)
  5. Custom Sites — Slot greift dort nicht. Schema muss manuell in index.html vor </head>. Im README dokumentiert.

Bonus-Fix

Beim Implementieren ist ein latenter Bug in render.sh aufgetaucht: awk gsub interpretiert & im Replacement als matched-text. Das hätte bei künftiger Template-Nutzung &copy; in person-dark.html zu {{body}}copy; korrumpiert. Habe das ganze multiline-Substitutions-Block auf eine literal-string lreplace-Funktion umgestellt — gleiche Logik, keine Sonderzeichen-Interpretation.

QA

  • ./build.sh durchgelaufen (59 sites OK, build/ clean rebuild).
  • Custom Sites: diff sites/<x>/index.html build/<x>/index.html byte-identical für 4 stichprobenartig geprüfte Sites (lexsiebels, orakil, ichbinotto, smartin3). Kein schema_jsonld-Leak in Custom-Output.
  • 3 Test-Fixtures (tests/fixtures/) decken: explizites type: Person, Template-Default Product, Template-Default Article. Vierte Fixture (no-schema.yaml) verifiziert leeren Slot.
  • ./tests/schema-test.sh → 4/4 PASS. JSON-LD ist gültiges JSON, hat @context: https://schema.org, korrekten @type, kein type-Restkey.
  • Beispiel-Output für Person-Fixture (Schema.org-Validator-fähig):
    {"@context":"https://schema.org","@type":"Person","name":"Erika Mustermann","url":"https://example-person.de/","jobTitle":"Patentanwältin","worksFor":{"@type":"Organization","name":"Mustermann & Partner"},"sameAs":["https://www.linkedin.com/in/erika-mustermann/","https://github.com/erika-mustermann"]}
    
    Korrektes & (nicht escaped, JSON-LD-konform — & braucht in JSON-string keine Entity).

Out of Scope (separate Issues)

  • Schema-Blöcke in den 6 kommerziellen/persönlichen Sites (ichbinotto, mai-otto, lexsiebels, heygoldi, smartin3, martinsiebels) — alle aktuell template: custom, müssen handgepflegt werden bzw. erst auf Templates portiert. Folge-Issue.
  • Satire-/KI-Sites: bewusst kein Schema (Guideline-Konsens).

Files

  • templates/base.html (+1 Zeile)
  • render.sh (+ Schema-Block, lreplace-Refactor)
  • README.md (+ Schema.org-Sektion)
  • tests/schema-test.sh + tests/fixtures/*.yaml (neu)
## Erledigt — Schema-Slot in Templates + render.sh **Branch:** `mai/hermes/issue-9-geo-schema-slot` (push only, head merged) **Commit:** [`29965c11`](https://mgit.msbls.de/m/onepager/commit/29965c11647490cd9d0632b08d9134593178ba96) ### Was umgesetzt ist 1. **`templates/base.html`** — `{{schema_jsonld}}` Slot im `<head>`, direkt nach `{{fonts}}`. 2. **`site.yaml` Schema-Block** — optional, Form aus dem Issue: ```yaml schema: type: Person # -> @type name: "Erika Mustermann" url: "https://example.de/" jobTitle: "Patentanwältin" sameAs: - https://www.linkedin.com/in/... - https://github.com/... ``` 3. **`render.sh`** — liest `.schema` via `yq -o=json`, transformiert mit `jq` (`type` → `@type`, `@context: https://schema.org` automatisch), emittiert als `<script type="application/ld+json">…</script>`. Fehlt `schema:` → leerer Slot, kein Tag. 4. **Template-Defaults** — wenn `schema:` da ist aber `type:` fehlt: - `person-dark`, `person-light` → `Person` - `product-dark` → `Product` - `editorial` → `Article` - `fun`, `minimal` → kein Default (`type:` muss explizit gesetzt werden) 5. **Custom Sites** — Slot greift dort nicht. Schema muss manuell in `index.html` vor `</head>`. Im README dokumentiert. ### Bonus-Fix Beim Implementieren ist ein latenter Bug in `render.sh` aufgetaucht: `awk gsub` interpretiert `&` im Replacement als matched-text. Das hätte bei künftiger Template-Nutzung `&copy;` in `person-dark.html` zu `{{body}}copy;` korrumpiert. Habe das ganze multiline-Substitutions-Block auf eine literal-string `lreplace`-Funktion umgestellt — gleiche Logik, keine Sonderzeichen-Interpretation. ### QA - `./build.sh` durchgelaufen (59 sites OK, `build/` clean rebuild). - Custom Sites: `diff sites/<x>/index.html build/<x>/index.html` byte-identical für 4 stichprobenartig geprüfte Sites (lexsiebels, orakil, ichbinotto, smartin3). Kein `schema_jsonld`-Leak in Custom-Output. - 3 Test-Fixtures (`tests/fixtures/`) decken: explizites `type: Person`, Template-Default `Product`, Template-Default `Article`. Vierte Fixture (`no-schema.yaml`) verifiziert leeren Slot. - `./tests/schema-test.sh` → 4/4 PASS. JSON-LD ist gültiges JSON, hat `@context: https://schema.org`, korrekten `@type`, kein `type`-Restkey. - Beispiel-Output für Person-Fixture (Schema.org-Validator-fähig): ```json {"@context":"https://schema.org","@type":"Person","name":"Erika Mustermann","url":"https://example-person.de/","jobTitle":"Patentanwältin","worksFor":{"@type":"Organization","name":"Mustermann & Partner"},"sameAs":["https://www.linkedin.com/in/erika-mustermann/","https://github.com/erika-mustermann"]} ``` Korrektes `&` (nicht escaped, JSON-LD-konform — `&` braucht in JSON-string keine Entity). ### Out of Scope (separate Issues) - Schema-Blöcke in den 6 kommerziellen/persönlichen Sites (ichbinotto, mai-otto, lexsiebels, heygoldi, smartin3, martinsiebels) — alle aktuell `template: custom`, müssen handgepflegt werden bzw. erst auf Templates portiert. Folge-Issue. - Satire-/KI-Sites: bewusst kein Schema (Guideline-Konsens). ### Files - `templates/base.html` (+1 Zeile) - `render.sh` (+ Schema-Block, lreplace-Refactor) - `README.md` (+ Schema.org-Sektion) - `tests/schema-test.sh` + `tests/fixtures/*.yaml` (neu)
mAi added the
needs-review
label 2026-04-30 00:50:55 +00:00
m closed this issue 2026-04-30 00:53:34 +00:00
mAi added
done
and removed
needs-review
labels 2026-04-30 14:28:46 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/onepager#9
No description provided.