-
-
Notifications
You must be signed in to change notification settings - Fork 176
Adds docs for creating custom control panel #1909
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
base: 6.0
Are you sure you want to change the base?
Changes from 8 commits
420759b
f1b16b2
277d4f2
ac4c3ce
10d99f4
b36a926
f221c11
4f87d25
228a0d3
5ad2633
9fcd80f
81e2079
816824a
ac9fc7d
50cb6b7
27489e4
d1175d5
b3fd198
2a65a79
e1b4aac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,327 @@ | ||
--- | ||
myst: | ||
html_meta: | ||
"description": "How to add a Control Panel" | ||
"property=og:description": "How to add a Control Panel" | ||
"property=og:title": "Control panels" | ||
"keywords": "Plone, Add, Control Panel" | ||
--- | ||
|
||
(backend-controlpanels-label)= | ||
|
||
# Create a control panel | ||
|
||
There are two approaches to create a control panel for your Plone add-on: | ||
|
||
- [`plonecli`](https://pypi.org/project/plonecli/) | ||
- manual | ||
|
||
|
||
## `plonecli` | ||
|
||
To add a control panel to your add-on, you can use [`plonecli`](https://pypi.org/project/plonecli/) as follows. | ||
|
||
```shell | ||
plonecli add controlpanel | ||
``` | ||
|
||
This creates the control panel Python file in the control panel's folder where you can define your control panel schema fields. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where should the reader go from here? I'm lost. Help! In other words, write documentation as if you didn't have years of experience with Plone. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, after running the So, ig the reader will now be required to know the schemas, then There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case, we need to direct the reader to those parts of the documentation. And now that I think about it, we should have only one method. plonecli automatically performs all the steps in the manual process for the reader, so it's silly to say that there are two processes. The steps are identical, and the only difference is automation of performing them. In any case, the reader will need to modify their add-on's schema, as plonecli has no way to read the developer's mind. Yet. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, we can simply add a note that plonecli does everything done in the manual process... since, the manual process exposes developers to some minor technicalities of the thing |
||
|
||
|
||
## Manual | ||
|
||
To manually create a control panel, go through the following steps. | ||
|
||
- Define the settings interface and form. | ||
- Register the control panel view in ZCML. | ||
- Add the control panel to the Plone control panel listing. | ||
- Set default values in the registry. | ||
|
||
|
||
### Define the settings interface and form | ||
|
||
Create a Python module, {file}`mypackage/controlpanel/settings.py`, that defines your control panel's settings interface and form class as follows. | ||
|
||
```python | ||
# mypackage/controlpanel/settings.py | ||
from zope import schema | ||
from zope.interface import Interface | ||
from plone.app.registry.browser.controlpanel import RegistryEditForm, ControlPanelFormWrapper | ||
from plone.z3cform import layout | ||
|
||
class IMyControlPanelSettings(Interface): | ||
"""Schema for the control panel form.""" | ||
|
||
my_setting = schema.TextLine( | ||
title=u'My Setting', | ||
description=u'Enter the value for my setting', | ||
required=False, | ||
default=u'' | ||
) | ||
|
||
my_choice = schema.Choice( | ||
title=u'My Choice', | ||
description=u'Select a value for my choice', | ||
required=False, | ||
default=u'value3', | ||
values=['value1', 'value2', 'value3'] | ||
) | ||
|
||
class MyControlPanelForm(RegistryEditForm): | ||
"""Control panel form.""" | ||
|
||
schema = IMyControlPanelSettings | ||
schema_prefix = "my.addon" | ||
label = u"My Addon Settings" | ||
|
||
# Wrap the form with plone.z3cform's ControlPanelFormWrapper to get the Plone | ||
# control panel look and feel | ||
MyControlPanelView = layout.wrap_form(MyControlPanelForm, ControlPanelFormWrapper) | ||
``` | ||
|
||
|
||
### Register the control panel view | ||
|
||
Create a file {file}`mypackage/controlpanel/configure.zcml` with the following content to register the control panel view in ZCML. | ||
|
||
```xml | ||
<!-- mypackage/controlpanel/configure.zcml --> | ||
<configure | ||
xmlns="http://namespaces.zope.org/zope" | ||
xmlns:browser="http://namespaces.zope.org/browser" | ||
i18n_domain="mypackage"> | ||
|
||
<browser:page | ||
name="my-controlpanel" | ||
for="Products.CMFPlone.interfaces.IPloneSiteRoot" | ||
class=".settings.MyControlPanelView" | ||
permission="cmf.ManagePortal" | ||
/> | ||
|
||
</configure> | ||
``` | ||
|
||
Make sure to include the above file in your package's main {file}`mypackage/configure.zcml` as shown by the highlighted line below. | ||
|
||
{emphasize-lines="9"} | ||
```xml | ||
<!-- mypackage/configure.zcml --> | ||
<configure | ||
xmlns="http://namespaces.zope.org/zope" | ||
xmlns:i18n="http://namespaces.zope.org/i18n" | ||
i18n_domain="mypackage"> | ||
|
||
<!-- Other configuration --> | ||
|
||
<include package=".controlpanel" /> | ||
|
||
</configure> | ||
``` | ||
|
||
### Add the control panel entry | ||
|
||
Create a {file}`mypackage/profiles/default/controlpanel.xml` in your package's GenericSetup profile with the following content to add your control panel to the Plone control panel listing. | ||
|
||
```xml | ||
<!-- mypackage/profiles/default/controlpanel.xml --> | ||
<?xml version="1.0"?> | ||
<object name="portal_controlpanel"> | ||
<configlet | ||
title="My Addon Settings" | ||
action_id="my-controlpanel" | ||
appId="my.addon" | ||
category="plone-general" | ||
condition_expr="" | ||
icon_expr="string:puzzle" | ||
url_expr="string:${portal_url}/@@my-controlpanel" | ||
visible="True"> | ||
<permission>Manage portal</permission> | ||
</configlet> | ||
</object> | ||
``` | ||
|
||
The category attribute can be one of the following values. | ||
These values correspond to the groups in Site Setup. | ||
rohnsha0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
`plone-general` | ||
: General settings | ||
|
||
`plone-content` | ||
: Content-related settings | ||
|
||
`plone-users` | ||
: Users and groups settings | ||
|
||
`plone-security` | ||
: Security settings | ||
|
||
`plone-advanced` | ||
: Advanced settings | ||
rohnsha0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
### Set default values in the registry | ||
|
||
Define default values for your settings in {file}`mypackage/profiles/default/registry.xml`. | ||
|
||
```xml | ||
<!-- mypackage/profiles/default/registry.xml --> | ||
<?xml version="1.0"?> | ||
<registry> | ||
<records interface="mypackage.controlpanel.settings.IMyControlPanelSettings" | ||
prefix="my.addon"> | ||
<value key="my_setting">default value</value> | ||
<value key="my_choice">value3</value> | ||
</records> | ||
</registry> | ||
``` | ||
|
||
|
||
### Access your settings in code | ||
|
||
You can access your settings in Python code as follows. | ||
|
||
```python | ||
from plone.registry.interfaces import IRegistry | ||
from zope.component import getUtility | ||
|
||
registry = getUtility(IRegistry) | ||
settings = registry.forInterface(IMyControlPanelSettings, prefix="my.addon") | ||
|
||
# Now you can access the settings | ||
my_setting_value = settings.my_setting | ||
my_choice_value = settings.my_choice | ||
``` | ||
|
||
|
||
## Register a control panel | ||
rohnsha0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
To manually register a view as a control panel, add the following registration to your {file}`/profiles/default/controlpanel.xml`. | ||
|
||
```xml | ||
<?xml version="1.0"?> | ||
<object | ||
name="portal_control-panel" | ||
xmlns:i18n="http://xml.zope.org/namespaces/i18n" | ||
i18n:domain="lmu.behavior"> | ||
<configlet | ||
title="Some Control Panel" | ||
action_id="collective.example.some_control-panel" | ||
appId="collective.example" | ||
category="Products" | ||
condition_expr="" | ||
url_expr="string:${portal_url}/@@some_view" | ||
icon_expr="" | ||
visible="True" | ||
i18n:attributes="title"> | ||
<permission>Manage portal</permission> | ||
</configlet> | ||
</object> | ||
``` | ||
|
||
stevepiercy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Use `FieldSet` to group fields | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this also part of the manual process only or both manual and plonecli? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stevepiercy this needs to be added in any way you use to create the controlpanel, as these include the fields (to be grouped) that needs to be shown in the settings (of the controlpanel) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, please see other comments regarding the flow and structure of this chapter. I think we're close to finished with those enhancements.
rohnsha0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
For complex control panels, you can group fields together as in the following example. | ||
|
||
```python | ||
from plone.supermodel import model | ||
|
||
class IMyControlPanelSettings(Interface): | ||
|
||
model.fieldset( | ||
'advanced', | ||
label=u"Advanced Settings", | ||
fields=['advanced_setting1', 'advanced_setting2'] | ||
) | ||
|
||
# Basic settings | ||
my_setting = schema.TextLine( | ||
title=u'My Setting', | ||
description=u'Enter the value for my setting', | ||
required=False | ||
) | ||
|
||
# Advanced settings | ||
advanced_setting1 = schema.TextLine( | ||
title=u'Advanced Setting 1', | ||
required=False | ||
) | ||
|
||
advanced_setting2 = schema.Bool( | ||
title=u'Advanced Setting 2', | ||
default=False | ||
) | ||
``` | ||
|
||
|
||
## Common schema fields | ||
|
||
The following is a list of commonly used schema field types. | ||
|
||
`schema.TextLine` | ||
: For single-line text | ||
|
||
`schema.Text` | ||
: For multi-line text | ||
|
||
`schema.Bool` | ||
: For boolean values | ||
|
||
`schema.Int` | ||
: For integer values | ||
|
||
`schema.Float` | ||
: For floating-point values | ||
|
||
`schema.Choice` | ||
: For selection from a list of values | ||
|
||
`schema.Datetime` | ||
: For date and time values | ||
|
||
`schema.List` | ||
: For list of values | ||
|
||
|
||
## Modify control panel fields | ||
|
||
When you modify the fields in your control panel settings interface, the changes won't be automatically reflected in existing sites. | ||
You'll need to perform one or more of the following steps. | ||
|
||
- Run the appropriate upgrade steps. | ||
- Reinstall your add-on. | ||
- Test with a fresh site installation. | ||
|
||
|
||
## Troubleshooting | ||
|
||
If your control panel doesn't appear or doesn't work as expected: | ||
|
||
- Verify that all ZCML is properly registered | ||
- Check for errors in the Plone error log | ||
- Ensure your GenericSetup profiles are correctly installed | ||
- Validate that the interface path in registry.xml matches your actual Python path | ||
rohnsha0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
## Example file structure | ||
|
||
Below is a complete example file structure for a basic add-on with a control panel. | ||
|
||
``` | ||
mypackage/ | ||
├── __init__.py | ||
├── configure.zcml | ||
├── controlpanel/ | ||
│ ├── __init__.py | ||
│ ├── configure.zcml | ||
│ └── settings.py | ||
└── profiles/ | ||
└── default/ | ||
├── controlpanel.xml | ||
├── metadata.xml | ||
└── registry.xml | ||
``` | ||
|
||
```{seealso} | ||
See the chapter {ref}`training:controlpanel-label` from the Mastering Plone 6 Training. | ||
``` |
Uh oh!
There was an error while loading. Please reload this page.