feat: H1 to H2 setting with the admin save conversion (tracer)

- content_h1_to_h2 and generic_anchors on the settings row (migration
  202610280001), Headings and links tab, config key
  golem15.journal.content_h1_to_h2 used when no settings row exists
- classes.ConvertH1 on the x/net/html tokenizer; the Blog Editor types
  convert while the setting is on and answer editor.h1_converted
- GET /posts/{slug} reports content_h1_to_h2 (additive key)
This commit is contained in:
Jakub Zych
2026-11-04 09:44:58 +01:00
parent f7bfb3313b
commit 305f94afd9
15 changed files with 553 additions and 7 deletions

View File

@@ -10,8 +10,10 @@ import (
"time"
"unicode"
"git.golem15.com/golem15/sm-journal-plugin/classes"
"git.golem15.com/golem15/sm-journal-plugin/models"
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/compass"
"git.golem15.com/golem15/summercms/modules/bouncer"
"git.golem15.com/golem15/summercms/modules/cabana"
"git.golem15.com/golem15/summercms/modules/cooler"
@@ -173,6 +175,10 @@ func Show(app *backpack.App) http.HandlerFunc {
rows = append(rows, serializePost(&related[i], db))
}
payload["related_posts"] = rows
// Additive (2026-10-28 Journal H1 setting): whether H1 in post
// content is stored as H2, so a frontend knows whether the page
// title is the only H1.
payload["content_h1_to_h2"] = classes.EffectiveH1ToH2(r.Context(), db, appConfig(app))
wire.WriteJSON(w, http.StatusOK, map[string]any{"data": payload})
}
}
@@ -444,6 +450,14 @@ func UploadFeaturedImage(app *backpack.App) http.HandlerFunc {
}
}
// appConfig is app's config, nil without an application.
func appConfig(app *backpack.App) *compass.Config {
if app == nil {
return nil
}
return app.Config
}
// purgeSiteCache queues the host site's cache purge for post, as the admin
// save hooks do. The API writes run outside a transaction, so the purge is
// queued at once and never delays the response. Without site_cache.purge_url