diff --git a/djangocms_frontend/common/__init__.py b/djangocms_frontend/common/__init__.py
index da4c271d..b97aa311 100644
--- a/djangocms_frontend/common/__init__.py
+++ b/djangocms_frontend/common/__init__.py
@@ -24,7 +24,7 @@
module = import_module(f"{__name__}.{settings.framework}.{module}", module)
for cls in classes:
globals()[cls] = getattr(module, cls)
- except ModuleNotFoundError:
+ except ModuleNotFoundError: # pragma: no cover
for cls in classes:
globals()[cls] = type(cls, (object,), {})
diff --git a/djangocms_frontend/component_pool.py b/djangocms_frontend/component_pool.py
index a04d3f5b..943f1cbe 100644
--- a/djangocms_frontend/component_pool.py
+++ b/djangocms_frontend/component_pool.py
@@ -1,7 +1,7 @@
from collections import defaultdict
+from collections.abc import Iterator
import importlib
import os
-from collections.abc import Iterator
import warnings
from django import forms
@@ -15,16 +15,16 @@
from djangocms_frontend.component_base import CMSFrontendComponent
-def find_cms_component_templates() -> list[tuple[str, str]]:
+def find_cms_component_templates(subfolder: str) -> list[tuple[str, str]]:
templates = []
for app in apps.get_app_configs():
- app_template_dir = os.path.join(app.path, "templates", app.label, "cms_components")
+ app_template_dir = os.path.join(app.path, "templates", app.label, subfolder)
if os.path.exists(app_template_dir):
for root, _, files in os.walk(app_template_dir):
for file in files:
if file.endswith(".html") or file.endswith(".htm"):
relative_path = os.path.relpath(os.path.join(root, file), app_template_dir)
- templates.append((app.module.__name__, f"{app.label}/cms_components/{relative_path}"))
+ templates.append((app.module.__name__, f"{app.label}/{subfolder}/{relative_path}"))
return templates
@@ -43,7 +43,7 @@ class CMSAutoComponentDiscovery:
def __init__(self, register_to):
self.default_field_context.update(settings.COMPONENT_FIELDS)
- templates = find_cms_component_templates()
+ templates = find_cms_component_templates(settings.COMPONENT_FOLDER)
auto_components = self.scan_templates_for_component_declaration(templates)
for component in auto_components:
register_to.register(component)
diff --git a/djangocms_frontend/settings.py b/djangocms_frontend/settings.py
index a513e0f4..13bee5b5 100644
--- a/djangocms_frontend/settings.py
+++ b/djangocms_frontend/settings.py
@@ -77,7 +77,7 @@
FORM_OPTIONS = getattr(django_settings, "DJANGOCMS_FRONTEND_FORM_OPTIONS", {})
COMPONENT_FIELDS = getattr(django_settings, "DJANGOCMS_FRONTEND_COMPONENT_FIELDS", {})
-
+COMPONENT_FOLDER = getattr(django_settings, "DJANGOCMS_FRONTEND_COMPONENT_FOLDER", "cms_components")
framework = getattr(django_settings, "DJANGOCMS_FRONTEND_FRAMEWORK", "bootstrap5")
theme = getattr(django_settings, "DJANGOCMS_FRONTEND_THEME", "djangocms_frontend")
diff --git a/djangocms_frontend/templatetags/cms_component.py b/djangocms_frontend/templatetags/cms_component.py
index 149cc72b..5d8869a9 100644
--- a/djangocms_frontend/templatetags/cms_component.py
+++ b/djangocms_frontend/templatetags/cms_component.py
@@ -61,7 +61,7 @@ def _to_tuple_if_needed(value: str) -> str | tuple[str, str]:
value (str): The string to be converted.
Returns:
- str | tuple[str, str]: A tuple containing the two parts of the string if it contains
+ str | tuple[str, str]: A tuple containing the two parts of the string if it contains
a delimiter, otherwise returns the original string.
"""
match = _TUPLE_RE.fullmatch(value)
@@ -82,7 +82,7 @@ def split(value: str, delimiter: str = "|") -> list[str | tuple[str, str]]:
delimiter (str, optional): The delimiter to use for splitting the string. Defaults to "|".
Returns:
- list[str | tuple[str, str]: A list of substrings or 2-tuples obtained by splitting the
+ list[str | tuple[str, str]: A list of substrings or 2-tuples obtained by splitting the
input string using the delimiter.
"""
split_list = value.split(delimiter)
diff --git a/djangocms_frontend/templatetags/frontend.py b/djangocms_frontend/templatetags/frontend.py
index 1535ee08..d72f4acf 100644
--- a/djangocms_frontend/templatetags/frontend.py
+++ b/djangocms_frontend/templatetags/frontend.py
@@ -317,6 +317,7 @@ def render_tag(self, context, instance, attribute, **kwargs):
instance = context.get("instance", None) # Use instance from context
if is_registering_component(context) and attribute:
+ # Autodetect inline field and add it to the component
update_component_properties(context, "frontend_editable_fields", attribute, append=True)
elif is_inline_editing_active(context) and isinstance(instance, CMSPlugin) and instance.pk:
# Only allow inline field to be rendered if inline editing is active and the instance is a CMSPlugin
diff --git a/docs/source/reference.rst b/docs/source/reference.rst
index e7071e67..277f1eb4 100644
--- a/docs/source/reference.rst
+++ b/docs/source/reference.rst
@@ -28,6 +28,24 @@ in your project's ``settings.py``.
]
+.. py:attribute:: settings.DJANGOCMS_FRONTEND_COMPONENT_FOLDER
+
+ Defaults to ``"cms_components"``
+
+ The subfolder where the component templates are discovered. This is used by the
+ :ref:`template components
hello
world
"), "hello
world
") diff --git a/tests/test_app/templates/test_app/cms_components/ui/button.html b/tests/test_app/templates/test_app/cms_components/ui/button.html new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_app/templates/test_app/my_components/test_component.htm b/tests/test_app/templates/test_app/my_components/test_component.htm new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_autocomponent.py b/tests/test_autocomponent.py index ea0d4417..b9abf8c2 100644 --- a/tests/test_autocomponent.py +++ b/tests/test_autocomponent.py @@ -106,3 +106,20 @@ def test_multiple_cms_component_tags_error(self): invalid_template = "{% load cms_tags %}{% cms_component 'Hero' %}{% cms_component 'Footer' %}" with self.assertRaises(TemplateSyntaxError): Template(invalid_template) + + def test_component_folder_selection(self): + from djangocms_frontend.component_pool import find_cms_component_templates + + all_components = find_cms_component_templates("cms_components") + path_components = find_cms_component_templates("cms_components/ui") + private_components = find_cms_component_templates("my_components") + no_components = find_cms_component_templates("no_components") + + assert set(all_components) == { + ("tests.test_app", "test_app/cms_components/hero.html"), + ("tests.test_app", "test_app/cms_components/with_slots.html"), + ("tests.test_app", "test_app/cms_components/ui/button.html"), + } + assert path_components == [("tests.test_app", "test_app/cms_components/ui/button.html")] + assert private_components == [("tests.test_app", "test_app/my_components/test_component.htm")] + assert no_components == []