feat: add show_in_legal category for bottom bar CMS pages

Add third placement category for content pages that appear in the
bottom bar alongside the copyright notice (Privacy Policy, Terms, etc.):

Model changes:
- Add show_in_legal boolean field to ContentPage model
- Add to to_dict() serialization

Service changes:
- Add legal_only filter to list_pages_for_vendor()

Platform changes:
- Fetch legal_pages in get_platform_context()
- Update base.html to render legal_pages dynamically
- Fallback to hardcoded links if no CMS pages configured

Migration:
- Add column with default=False
- Auto-set show_in_legal=True for privacy and terms pages

Categories:
- show_in_header: Top navigation
- show_in_footer: Quick Links column
- show_in_legal: Bottom bar with copyright (NEW)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-28 20:03:34 +01:00
parent c4ca57e9a0
commit bd447ae7f2
5 changed files with 70 additions and 8 deletions

View File

@@ -47,9 +47,10 @@ def get_platform_context(request: Request, db: Session) -> dict:
# Add i18n globals (_, t, current_language, SUPPORTED_LANGUAGES, etc.)
context.update(i18n_globals)
# Load CMS pages for header and footer navigation
# Load CMS pages for header, footer, and legal navigation
header_pages = []
footer_pages = []
legal_pages = []
try:
# Platform pages have vendor_id=None
header_pages = content_page_service.list_pages_for_vendor(
@@ -58,14 +59,18 @@ def get_platform_context(request: Request, db: Session) -> dict:
footer_pages = content_page_service.list_pages_for_vendor(
db, vendor_id=None, footer_only=True, include_unpublished=False
)
legal_pages = content_page_service.list_pages_for_vendor(
db, vendor_id=None, legal_only=True, include_unpublished=False
)
logger.debug(
f"Loaded CMS pages: {len(header_pages)} header, {len(footer_pages)} footer"
f"Loaded CMS pages: {len(header_pages)} header, {len(footer_pages)} footer, {len(legal_pages)} legal"
)
except Exception as e:
logger.error(f"Failed to load CMS navigation pages: {e}")
context["header_pages"] = header_pages
context["footer_pages"] = footer_pages
context["legal_pages"] = legal_pages
return context

View File

@@ -97,6 +97,7 @@ class ContentPageService:
include_unpublished: bool = False,
footer_only: bool = False,
header_only: bool = False,
legal_only: bool = False,
) -> list[ContentPage]:
"""
List all available pages for a vendor (includes vendor overrides + platform defaults).
@@ -109,6 +110,7 @@ class ContentPageService:
include_unpublished: Include draft pages
footer_only: Only pages marked for footer display
header_only: Only pages marked for header display
legal_only: Only pages marked for legal/bottom bar display
Returns:
List of ContentPage objects
@@ -124,6 +126,9 @@ class ContentPageService:
if header_only:
filters.append(ContentPage.show_in_header == True)
if legal_only:
filters.append(ContentPage.show_in_legal == True)
# Get vendor-specific pages
vendor_pages = []
if vendor_id:

View File

@@ -251,12 +251,21 @@
{{ _("platform.footer.copyright", year=2025) }}
</p>
<div class="flex space-x-6 mt-4 md:mt-0">
<a href="/privacy" class="text-gray-600 dark:text-gray-400 hover:text-primary text-sm transition-colors">
{{ _("platform.footer.privacy") }}
</a>
<a href="/terms" class="text-gray-600 dark:text-gray-400 hover:text-primary text-sm transition-colors">
{{ _("platform.footer.terms") }}
</a>
{% if legal_pages %}
{% for page in legal_pages %}
<a href="/{{ page.slug }}" class="text-gray-600 dark:text-gray-400 hover:text-primary text-sm transition-colors">
{{ page.title }}
</a>
{% endfor %}
{% else %}
{# Fallback to hardcoded links if no CMS pages #}
<a href="/privacy" class="text-gray-600 dark:text-gray-400 hover:text-primary text-sm transition-colors">
{{ _("platform.footer.privacy") }}
</a>
<a href="/terms" class="text-gray-600 dark:text-gray-400 hover:text-primary text-sm transition-colors">
{{ _("platform.footer.terms") }}
</a>
{% endif %}
</div>
</div>
</div>