From 1218ff810e65fac810433c2d1ffcd2bcc83ddd9a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 2 Apr 2026 20:20:13 +0000 Subject: [PATCH 1/4] fix: load header_content_tags not header_logo_tags in picture.html The refactor commit 53cfef6 deleted header_logo_tags.py and moved the header_logo_from_picture tag to header_content_tags.py, but missed updating the {% load %} tag in the djangocms_picture header_logo template. This would cause a TemplateSyntaxError when the Picture plugin is rendered using the 'header_logo' template (e.g. in the header-content placeholder). Co-authored-by: Wesley B --- .../templates/djangocms_picture/header_logo/picture.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taccsite_cms/templates/djangocms_picture/header_logo/picture.html b/taccsite_cms/templates/djangocms_picture/header_logo/picture.html index b0fa4002e..919f259f9 100644 --- a/taccsite_cms/templates/djangocms_picture/header_logo/picture.html +++ b/taccsite_cms/templates/djangocms_picture/header_logo/picture.html @@ -1,3 +1,3 @@ -{% load header_logo_tags %} +{% load header_content_tags %} {% header_logo_from_picture instance picture_link as plugin_logo %} {% include "header_logo.html" with plugin_logo=plugin_logo %} From 83cb8361e43f71b9a6792d132c48215df91a068c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 2 Apr 2026 22:47:11 +0000 Subject: [PATCH 2/4] fix: correct is_picture_plugin check and is_remote detection Two bugs in header_content_tags.py found during testing: 1. is_picture_plugin used getattr(plugin_type, '__name__', '') but get_plugin_instance() returns a plugin class *instance*, not the class itself. The instance has no __name__ attribute, so the check always returned False. Fixed to use type(plugin_type).__name__. 2. is_remote was hardcoded False, causing remote image URLs from the Picture plugin's external_picture/img_src to be passed through {% static %}, mangling the URL. Fixed to detect from img_src. Co-authored-by: Wesley B --- taccsite_cms/templatetags/header_content_tags.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/taccsite_cms/templatetags/header_content_tags.py b/taccsite_cms/templatetags/header_content_tags.py index a8be7b2c6..c609d0c3d 100644 --- a/taccsite_cms/templatetags/header_content_tags.py +++ b/taccsite_cms/templatetags/header_content_tags.py @@ -41,7 +41,7 @@ def _get_header_content_parsed(request, placeholder_name): if len(plugin_list) == 1: first_plugin = plugin_list[0] instance, plugin_type = first_plugin.get_plugin_instance() - is_picture_plugin = getattr(plugin_type, '__name__', '') == 'PicturePlugin' + is_picture_plugin = type(plugin_type).__name__ == 'PicturePlugin' uses_logo_template = getattr(instance, 'template', None) == 'header_logo' if instance and is_picture_plugin: @@ -111,9 +111,10 @@ def header_logo_from_picture(instance, picture_link): alt = attrs.get('alt') or default_alt_text or '' img_src = getattr(instance, 'img_src', None) or '' link_target = getattr(instance, 'link_target', None) + is_remote = img_src.startswith('http://') or img_src.startswith('https://') return { - 'is_remote': False, + 'is_remote': is_remote, 'img_file_src': img_src, 'img_class': '', 'link_href': picture_link or '/', From 418f9bb91b8e9bee062fa82cf31aa040d5b958d3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 2 Apr 2026 23:06:27 +0000 Subject: [PATCH 3/4] fix: use site_id__isnull=True to match CMS-created static placeholders Static placeholders created by {% static_placeholder %} without the 'site' extra bit are stored with site=None (site_id NULL). The previous filter used site=request.site (a Site object), which never matched these placeholders, so get_header_content_parsed always returned no content. Matches the lookup pattern used by CMS's own StaticPlaceholderNode. Co-authored-by: Wesley B --- taccsite_cms/templatetags/header_content_tags.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/taccsite_cms/templatetags/header_content_tags.py b/taccsite_cms/templatetags/header_content_tags.py index c609d0c3d..01ddb1dcf 100644 --- a/taccsite_cms/templatetags/header_content_tags.py +++ b/taccsite_cms/templatetags/header_content_tags.py @@ -20,10 +20,9 @@ def _get_header_content_parsed(request, placeholder_name): logo_link = None remaining_plugins = [] - site = getattr(request, 'site', None) placeholder = StaticPlaceholder.objects.filter( code=placeholder_name, - site=site + site_id__isnull=True ).first() # Return NO content (if placeholder does not exist) From 7249467b3a00c59cbaa32d46e55211be8d653977 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 3 Apr 2026 17:23:14 +0000 Subject: [PATCH 4/4] fix: use {% static_placeholder %} so header-content shows in sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The custom get_header_content_parsed tag queried the DB directly, bypassing the CMS renderer. This meant the CMS never registered the placeholder, so it never appeared in the Structure mode sidebar. Replace the custom DB query in header.html with the standard {% static_placeholder 'header-content' or %}...{% endstatic_placeholder %} pattern (matching footer.html). The 'or' fallback renders the settings-driven logo when the placeholder is empty. Plugin rendering is now handled by djangocms_picture/header_logo/picture.html (already in place), which calls header_logo_from_picture and includes header_logo.html — the same end result, but through the CMS machinery. Also remove the PicturePlugin-only restriction from CMS_PLACEHOLDER_CONF since the custom parsing logic that needed it is gone. Co-authored-by: Wesley B --- taccsite_cms/settings/settings.py | 4 ++-- taccsite_cms/templates/header.html | 18 +++--------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/taccsite_cms/settings/settings.py b/taccsite_cms/settings/settings.py index 5a494768f..4758d380b 100644 --- a/taccsite_cms/settings/settings.py +++ b/taccsite_cms/settings/settings.py @@ -563,8 +563,8 @@ def get_subdirs_as_module_names(path): CMS_PERMISSION = True CMS_PLACEHOLDER_CONF = { 'header-content': { - 'plugins': ['PicturePlugin'], - # One plugin with template "Header logo" = logo; any other content = bottom of header + # One PicturePlugin with template "Header logo" = custom logo + # Any other plugins render inline within the header nav 'limits': {'global': 10}, }, } diff --git a/taccsite_cms/templates/header.html b/taccsite_cms/templates/header.html index 4d48df637..9062397bb 100644 --- a/taccsite_cms/templates/header.html +++ b/taccsite_cms/templates/header.html @@ -1,5 +1,5 @@ {# @var settings #} -{% load cms_tags header_content_tags %} +{% load cms_tags %} {# WARNING: Some markup is duplicated in other repositories #} {# SEE: https://confluence.tacc.utexas.edu/x/LoCnCQ #} @@ -23,13 +23,9 @@ {% endif %} "> - {% get_header_content_parsed "header-content" as header_content %} - {% if header_content.logo_plugin %} - {% header_logo_from_picture header_content.logo_plugin header_content.logo_link as plugin_logo %} - {% include "header_logo.html" with plugin_logo=plugin_logo %} - {% else %} + {% static_placeholder "header-content" or %} {% include "header_logo.html" %} - {% endif %} + {% endstatic_placeholder %}