diff --git a/doc/development/api/plugins.rst b/doc/development/api/plugins.rst
index a03e83b1d2..e87eb01b48 100644
--- a/doc/development/api/plugins.rst
+++ b/doc/development/api/plugins.rst
@@ -46,6 +46,9 @@ name string The human-readable name of your plugin
author string Your name
version string A human-readable version code of your plugin
description string A more verbose description of what your plugin does.
+category string Category of a plugin. Either one of ``"FEATURE"``, ``"PAYMENT"``,
+ ``"INTEGRATION"``, ``"CUSTOMIZATION"``, ``"FORMATS"``, or ``"API"``,
+ or any other string.
visible boolean (optional) ``True`` by default, can hide a plugin so it cannot be normally activated.
restricted boolean (optional) ``False`` by default, restricts a plugin such that it can only be enabled
for an event by system administrators / superusers.
@@ -69,6 +72,7 @@ A working example would be::
name = _("PayPal")
author = _("the pretix team")
version = '1.0.0'
+ category = 'PAYMENT
visible = True
restricted = False
description = _("This plugin allows you to receive payments via PayPal")
diff --git a/src/pretix/control/templates/pretixcontrol/event/plugins.html b/src/pretix/control/templates/pretixcontrol/event/plugins.html
index af877d3bed..2a4d317b57 100644
--- a/src/pretix/control/templates/pretixcontrol/event/plugins.html
+++ b/src/pretix/control/templates/pretixcontrol/event/plugins.html
@@ -10,62 +10,75 @@
{% trans "Your changes have been saved." %}
{% endif %}
-
-
- {% for plugin in plugins %}
-
-
- {{ plugin.name }}
- {% if plugin.author %}
-
{% blocktrans trimmed with v=plugin.version a=plugin.author %}
- Version {{ v }} by {{ a }}
- {% endblocktrans %}
- {% else %}
-
{% blocktrans trimmed with v=plugin.version a=plugin.author %}
- Version {{ v }}
- {% endblocktrans %}
- {% endif %}
-
{{ plugin.description }}
- {% if plugin.restricted and not request.user.is_staff %}
-
- {% trans "This plugin needs to be enabled by a system administrator for your event." %}
-
- {% endif %}
- {% if plugin.app.compatibility_errors %}
-
- {% trans "This plugin cannot be enabled for the following reasons:" %}
-
- {% for e in plugin.app.compatibility_errors %}
-
{{ e }}
- {% endfor %}
-
-
- {% endif %}
- {% if plugin.app.compatibility_warnings %}
-
- {% trans "This plugin reports the following problems:" %}
-
- {% for e in plugin.app.compatibility_warnings %}
-
{{ e }}
- {% endfor %}
-
-
- {% endif %}
-
-
- {% if plugin.app.compatibility_errors %}
-
- {% elif plugin.restricted and not staff_session %}
-
- {% elif plugin.module in plugins_active %}
-
- {% else %}
-
- {% endif %}
-
-
- {% endfor %}
-
+
+ {% for cat, catlabel, plist in plugins %}
+
+ {% endfor %}
{% endblock %}
diff --git a/src/pretix/control/views/event.py b/src/pretix/control/views/event.py
index 0ba94f3793..ffe5da72c5 100644
--- a/src/pretix/control/views/event.py
+++ b/src/pretix/control/views/event.py
@@ -2,6 +2,7 @@ import json
import re
from collections import OrderedDict
from decimal import Decimal
+from itertools import groupby
from urllib.parse import urlsplit
from django.conf import settings
@@ -213,8 +214,32 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
from pretix.base.plugins import get_all_plugins
context = super().get_context_data(*args, **kwargs)
- context['plugins'] = [p for p in get_all_plugins(self.object) if not p.name.startswith('.')
- and getattr(p, 'visible', True)]
+ plugins = [p for p in get_all_plugins(self.object) if not p.name.startswith('.')
+ and getattr(p, 'visible', True)]
+ order = [
+ 'FEATURE',
+ 'PAYMENT',
+ 'INTEGRATION',
+ 'CUSTOMIZATION',
+ 'FORMATS',
+ 'API',
+ ]
+ labels = {
+ 'FEATURE': _('Features'),
+ 'PAYMENT': _('Payment providers'),
+ 'INTEGRATION': _('Integrations'),
+ 'CUSTOMIZATION': _('Customizations'),
+ 'FORMATS': _('Output and export formats'),
+ 'API': _('API features'),
+ }
+ context['plugins'] = sorted([
+ (c, labels.get(c, c), list(plist))
+ for c, plist
+ in groupby(
+ sorted(plugins, key=lambda p: str(getattr(p, 'category', _('Other')))),
+ lambda p: str(getattr(p, 'category', _('Other')))
+ )
+ ], key=lambda c: (order.index(c[0]), c[1]) if c[0] in order else (999, str(c[1])))
context['plugins_active'] = self.object.get_plugins()
return context
diff --git a/src/pretix/plugins/badges/__init__.py b/src/pretix/plugins/badges/__init__.py
index 2f1b9d439f..7084c8a734 100644
--- a/src/pretix/plugins/badges/__init__.py
+++ b/src/pretix/plugins/badges/__init__.py
@@ -12,6 +12,7 @@ class BadgesApp(AppConfig):
name = _("Badges")
author = _("the pretix team")
version = version
+ category = "FEATURE"
description = _("This plugin allows you to generate badges or name tags for your attendees.")
def ready(self):
diff --git a/src/pretix/plugins/banktransfer/__init__.py b/src/pretix/plugins/banktransfer/__init__.py
index 9dff72ae30..3525335fc9 100644
--- a/src/pretix/plugins/banktransfer/__init__.py
+++ b/src/pretix/plugins/banktransfer/__init__.py
@@ -12,6 +12,7 @@ class BankTransferApp(AppConfig):
class PretixPluginMeta:
name = _("Bank transfer")
author = _("the pretix team")
+ category = 'PAYMENT'
version = version
description = _("This plugin allows you to receive payments " +
"via bank transfer ")
diff --git a/src/pretix/plugins/manualpayment/__init__.py b/src/pretix/plugins/manualpayment/__init__.py
index 78fbb89ec4..8cbb29667a 100644
--- a/src/pretix/plugins/manualpayment/__init__.py
+++ b/src/pretix/plugins/manualpayment/__init__.py
@@ -12,6 +12,7 @@ class ManualPaymentApp(AppConfig):
name = _("Manual payment")
author = _("the pretix team")
version = version
+ category = 'PAYMENT'
description = _("This plugin adds a customizable payment method for manual processing.")
diff --git a/src/pretix/plugins/paypal/__init__.py b/src/pretix/plugins/paypal/__init__.py
index f5c656cbd1..1b7ba11711 100644
--- a/src/pretix/plugins/paypal/__init__.py
+++ b/src/pretix/plugins/paypal/__init__.py
@@ -13,6 +13,7 @@ class PaypalApp(AppConfig):
name = _("PayPal")
author = _("the pretix team")
version = version
+ category = 'PAYMENT'
description = _("This plugin allows you to receive payments via PayPal")
def ready(self):
diff --git a/src/pretix/plugins/pretixdroid/__init__.py b/src/pretix/plugins/pretixdroid/__init__.py
index 8557d27e75..3018f6c605 100644
--- a/src/pretix/plugins/pretixdroid/__init__.py
+++ b/src/pretix/plugins/pretixdroid/__init__.py
@@ -13,6 +13,7 @@ class PretixdroidApp(AppConfig):
author = _("the pretix team")
version = version
visible = True
+ category = 'INTEGRATION'
description = _("This plugin allows you to use the pretixdroid and pretixdesk apps for your event.")
def ready(self):
diff --git a/src/pretix/plugins/reports/__init__.py b/src/pretix/plugins/reports/__init__.py
index 1ac33c1316..4ff1f0a98a 100644
--- a/src/pretix/plugins/reports/__init__.py
+++ b/src/pretix/plugins/reports/__init__.py
@@ -13,6 +13,7 @@ class ReportsApp(AppConfig):
name = _("Report exporter")
author = _("the pretix team")
version = version
+ category = 'FORMATS'
description = _("This plugin allows you to generate printable reports about your sales.")
def ready(self):
diff --git a/src/pretix/plugins/returnurl/__init__.py b/src/pretix/plugins/returnurl/__init__.py
index 37326ad619..a17d17b0a2 100644
--- a/src/pretix/plugins/returnurl/__init__.py
+++ b/src/pretix/plugins/returnurl/__init__.py
@@ -12,6 +12,7 @@ class ReturnURLApp(AppConfig):
name = _("Redirection from order page")
author = _("the pretix team")
version = version
+ category = 'API'
description = _("This plugin allows to link to payments and redirect back afterwards. This is useful in "
"combination with our API.")
diff --git a/src/pretix/plugins/sendmail/__init__.py b/src/pretix/plugins/sendmail/__init__.py
index 4854858aef..36b2c85cac 100644
--- a/src/pretix/plugins/sendmail/__init__.py
+++ b/src/pretix/plugins/sendmail/__init__.py
@@ -11,6 +11,7 @@ class SendMailApp(AppConfig):
class PretixPluginMeta:
name = _("Send out emails")
author = _("the pretix team")
+ category = 'FEATURE'
version = version
description = _("This plugin allows you to send out emails " +
"to all your customers.")
diff --git a/src/pretix/plugins/statistics/__init__.py b/src/pretix/plugins/statistics/__init__.py
index c0aa494971..eb7d476351 100644
--- a/src/pretix/plugins/statistics/__init__.py
+++ b/src/pretix/plugins/statistics/__init__.py
@@ -12,6 +12,7 @@ class StatisticsApp(AppConfig):
name = _("Statistics")
author = _("the pretix team")
version = version
+ category = 'FEATURE'
description = _("This plugin shows you various statistics.")
def ready(self):
diff --git a/src/pretix/plugins/stripe/__init__.py b/src/pretix/plugins/stripe/__init__.py
index 4022c3e566..dd5075b8b1 100644
--- a/src/pretix/plugins/stripe/__init__.py
+++ b/src/pretix/plugins/stripe/__init__.py
@@ -13,6 +13,7 @@ class StripeApp(AppConfig):
name = _("Stripe")
author = _("the pretix team")
version = version
+ category = 'PAYMENT'
description = _("This plugin allows you to receive credit card payments " +
"via Stripe")
diff --git a/src/pretix/plugins/ticketoutputpdf/__init__.py b/src/pretix/plugins/ticketoutputpdf/__init__.py
index c4fac374db..a5e659f2f8 100644
--- a/src/pretix/plugins/ticketoutputpdf/__init__.py
+++ b/src/pretix/plugins/ticketoutputpdf/__init__.py
@@ -13,6 +13,7 @@ class TicketOutputPdfApp(AppConfig):
name = _("PDF ticket output")
author = _("the pretix team")
version = version
+ category = 'FORMATS'
description = _("This plugin allows you to print out tickets as PDF files")
def ready(self):