🔌 Extensions
Extensions add links, buttons and pages to the admin's menu: a link to an external tool, a button that runs your code, or another web application shown inside the admin.
# mysite/studio.py
from content_studio.admin import ContentStudioSite
from content_studio.extensions import IFramePage, MainMenuLink
class BlogStudioSite(ContentStudioSite):
extensions = [
MainMenuLink(
url="https://plausible.io/example.com",
label="Analytics",
icon="ph-bold ph-chart-line",
),
IFramePage(
path="reports/",
iframe_url="https://metabase.example.com/dashboard/1",
),
]
admin_site = BlogStudioSite()
MainMenuLink
A link in the admin's main menu. It takes a url, a label and an icon,
and optionally a color and a weight. The menu orders its links and
buttons by weight, lowest first; with equal weights, which is the default
of 0, they keep their order in extensions.
MainMenuButton
A button in the admin's main menu that runs your code on the server, such as
clearing a cache or starting a deployment. Subclass MainMenuButton and
implement handle(request):
# mysite/studio.py
from django.core.cache import cache
from content_studio.admin import ContentStudioSite
from content_studio.extensions import MainMenuButton
class ClearCacheButton(MainMenuButton):
label = "Clear cache"
icon = "ph-bold ph-broom"
confirm = "Clear the cache for every visitor?"
def is_visible(self, request):
return request.user.is_superuser
def handle(self, request):
cache.clear()
return "The cache is cleared."
class BlogStudioSite(ContentStudioSite):
extensions = [ClearCacheButton()]
admin_site = BlogStudioSite()
label,icon,colorandweight: as forMainMenuLink.confirm: a question to confirm before the button runs.is_visible(request): who sees the button. By default every staff user does. Content Studio checks it again when the button runs.
handle returns what the editor sees: a string as a notification, or a
ButtonResult with a message and a
value that appears once in a dialog with a copy button. The options can
also be passed as arguments, such as ClearCacheButton(label="Empty cache"). Record the changes the button makes with record_change, so they
appear in the objects' history. The webhooks app
ships one ready to use: DeployButton.
IFramePage
A page in the admin that shows another web page in an iframe. path is the
page's address under the admin's URL prefix, iframe_url the page it shows.
The embedded page runs in a sandbox: it can run scripts, keep its origin,
submit forms, open windows and offer downloads, but it cannot navigate the
admin away, show modal dialogs or lock the pointer. The sandbox option
takes another string of
sandbox tokens
to tighten or widen it, or None to embed the page without a sandbox:
IFramePage(
path="reports/",
iframe_url="https://metabase.example.com/dashboard/1",
sandbox="allow-scripts allow-same-origin",
)
You choose the page the iframe shows, so the admin trusts it to that extent:
a page that may navigate the admin or open dialogs needs sandbox=None.
Identity
Each extension gets an ID from its class and its settings, so every worker
of a deployment agrees on it. Two extensions with the same settings need an
explicit extension_id (a UUID) to tell them apart; manage.py check
reports duplicates.