From 72621bbb605f0f7dd51abb4bd1e75ec705c0d3e8 Mon Sep 17 00:00:00 2001 From: boss6825 Date: Sat, 24 Jan 2026 20:19:26 +0000 Subject: [PATCH 1/6] writeup for todo of registry config --- docs/backend/configuration-registry.md | 103 +++++++++++++++++++++---- 1 file changed, 90 insertions(+), 13 deletions(-) diff --git a/docs/backend/configuration-registry.md b/docs/backend/configuration-registry.md index 9aae7d4fa6..0de33d2d5d 100644 --- a/docs/backend/configuration-registry.md +++ b/docs/backend/configuration-registry.md @@ -1,27 +1,104 @@ --- myst: html_meta: - "description": "Configuration Registry in Plone 6" - "property=og:description": "Configuration Registry in Plone 6" - "property=og:title": "Configuration Registry in Plone 6" - "keywords": "Plone 6, Configuration Registry, backend, plone.registry, plone.app.registry, GenericSetup" + "description": "The Configuration Registry in Plone provides a central system for storing and managing site-wide settings using plone.registry and plone.app.registry." + "property=og:description": "The Configuration Registry in Plone provides a central system for storing and managing site-wide settings using plone.registry and plone.app.registry." + "property=og:title": "Configuration Registry" + "keywords": "Plone 6, Configuration Registry, plone.registry, plone.app.registry, GenericSetup, settings, control panel" --- (backend-configuration-registry-label)= # Configuration Registry -```{todo} -Explain how `plone.registry` / `plone.app.registry` and `GenericSetup` work together. -Provide examples of how to import and export Plone settings. +The Configuration Registry in Plone is a central system for storing and managing site-wide settings and configuration options. +It allows developers and administrators to define, store, and retrieve configuration data in a structured way. -See https://github.com/plone/documentation/issues/1424 +If you have the Manager role, you can directly view and change many variables that influence Plone through the {guilabel}`Configuration Registry` control panel in {guilabel}`Site Setup`. +Because there is a large number of settings, you can filter them or select a prefix to find the right one. +Add-on packages can create their own prefixes for their settings. + +```{warning} +Setting variables directly in the Configuration Registry is not recommended as part of regular maintenance. +It is a useful tool for inspecting variables for expert users. ``` -(backend-configuration-registry-generic-setup-label)= +The Configuration Registry is built on two main packages: + +[`plone.registry`](https://pypi.org/project/plone.registry/) +: The core package that provides the low-level registry implementation for storing settings. + +[`plone.app.registry`](https://pypi.org/project/plone.app.registry/) +: The Plone integration layer that provides control panel support, GenericSetup integration, and user interface components. + + +(backend-configuration-registry-plone-registry-label)= + +## `plone.registry` + +The `plone.registry` package provides a debatably simple, persistent (ZODB-based) system for managing configuration settings. +It uses `zope.schema` fields to define the types and constraints for settings. + +### Key concepts + +Registry +: The main storage container for all settings. + In Plone, you access it as a utility: `from plone.registry import getUtility; registry = getUtility(IRegistry)`. + +Records +: Individual settings stored in the registry. + Each record has a name (a dotted name string), a field (a `zope.schema` field), and a value. + +Interfaces +: You can register a `zope.interface` Interface with the registry. + The registry will then contain one record for each field in the interface. + + +### Accessing registry values + +You can access registry values programmatically in several ways. + +#### Direct access by record name + +```python +from plone.registry.interfaces import IRegistry +from zope.component import getUtility + +registry = getUtility(IRegistry) + +# Get a value directly +value = registry["my.package.setting"] + +# Set a value +registry["my.package.setting"] = "new value" +``` + +#### Access through an interface + +When you register an interface with the registry, you can use `registry.forInterface()` to get a proxy object that provides attribute access to the settings. + +```python +from plone.registry.interfaces import IRegistry +from zope.component import getUtility +from my.package.interfaces import IMySettings + +registry = getUtility(IRegistry) +settings = registry.forInterface(IMySettings) + +# Access settings as attributes +value = settings.my_setting +settings.my_setting = "new value" +``` + + +(backend-configuration-registry-plone-app-registry-label)= + +## `plone.app.registry` -## `GenericSetup` +The `plone.app.registry` package integrates `plone.registry` with Plone. +It provides: -```{todo} -Explain how `GenericSetup` works. -``` \ No newline at end of file +- GenericSetup import and export handlers for registry settings +- A control panel base class for creating settings forms +- The {guilabel}`Configuration Registry` control panel for viewing and editing settings +- Browser views for managing the registry \ No newline at end of file From ae0739eabdd946743505d974d10d6dcc3e0c394d Mon Sep 17 00:00:00 2001 From: boss6825 Date: Sat, 24 Jan 2026 20:32:22 +0000 Subject: [PATCH 2/6] more writeup on todos --- docs/backend/configuration-registry.md | 159 ++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/docs/backend/configuration-registry.md b/docs/backend/configuration-registry.md index 0de33d2d5d..f7b3825587 100644 --- a/docs/backend/configuration-registry.md +++ b/docs/backend/configuration-registry.md @@ -101,4 +101,161 @@ It provides: - GenericSetup import and export handlers for registry settings - A control panel base class for creating settings forms - The {guilabel}`Configuration Registry` control panel for viewing and editing settings -- Browser views for managing the registry \ No newline at end of file +- Browser views for managing the registry + + +### Creating settings for your add-on + +To create settings for your add-on, you need to: + +1. Define a schema interface for your settings +2. Register the interface with the registry using GenericSetup +3. Optionally create a control panel to edit the settings + + +#### Define a settings interface + +Create an interface that defines your settings using `zope.schema` fields. + +```python +# In your package's interfaces.py +from zope import schema +from zope.interface import Interface + + +class IMyPackageSettings(Interface): + """Settings for my package.""" + + enable_feature = schema.Bool( + title="Enable feature", + description="Turn this feature on or off", + default=True, + ) + + max_items = schema.Int( + title="Maximum items", + description="The maximum number of items to display", + default=10, + min=1, + max=100, + ) + + admin_email = schema.TextLine( + title="Admin email", + description="Email address for notifications", + required=False, + ) +``` + + +#### Register settings with GenericSetup + +Create a `registry.xml` file in your package's `profiles/default` directory. + +```xml + + + + + True + 10 + + + +``` + +The `prefix` attribute determines the dotted name prefix for the records. +With `prefix="my.package"`, the `enable_feature` field becomes `my.package.enable_feature` in the registry. + + +#### Access settings in your code + +```python +from plone.registry.interfaces import IRegistry +from zope.component import getUtility +from my.package.interfaces import IMyPackageSettings + + +def get_settings(): + registry = getUtility(IRegistry) + return registry.forInterface(IMyPackageSettings) + + +def is_feature_enabled(): + settings = get_settings() + return settings.enable_feature +``` + + +### Creating a control panel + +To provide a user interface for editing your settings, create a control panel. + +```python +# In your package's controlpanel.py +from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper +from plone.app.registry.browser.controlpanel import RegistryEditForm +from plone.z3cform import layout +from my.package.interfaces import IMyPackageSettings + + +class MyPackageSettingsForm(RegistryEditForm): + """Control panel form for my package settings.""" + + schema = IMyPackageSettings + label = "My Package Settings" + description = "Configure settings for my package" + + +MyPackageSettingsView = layout.wrap_form( + MyPackageSettingsForm, + ControlPanelFormWrapper +) +``` + +Register the view and control panel in ZCML. + +```xml + + + + + +``` + +Register the control panel configlet in `profiles/default/controlpanel.xml`. + +```xml + + + + + Manage portal + + + +``` + +```{seealso} +See the chapter {doc}`/backend/control-panels` for more information on creating control panels. +``` + + From 417303a2e4a74eb513f44e4592657378d0b2e027 Mon Sep 17 00:00:00 2001 From: boss6825 Date: Sat, 24 Jan 2026 20:36:02 +0000 Subject: [PATCH 3/6] update 3 on todos with further sections --- docs/backend/configuration-registry.md | 115 +++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/docs/backend/configuration-registry.md b/docs/backend/configuration-registry.md index f7b3825587..16a4153d5e 100644 --- a/docs/backend/configuration-registry.md +++ b/docs/backend/configuration-registry.md @@ -259,3 +259,118 @@ See the chapter {doc}`/backend/control-panels` for more information on creating ``` +### Widget customization + +You can customize the widgets used in your control panel form by overriding the `updateFields()` and `updateWidgets()` methods. + +```python +from plone.app.registry.browser.controlpanel import RegistryEditForm +from z3c.form.browser.checkbox import CheckBoxFieldWidget + + +class MyPackageSettingsForm(RegistryEditForm): + schema = IMyPackageSettings + label = "My Package Settings" + + def updateFields(self): + super().updateFields() + # Change the widget type for a field + self.fields["content_types"].widgetFactory = CheckBoxFieldWidget + + def updateWidgets(self): + super().updateWidgets() + # Customize widget properties + self.widgets["description"].rows = 8 + self.widgets["description"].style = "width: 100%;" +``` + + +### Content type choice settings + +A common use case is allowing users to select which content types a feature applies to. + +```python +from plone.autoform import directives as form +from z3c.form.browser.checkbox import CheckBoxFieldWidget +from zope import schema +from zope.interface import Interface + + +class IMyPackageSettings(Interface): + """Settings with content type selection.""" + + form.widget(enabled_types=CheckBoxFieldWidget) + enabled_types = schema.List( + title="Enabled content types", + description="Select which content types this feature applies to", + required=False, + value_type=schema.Choice( + source="plone.app.vocabularies.ReallyUserFriendlyTypes" + ), + ) +``` + +In `registry.xml`, you can set default values for the list. + +```xml + + + + Document + News Item + Folder + + + +``` + + +(backend-configuration-registry-genericsetup-label)= + +## GenericSetup integration + +GenericSetup is an XML-based framework for importing and exporting Plone site configurations. +The Configuration Registry integrates with GenericSetup through the `registry.xml` import and export step. + + +### The `registry.xml` file + +The `registry.xml` file in a GenericSetup profile allows you to: + +- Register interfaces and their fields as registry records +- Set values for existing records +- Create individual records without an interface + + +#### Register an interface + +```xml + + + + default value + + +``` + + +#### Create individual records + +You can create records without defining an interface first. + +```xml + + + + + Simple Setting + A simple text setting + + default value + + +``` + + From e5b75d947e3542297eb745978296a3522bde43ea Mon Sep 17 00:00:00 2001 From: boss6825 Date: Sat, 24 Jan 2026 20:38:19 +0000 Subject: [PATCH 4/6] update 4 on todos for configuration-registry.md --- docs/backend/configuration-registry.md | 201 +++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/docs/backend/configuration-registry.md b/docs/backend/configuration-registry.md index 16a4153d5e..4ca99d4332 100644 --- a/docs/backend/configuration-registry.md +++ b/docs/backend/configuration-registry.md @@ -374,3 +374,204 @@ You can create records without defining an interface first. ``` +#### Modify existing records + +To modify a record that already exists, reference it by name. + +```xml + + + + My New Site Title + + +``` + + +### The `purge` attribute + +The `purge` attribute controls whether existing values are cleared before importing new ones. +This is especially important for list fields. + +```xml + + + Document + + + + + News Item + +``` + +By default, `purge` is `true`, which means existing values are replaced. +Set `purge="false"` to add to existing list values instead of replacing them. + + +### The `remove` attribute + +You can remove records or values using the `remove` attribute. + +```xml + + + + + + + + + OldType + + + +``` + + +### Exporting registry settings + +You can export the current registry configuration using the {guilabel}`Management Interface`. + +1. Navigate to the {guilabel}`Management Interface` (add `/manage_main` to your site URL). +2. Go to `portal_setup`. +3. Click the {guilabel}`Export` tab. +4. Select {guilabel}`Configuration Registry` from the list of export steps. +5. Click {guilabel}`Export selected steps`. + +This generates a `registry.xml` file with all current settings that you can use in your GenericSetup profile. + + +### Uninstall profile + +When creating an uninstall profile for your add-on, you should clean up any registry records you created. + +In `profiles/uninstall/registry.xml`: + +```xml + + + + +``` + + +(backend-configuration-registry-field-types-label)= + +## Available field types + +The registry supports various field types from `plone.registry.field` and `zope.schema`. + +| Field Type | Description | +|------------|-------------| +| `Bool` | Boolean (true/false) value | +| `Int` | Integer value | +| `Float` | Floating-point number | +| `TextLine` | Single line of text | +| `Text` | Multi-line text | +| `ASCIILine` | Single line of ASCII text | +| `ASCII` | Multi-line ASCII text | +| `Bytes` | Binary data | +| `BytesLine` | Single line of binary data | +| `Choice` | Selection from a vocabulary | +| `List` | List of values | +| `Tuple` | Tuple of values | +| `Set` | Set of unique values | +| `FrozenSet` | Immutable set of unique values | +| `Dict` | Dictionary of key-value pairs | +| `Date` | Date value | +| `Datetime` | Date and time value | +| `Time` | Time value | +| `Timedelta` | Time duration | +| `URI` | URI/URL value | +| `SourceText` | Source code text | +| `Object` | Nested object with its own schema | + +When defining fields in XML, use the full dotted name for the field type. + +```xml + + + My Integer Setting + 0 + 100 + + 50 + +``` + + +(backend-configuration-registry-best-practices-label)= + +## Best practices + +### Use meaningful prefixes + +Always use a meaningful prefix for your registry records, typically your package name. +This prevents conflicts with other packages and makes it easy to identify which package owns a setting. + +```python +# Good +prefix = "my.package" + +# Bad +prefix = "settings" +``` + + +### Provide default values + +Always provide sensible default values for your settings in `registry.xml`. +This ensures your add-on works correctly immediately after installation. + + +### Use interfaces for related settings + +Group related settings into an interface rather than creating individual records. +This makes the settings easier to manage and access programmatically. + + +### Document your settings + +Add clear titles and descriptions to your schema fields. +These appear in the control panel and help administrators understand what each setting does. + +```python +class IMySettings(Interface): + """Settings for my package.""" + + cache_timeout = schema.Int( + title="Cache timeout", + description="How long (in seconds) to cache results. Set to 0 to disable caching.", + default=300, + min=0, + ) +``` + + +### Handle missing settings gracefully + +When accessing registry settings, handle the case where the setting might not exist, especially during upgrades. + +```python +from plone.registry.interfaces import IRegistry +from zope.component import getUtility + + +def get_setting_safely(): + registry = getUtility(IRegistry) + try: + return registry["my.package.new_setting"] + except KeyError: + return "default_value" +``` + + +## Related content + +- {doc}`/backend/control-panels` +- {doc}`/backend/schemas` +- [`plone.registry` on PyPI](https://pypi.org/project/plone.registry/) +- [`plone.app.registry` on PyPI](https://pypi.org/project/plone.app.registry/) \ No newline at end of file From a2b91d817ced3fdc32588eb143c24db335895590 Mon Sep 17 00:00:00 2001 From: boss6825 Date: Sat, 24 Jan 2026 20:44:52 +0000 Subject: [PATCH 5/6] removed one suggested page --- docs/backend/configuration-registry.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/backend/configuration-registry.md b/docs/backend/configuration-registry.md index 4ca99d4332..3b945b44c5 100644 --- a/docs/backend/configuration-registry.md +++ b/docs/backend/configuration-registry.md @@ -572,6 +572,5 @@ def get_setting_safely(): ## Related content - {doc}`/backend/control-panels` -- {doc}`/backend/schemas` - [`plone.registry` on PyPI](https://pypi.org/project/plone.registry/) - [`plone.app.registry` on PyPI](https://pypi.org/project/plone.app.registry/) \ No newline at end of file From bfb5ec3978ba489c735b119bfc8c71752aa4b82e Mon Sep 17 00:00:00 2001 From: boss6825 Date: Sun, 25 Jan 2026 15:54:29 +0000 Subject: [PATCH 6/6] removed some irrelevant sections --- docs/backend/configuration-registry.md | 141 ------------------------- 1 file changed, 141 deletions(-) diff --git a/docs/backend/configuration-registry.md b/docs/backend/configuration-registry.md index 3b945b44c5..269ba00950 100644 --- a/docs/backend/configuration-registry.md +++ b/docs/backend/configuration-registry.md @@ -188,146 +188,6 @@ def is_feature_enabled(): ``` -### Creating a control panel - -To provide a user interface for editing your settings, create a control panel. - -```python -# In your package's controlpanel.py -from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper -from plone.app.registry.browser.controlpanel import RegistryEditForm -from plone.z3cform import layout -from my.package.interfaces import IMyPackageSettings - - -class MyPackageSettingsForm(RegistryEditForm): - """Control panel form for my package settings.""" - - schema = IMyPackageSettings - label = "My Package Settings" - description = "Configure settings for my package" - - -MyPackageSettingsView = layout.wrap_form( - MyPackageSettingsForm, - ControlPanelFormWrapper -) -``` - -Register the view and control panel in ZCML. - -```xml - - - - - -``` - -Register the control panel configlet in `profiles/default/controlpanel.xml`. - -```xml - - - - - Manage portal - - - -``` - -```{seealso} -See the chapter {doc}`/backend/control-panels` for more information on creating control panels. -``` - - -### Widget customization - -You can customize the widgets used in your control panel form by overriding the `updateFields()` and `updateWidgets()` methods. - -```python -from plone.app.registry.browser.controlpanel import RegistryEditForm -from z3c.form.browser.checkbox import CheckBoxFieldWidget - - -class MyPackageSettingsForm(RegistryEditForm): - schema = IMyPackageSettings - label = "My Package Settings" - - def updateFields(self): - super().updateFields() - # Change the widget type for a field - self.fields["content_types"].widgetFactory = CheckBoxFieldWidget - - def updateWidgets(self): - super().updateWidgets() - # Customize widget properties - self.widgets["description"].rows = 8 - self.widgets["description"].style = "width: 100%;" -``` - - -### Content type choice settings - -A common use case is allowing users to select which content types a feature applies to. - -```python -from plone.autoform import directives as form -from z3c.form.browser.checkbox import CheckBoxFieldWidget -from zope import schema -from zope.interface import Interface - - -class IMyPackageSettings(Interface): - """Settings with content type selection.""" - - form.widget(enabled_types=CheckBoxFieldWidget) - enabled_types = schema.List( - title="Enabled content types", - description="Select which content types this feature applies to", - required=False, - value_type=schema.Choice( - source="plone.app.vocabularies.ReallyUserFriendlyTypes" - ), - ) -``` - -In `registry.xml`, you can set default values for the list. - -```xml - - - - Document - News Item - Folder - - - -``` - - -(backend-configuration-registry-genericsetup-label)= - ## GenericSetup integration GenericSetup is an XML-based framework for importing and exporting Plone site configurations. @@ -571,6 +431,5 @@ def get_setting_safely(): ## Related content -- {doc}`/backend/control-panels` - [`plone.registry` on PyPI](https://pypi.org/project/plone.registry/) - [`plone.app.registry` on PyPI](https://pypi.org/project/plone.app.registry/) \ No newline at end of file