Repository: django-cms/django-cms

Issue:
Simpler CMS Plugins
For a project I just wrote this base plugin and arguably, it's behavior (not this code) should be the default:

``` python
# -*- coding: utf-8 -*-
from cms.plugin_base import CMSPluginBase, CMSPluginBaseMetaclass
import re

class BasePluginMeta(CMSPluginBaseMetaclass):
    def __new__(cls, name, bases, attrs):
        super_new = super(BasePluginMeta, cls).__new__
        parents = [base for base in bases if isinstance(base, BasePluginMeta)]
        klass = super_new(cls, name, bases, attrs)
        if not parents:
            return klass
        klass.name = re.sub("([a-z])([A-Z])","\g<1> \g<2>", name)
        return klass


class BasePlugin(CMSPluginBase):
    __metaclass__ = BasePluginMeta

    admin_preview = False

    def render(self, context, instance, placeholder):
        context['instance'] = instance
        return context
```

What this does is automatically setting the plugin name to the class name (inserting spaces, so `HelloWorld` becomes `Hello World`. It defines a default render method which just sets the 'instance' variable in the context. And it disables admin preview because admin preview is hardly ever useful.

Note that the code above is a little specific and always applies the name patch, this would obviously be conditional.



Discussion:
Where is the plugin name used? Will it need to be translatable?

No in this case not, and this would only be the default case of course. I don't want to remove the `name` attribute.


Resolving patch:
diff --git a/cms/plugin_base.py b/cms/plugin_base.py
--- a/cms/plugin_base.py
+++ b/cms/plugin_base.py
@@ -1,11 +1,11 @@
 # -*- coding: utf-8 -*-
+import re
 from cms.exceptions import SubClassNeededError, Deprecated
 from cms.models import CMSPlugin
 from django import forms
 from django.conf import settings
 from django.contrib import admin
 from django.core.exceptions import ImproperlyConfigured
-from django.db.models.options import get_verbose_name
 from django.forms.models import ModelForm
 from django.utils.encoding import smart_str
 from django.utils.translation import ugettext_lazy as _
@@ -71,7 +71,7 @@ def __new__(cls, name, bases, attrs):
                 ]
         # Set default name
         if not new_plugin.name:
-            new_plugin.name = get_verbose_name(new_plugin.__name__)
+            new_plugin.name = re.sub("([a-z])([A-Z])","\g<1> \g<2>", name)
         return new_plugin
 
 
@@ -83,7 +83,7 @@ class CMSPluginBase(admin.ModelAdmin):
     form = None
     change_form_template = "admin/cms/page/plugin_change_form.html"
     # Should the plugin be rendered in the admin?
-    admin_preview = True 
+    admin_preview = False
     
     render_template = None
     # Should the plugin be rendered at all, or doesn't it have any output?
@@ -106,8 +106,11 @@ def __init__(self, model=None,  admin_site=None):
         self.placeholder = None
         self.page = None
 
+
     def render(self, context, instance, placeholder):
-        raise NotImplementedError("render needs to be implemented")
+        context['instance'] = instance
+        context['placeholder'] = placeholder
+        return context
     
     @property
     def parent(self):
@@ -223,4 +226,4 @@ def pluginmedia(self):
     def get_plugin_media(self, request, context, plugin):
         raise Deprecated(
             "CMSPluginBase.get_plugin_media is deprecated in favor of django-sekizai"
-        )
\ No newline at end of file
+        )


Test patch:
diff --git a/cms/tests/plugins.py b/cms/tests/plugins.py
--- a/cms/tests/plugins.py
+++ b/cms/tests/plugins.py
@@ -25,6 +25,7 @@
 from cms.test_utils.util.context_managers import SettingsOverride
 from cms.utils.copy_plugins import copy_plugins_to
 from django.conf import settings
+from django.contrib import admin
 from django.contrib.auth.models import User
 from django.core.exceptions import ImproperlyConfigured, ValidationError
 from django.core.files.uploadedfile import SimpleUploadedFile
@@ -999,3 +1000,19 @@ def test_link_or_page(self):
         picture.url = "test"
         self.assertRaises(ValidationError, picture.clean)
 
+
+class SimplePluginTests(TestCase):
+    def test_simple_naming(self):
+        class MyPlugin(CMSPluginBase):
+            render_template = 'base.html'
+        self.assertEqual(MyPlugin.name, 'My Plugin')
+
+    def test_simple_context(self):
+        class MyPlugin(CMSPluginBase):
+            render_template = 'base.html'
+        plugin = MyPlugin(ArticlePluginModel, admin.site)
+        context = {}
+        out_context = plugin.render(context, 1, 2)
+        self.assertEqual(out_context['instance'], 1)
+        self.assertEqual(out_context['placeholder'], 2)
+        self.assertIs(out_context, context)