feat(cms): CMS-driven homepages, products section, placeholder resolution
Some checks failed
CI / ruff (push) Successful in 11s
CI / pytest (push) Failing after 51m41s
CI / validate (push) Successful in 26s
CI / dependency-scanning (push) Successful in 32s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped

- Add ProductCard/ProductsSection schema and _products.html section macro
- Rewrite seed script with 3-platform homepage sections (wizard, OMS, loyalty),
  platform marketing pages, and store defaults with {{store_name}} placeholders
- Add resolve_placeholders() to ContentPageService for store default pages
- Fix SQLAlchemy filter bugs: replace Python `is None` with `.is_(None)` across
  all ContentPageService query methods (was silently breaking all platform page lookups)
- Remove hardcoded orion fallback and delete homepage-orion.html
- Add placeholder hint box with click-to-copy in admin content page editor
- Export ProductCard/ProductsSection from cms schemas __init__

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 12:12:20 +01:00
parent ef9ea29643
commit adbecd360b
11 changed files with 1132 additions and 916 deletions

View File

@@ -164,46 +164,13 @@ async def homepage(
logger.info(f"[HOMEPAGE] Rendering CMS homepage with template: {template_path}")
return templates.TemplateResponse(template_path, context)
# Fallback: Default orion homepage (no CMS content)
logger.info("[HOMEPAGE] No CMS homepage found, using default orion template")
# Fallback: Default homepage template with placeholder content
logger.info("[HOMEPAGE] No CMS homepage found, using default template with placeholders")
context = get_platform_context(request, db)
context["tiers"] = _get_tiers_data(db)
# Add-ons (hardcoded for now, will come from DB)
context["addons"] = [
{
"code": "domain",
"name": "Custom Domain",
"description": "Use your own domain (mydomain.com)",
"price": 15,
"billing_period": "year",
"icon": "globe",
},
{
"code": "ssl_premium",
"name": "Premium SSL",
"description": "EV certificate for trust badges",
"price": 49,
"billing_period": "year",
"icon": "shield-check",
},
{
"code": "email",
"name": "Email Package",
"description": "Professional email addresses",
"price": 5,
"billing_period": "month",
"icon": "mail",
"options": [
{"quantity": 5, "price": 5},
{"quantity": 10, "price": 9},
{"quantity": 25, "price": 19},
],
},
]
return templates.TemplateResponse(
"cms/platform/homepage-orion.html",
"cms/platform/homepage-default.html",
context,
)

View File

@@ -101,9 +101,17 @@ async def generic_content_page(
},
)
# Resolve placeholders in store default pages ({{store_name}}, etc.)
page_content = page.content
if page.is_store_default and store:
page_content = content_page_service.resolve_placeholders(page.content, store)
context = get_storefront_context(request, db=db, page=page)
context["page_content"] = page_content
return templates.TemplateResponse(
"cms/storefront/content-page.html",
get_storefront_context(request, db=db, page=page),
context,
)