Do you ever wanted to display a cms plugin content on any page, without having to copy the plugin? Display multiple plugins too?
- Create a new model:
# my_plugin/models.py
from cms.models.pluginmodel import CMSPlugin
class MyPlugin():
...
# the existing cms plugin model that we want to display
class DisplayOneOrMultipleMyPlugins(CMSPlugin):
my_plugins = models.ManyToManyField(to=MyPlugin, limit_choices_to={"placeholder__page__publisher_is_draft": False},)
def copy_relations(self, oldinstance):
self.my_plugins.add(*oldinstance.my_plugins.all())
- Makemigrations & migrate.
- Create a new CMSPlugin (I'll explain the
FakePlugin
thing later):
# my_plugin/cms_plugins.py
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from apps.my_plugin.models import DisplayOneOrMultipleMyPlugins
# There should be your class "MyPluginPublished()" here.
@plugin_pool.register_plugin
class DisplayOneOrMultipleMyPluginsPluginRender(CMSPluginBase):
module = _("My Plugin")
name = _("Display one My Plugin or more.")
model = DisplayOneOrMultipleMyPlugins
render_template = "my_plugin/my_plugins.html"
class FakePlugin():
plugin = None
def __init__(self, plugin): self.plugin = plugin # oneliner rulez!!!!1!
def render(self, context, instance, placeholder):
instances = []
for my_plugin_instance in instance.my_plugins.all():
fake_instance = self.FakePlugin(my_plugin_instance)
instances.append(fake_instance)
context.update({"instances": instances})
return context
- Use this dark magic template to render your plugin:
{% load cms_alias_tags %}
{% for instance in instances %}
{% render_alias_plugin instance %}
{% endfor %}
What's the thing with FakePlugin
?
I've struggled to understand how DjangoCMS works for hours before a colleague pointed me to the right direction. This direction, friends, is this templatetag.
render_alias_plugin
is a function used in the Aliases feature of DjangoCMS (create an "alias" (a copy) of a plugin and display it on multiple pages). It takes an instance
(???), a request
, then searches for the plugin
attribute in the instance
object, and call all the required complicated functions in the right order with the right arguments in order to render the plugin (idk I don't understand the DjangoCMS code no matter how hard I try).
So in order to make the templatetag work I just created a fake class in DisplayOneOrMultipleMyPluginsPluginRender
that has a plugin
attribute, assigned the instance of the plugin we want to display in it, and tried.
Worked first time, after like 5 hours of struggle. 10/10 can recommand.