Skip to content

feat: simpler component configuration #279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 19, 2025
Merged
8 changes: 7 additions & 1 deletion djangocms_frontend/cms_plugins.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from cms.plugin_pool import plugin_pool
from django.core.exceptions import ImproperlyConfigured

from .ui_plugin_base import CMSUIPluginBase

Expand All @@ -11,7 +12,7 @@ def update_plugin_pool():
from .component_pool import components

# Loop through the values in the components' registry
for _, plugin, slot_plugins in components._registry.values():
for key, (_, plugin, slot_plugins) in components._registry.items():
if plugin.__name__ not in plugin_pool.plugins:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): We've found these issues:

# Add the plugin to the global namespace
globals()[plugin.__name__] = plugin
Expand All @@ -24,3 +25,8 @@ def update_plugin_pool():
globals()[slot_plugin.__name__] = slot_plugin
# Register the slot plugin with the plugin pool
plugin_pool.register_plugin(slot_plugin)
else:
raise ImproperlyConfigured(
f"Cannot register frontend component {key} since a plugin {plugin.__name__} "
f"is already registered by {plugin_pool.plugins[plugin.__name__].__module__}."
)
2 changes: 1 addition & 1 deletion djangocms_frontend/component_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def plugin_factory(cls) -> type:
if hasattr(cls, "get_render_template")
else {}
),
"__module__": cls.__module__,
"__module__": "djangocms_frontend.cms_plugins",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Hardcoding module may affect debugging and serialization

Overriding module can break stack traces, pickling, and introspection. Either keep the original module or use qualname to group classes.

Suggested change
"__module__": "djangocms_frontend.cms_plugins",
"__module__": cls.__module__,

},
)
return cls._plugin
Expand Down
19 changes: 14 additions & 5 deletions djangocms_frontend/plugin_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@
"ui_item",
)

allowed_plugin_types = tuple(
getattr(importlib.import_module(cls.rsplit(".", 1)[0]), cls.rsplit(".", 1)[-1]) if isinstance(cls, str) else cls
for cls in getattr(settings, "CMS_COMPONENT_PLUGINS", [])
)


def _get_plugindefaults(instance):
defaults = {
Expand Down Expand Up @@ -65,7 +60,21 @@ def patch_template(template):
return copied_template if patch else template


def get_plugin_class(settings_string: str | type) -> type:
"""Get the plugin class from the settings string or import it if it's a dotted path."""
if isinstance(settings_string, str):
if "." in settings_string:
# import the class if a dotted oath is given
module_name, class_name = settings_string.rsplit(".", 1)
return getattr(importlib.import_module(module_name), class_name, None)
# Get the plugin class from the plugin pool by its name
return plugin_pool.get_plugin(settings_string)
return settings_string


def setup():
allowed_plugin_types = tuple(get_plugin_class(cls) for cls in getattr(settings, "CMS_COMPONENT_PLUGINS", []))

for plugin in plugin_pool.get_all_plugins():
if not issubclass(plugin, allowed_plugin_types):
continue
Expand Down
5 changes: 3 additions & 2 deletions docs/source/how-to/use-frontend-as-component.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ repetition.

To make plugins available as components, ensure that the
``CMS_COMPONENT_PLUGINS`` setting in your project's ``settings.py``
includes the necessary plugin classes and their subclasses. This setting
allows you to specify which plugins can be used directly in templates
is a list that includes the necessary plugin names or dotted path to
a plugin parent class . Only plugins named in the listing or their
child classes can be used directly in templates
without creating database entries.

* To include all ``djangocms-frontend`` plugins, use
Expand Down