diff --git a/docs/backend/generic-setup.md b/docs/backend/generic-setup.md new file mode 100644 index 000000000..8d0b34d78 --- /dev/null +++ b/docs/backend/generic-setup.md @@ -0,0 +1,1763 @@ +--- +myst: + html_meta: + "description": "How does GenericSetup work" + "property=og:description": "How does GenericSetup work" + "property=og:title": "GenericSetup" + "keywords": "Plone 6, backend, GenericSetup" +--- + +(genericsetup-label)= + +# GenericSetup + +GenericSetup is a framework to modify the Plone site during add-on package installation and uninstallation. + +It provides XML-based rules to change the site settings. + +```{todo} +remove archetypes example code everywhere +``` + + +## Introduction + +GenericSetup is an XML-based way to import and export Plone site configurations. + +It is mainly used to prepare the Plone site for add-on packages, by: + +- registering Registry entries (resources, configuration, etc) +- setting various properties, +- registering portlets, +- registering portal_catalog search query indexes, +- providing upgrade steps for addon version upgrades +- ... etc ... + +GenericSetup is mostly used to apply an add-on's specific changes to the site configuration and to enable specific behaviors when the add-on installer is run. + +GenericSetup XML files are usually in a `profiles/default` folder inside the add-on package. + +All run-time through-the-web ({term}`TTW`) configurable items (for example viewlets order through `/@@manage-viewlets` page) are made repeatable using GenericSetup profile files. + +You can always change the configuration options through Plone or using the Management Interface, and then you export the resulting profile as an XML file, using the *Export* tab in `portal_setup` accessible from the Management Interface. + +Directly editing XML profile files does not change anything on the site, even after Zope restart. +This is because run-time TTW configurable items are stored in the database. + +If you edit profile files, you need to either reimport the edited files using the `portal_setup` tool or fully rerun the add-on package installer in Plone control panel. + +This import will read XML files and change the Plone database accordingly. + +```{note} +Difference between ZCML and GenericSetup + +ZCML changes affect loaded Python code in **all** sites inside Zope whereas GenericSetup XML files affect only one Plone site and its database. +GenericSetup XML files are always database changes. + +Relationship between ZCML and site-specific behavior is usually done using {doc}`layers `. +ZCML directives, like viewlets and views, are registered to be active only on a certain layer using `layer` attribute. +When GenericSetup XML is imported through `portal_setup`, or the add-on package installer is run for a Plone site, the layer is activated for the particular site only, enabling all views registered for this layer. +``` + +```{note} +The `metadata.xml` file (add-on dependency and version information) is read during Plone start-up. +If this file has problems, your add-on might not appear in the installer control panel. +``` + + +- [GenericSetup package page](https://pypi.python.org/pypi/Products.GenericSetup). +- [GenericSetup source code](https://github.com/zopefoundation/Products.GenericSetup). + +## Creating A Profile + +You use `` directive in your add-on package's `configure.zcml`. +The name for the default profile executed by the Plone add-on installer is `default`. + +If you need different profiles, for example for unit testing, you can declare them here. + +XML files for the `default` profile go in the `profiles/default` folder inside your add-on package. + +```xml + + + + + +``` + +### Multiple Profiles + +When you have more than one profile in your add-on package, the add-ons control panel needs to decide which one to use when you install it. + +Since Plone 5.1, when there is a `default` profile, it is always used as the installation profile, regardless of other profile names. + +Exception: when this `default` profile is marked in an `INonInstallable` utility, it is ignored and Plone falls back to using the first from the alphabetical sorting. + +```{note} +In Plone 5.0 and lower, +the profiles are sorted alphabetically by id, +and the first one is chosen. +If you have profiles `base` and `default`, +the `base` profile is installed. +It is recommended to let `default` be the alphabetically first profile. +``` + +## Add-on-specific Issues + +Add-on packages may contain: + +- A default GenericSetup XML profile which is automatically run when the package is installed using the quick-installer. + The profile name is usually `default`. +- Other profiles which the user may install using the `portal_setup` *Import* tab, or which can be manually enabled for unit tests. +- An "Import various" step, which runs Python code every time the GenericSetup XML profile is installed. + See {ref}`custominstall`. +- A `pre_handler` or `post_handler` when you use GenericSetup 1.8.2 or higher. + See note at {ref}`custominstall`. + +For more information about custom import steps, see: + +- + +## Listing Available Profiles + +Example: + +``` +# List all profiles know to the Plone instance. +setup_tool = self.portal.portal_setup + +profiles = setup_tool.listProfileInfo() +for profile in profiles: + print str(profile) +``` + +Sample results: + +```python +{'product': 'PluggableAuthService', + 'description': 'Content for an empty PAS (plugins registry only).', + 'for': , + 'title': 'Empty PAS Content Profile', + 'version': 'PluggableAuthService-1.5.3', + 'path': 'profiles/empty', + 'type': 1, + 'id': 'PluggableAuthService:empty'} +{'product': 'Products.CMFPlone', + 'description': u'Profile for a default Plone.', + 'for': , + 'title': u'Plone Site', + 'version': u'3.1.7', + 'path': u'/home/moo/sits/parts/plone/CMFPlone/profiles/default', + 'type': 1, + 'id': u'Products.CMFPlone:plone'} +... +``` + +## Installing A Profile + +This is usually unit test specific question how to enable certain add-ons for unit testing. + +### plone.app.testing + +See [Product and profile installation](http://docs.plone.org/external/plone.app.testing/docs/source/README.html#product-and-profile-installation). + +### Manually + +You might want to install profiles manually if they need to be enabled only for certain tests. + +The profile name is in the format `profile-${package_name}:${profile id}` + +Unit testing example: + +``` +# Run the extended profile of the "your.addonpackage" package. +setup_tool.runAllImportStepsFromProfile('profile-your.addonpackage:extended') +``` + +```{note} +Since Products.GenericSetup 1.8.0 the `profile-` part is optional. +The code can handle both. +``` + +## Missing Upgrade Procedure + +In the Add-ons control panel you may see a warning that your add-on package is [missing an upgrade procedure](http://stackoverflow.com/questions/15316583/how-to-define-a-procedure-to-upgrade-an-add-on). + +This means you need to write some {ref}`genericsetup-upgrade-steps-label`. + + +## Uninstall Profile + +When you deactivate an add-on in the control panel, Plone looks for a profile with the name `uninstall` and applies it. + +```{note} +If there is no `uninstall` profile, a warning is displayed before installing the add-on. +If you do activate the add-on, no deactivate button will be shown. +``` + + +## Dependencies + +GenericSetup profile can contain dependencies to other add-on package installers and profiles. + +For example, if you want to declare a dependency to the *your.addonpackage* package, that it is automatically installed when your add-on is installed, +you can use the declaration below. + +This way you can be sure that all layers, portlets and other features which require database changes are usable from *your.addonpackage* when it is run. + +`metadata.xml`: + +```xml + + + 1000 + + profile-your.addonpackage:default + + +``` + +*your.addonpackage* declares the profile in its configure.zcml: + +```xml + +``` + +```{warning} +Unlike other GenericSetup XML files, `metadata.xml` is read on the start-up and this read is cached. +Always restart Plone after editing `metadata.xml`. + +If your `metadata.xml` file contains syntax errors or dependencies to a missing or non-existent package (e.g. due to a typo in a name) your add-on will disappear from the installation control panel. +``` + +```{note} +For some old add-ons in the `Products.*` Python namespace, you must not include the full package name in the dependencies. + +This is true when this add-on has registered its profile in Python instead of zcml, and there it has used only part of its package name. + +In most cases you *do* need to use the full `Products.xxx` name. +``` + +To declare a dependency on the `simple` profile of `Products.PluggableAuthService`: + +```xml + + + 1000 + + + profile-PluggableAuthService:simple + + +``` + +## Metadata version numbers + +Some old add-on packages may have a `metadata.xml` without version number, but this is considered bad practice. + +What should the version number in your `metadata.xml` be? + +This mostly matters when you are adding upgrade steps, see also the [Upgrade steps] section. + +Upgrade steps have a sort order in which they are executed. This used to be alphabetical sorting. + +When you had eleven upgrade steps, marked from 1 through 11, alphabetical sorting meant this order: 1, 10, 11, 2, 3, etc. + +If you are seeing this, then you are using an old version of GenericSetup. + +You want numerical sorting here, which is correctly done currently. Versions with dots work fine too. + +They get ordered just like they would when used for packages on PyPI. + +Best practice for all versions of GenericSetup is this: + +- Start with 1000. + This avoids problems with ancient GenericSetup that used alphabetical sorting. +- Simply increase the version by 1 each time you need a new metadata version. + For example: 1001, 1002, etc. +- If your add-on package version number changes, but your profile stays the same and no upgrade step is needed, you should **not** change the metadata version. + There is no need. +- If you make changes for a new major release, you should increase the metadata version significantly. + This leaves room for small metadata version increases on a maintenance branch. + Example: + You have branch master with version 1025. + You make backwards incompatible changes and you increase the version to 2000. + You create a maintenance branch where the next metadata version will be 1026. + +(genericsetup-custom-installer-code-label)= + +## Custom Installer Code (`setuphandlers.py`) + +Besides out-of-the-box XML steps which provide both install and uninstall, +GenericSetup provides a way to run custom Python code when your add-on package is installed and uninstalled. + +This is not a very straightforward process, though. + +````{note} +An easier way may be possible for you. +GenericSetup 1.8.2 has an option to point to a function to run before or after applying all import steps for your profile. + +If you do not need to support older versions, this is the easiest way. + +In `configure.zcml`: + +``` + + + + + +``` + +In `setuphandlers.py`: + +```python +def run_before(context): + # This is run before running the first import step of + # the default profile. context is portal_setup. + # If you need the same context as you would get in + # an import step, like setup_various below, do this: + profile_id = 'profile-your.addonpackage:default' + good_old_context = context._getImportContext(profile_id) + ... + +def run_after(context): + # This is run after running the last import step of + # the default profile. context is portal_setup. + ... +``` + +The best practice is to create a `setuphandlers.py` file which contains a function `setup_various()` which runs the required Python code +to make changes to Plone site object. + +This function is registered as a custom `genericsetup:importStep` in XML. + +```{note} +When you write a custom `importStep`, remember to write uninstallation code as well. +``` + +However, the trick is that all GenericSetup import steps, including your custom step, are run for *every* add-on package when they are installed. + +If your need to run code which is **specific to your add-on install only** you need to use a marker text file which is checked by the GenericSetup context. + +Also you need to register this custom import step in `configure.zcml`: + +```xml + + + + + +``` + +You can run other steps before yours by using the `depends` directive. + +For instance, if your import step depends on a content type to be installed first, you must use: + +```xml + + + + + + + +``` + +`setuphandlers.py` example + +```python + +def run_custom_code(site): + """Run custom add-on package installation code to modify Plone + site object and others + + @param site: Plone site + """ + +def setup_various(context): + """ + @param context: Products.GenericSetup.context.DirectoryImportContext instance + """ + + # We check from our GenericSetup context whether we are running + # add-on installation for your package or any other + if context.readDataFile('your.addonpackage.marker.txt') is None: + # Not your add-on + return + + portal = context.getSite() + + run_custom_code(portal) +``` + +And add a dummy text file +`your.addonpackage/your/addonpackage/profiles/default/your.addonpackage.marker.txt`: + +This text file can contain any content - it just needs to be present + + + +## Overriding Import Step Order + +If you need to override the order of import steps in a package that is not yours, +it might work if you [use an overrides.zcml](http://plone.293351.n2.nabble.com/Overriding-import-step-order-td2189638.html). + +### Controlling The Import Step Execution Order + +If you need to control the execution order of one of your own custom import steps, you can do this in your import step definition in zcml. + +To make sure the catalog and typeinfo steps are run before your own step, use this code: + +```xml + + + + + + + + +``` + +```{note} +The name that you need, is usually the name of the related xml file, but with the `.xml` stripped. +For the `catalog.xml` the import step name is `catalog`. +But there are exceptions. + +For the `types.xml` and the `types` directory, the import step name is `typeinfo`. + +See {ref}`genericsetup-generic-setup-files-label` for a list. +``` + + +(genericsetup-upgrade-steps-label)- + +## Upgrade Steps + +You can define upgrade steps to run code when someone upgrades your package from version *x* to *y*. + +As an example, let's say that the new version of your.addonpackage defines a *price* field on a content type *MyType* to be a string, +but previously (version 1.1 and earlier) it was a float. + +Code that uses this field and assumes it to be a float will break after the upgrade, you'd like to automatically convert existing values for the field to string. + +You could do this in a script, but having a GenericSetup upgrade step means non-technical people can do it as well. + +Once you have the script, it's code can be to put in an upgrade step. + +### Increment Profile Version + +First increase the number of the version in the `profiles/default/metadata.xml`. +This version number should be an integer. + +Package version are different because they add sense like the status of the add-on: is it stable, is it in development, in beta, which branch is it. + +A profile version indicates only that you have to migrate data in the database. + +### Add Upgrade Step + +Next we add an upgrade step: + +```xml + + + + + +``` + +- You can use a wildcard character for *source* to indicate an upgrade for any previous version. + Since Products.GenericSetup 1.7.6 this works fine. + To run the upgrade step only when upgrading from a specific version, use that version's number. +- The optional `sortkey` can be used to indicate the order in which upgrade steps from the same source to destination are run. + +### Add Upgrade Code + +The code for the upgrade method itself is best placed in a *upgrades.py* module: + +```python +from plone import api +import logging + +PROFILE_ID = 'profile-your.addonpackage:default' + + +def convert_price_to_string(context, logger=None): + """Method to convert float Price fields to string. + + When called from the import_various method, 'context' is + the plone site and 'logger' is the portal_setup logger. + + But this method will be used as upgrade step, in which case 'context' + will be portal_setup and 'logger' will be None.""" + + if logger is None: + # Called as upgrade step: define our own logger. + logger = logging.getLogger('your.addonpackage') + + # Run the catalog.xml step as that may have defined new metadata + # columns. We could instead add to + # the registration of our import step in zcml, but doing it in + # code makes this method usable as upgrade step as well. + # Remove these lines when you have no catalog.xml file. + setup = api.portal.get_tool('portal_setup') + setup.runImportStepFromProfile(PROFILE_ID, 'catalog') + + catalog = api.portal.get_tool('portal_catalog') + brains = catalog(portal_type='MyType') + count = 0 + for brain in brains: + current_price = brain.getPrice + if type(current_price) != type('a string'): + obj = brain.getObject() + obj.setPrice(str(current_price)) + obj.reindexObject() + count += 1 + + setup.runImportStepFromProfile(PROFILE_ID, 'catalog') + logger.info('%s fields converted.' % count) +``` + +Other examples of using generic setup to run import steps are below. + +If you want to call `types.xml` use `typeinfo`: + +```python +setup.runImportStepFromProfile(PROFILE_ID, 'typeinfo') +``` + +If you want to call `workflow.xml` use `workflow`: + +```python +setup.runImportStepFromProfile(PROFILE_ID, 'workflow') +``` + +The ids of the various default import steps are defined in several places. + +Some of the most used ones are here: + +- +- + +After restarting Zope, your upgrade step should be visible in the Management Interface: +the `portal_setup` tool has a tab `Upgrades`. + +Select your package profile to see which upgrade steps Zope knows about for your add-on. + +### upgradeDepends + +In an upgrade step you can apply a specific import step from your profile: + +```xml + +``` + +You can apply multiple steps, separated by a space: + +```xml + +``` + +You can apply steps from a different profile: + +```xml + +``` + +You can apply a complete profile: + +```xml + +``` + +### Combining Upgrade Steps + +You can create many upgrade steps under one migration. + +This is useful when you want to have the ability to re-run some parts of the migration and make your code more re-useable (for example cook css resource of your theme). + +Here is an example of many upgrade steps you can have to achieve on a site policy: + +```xml + + + + + + + + + + + + + +``` + + +## Best Practices + +### The `purge` attribute + +When importing items such as property sheets, make sure not to override other profile settings: set the `purge` attribute to False. + +This will *add* the listed items to the property instead of resetting the property. + +Example: + +```xml + + + + +``` + +### The `remove` Attribute + +The `remove` attribute can be used to remove an item. + +```xml + +``` + +There are dangers: + +- Some importers do not support the `remove` keyword. + They ignore it and add the item blindly. + This should be regarded as a bug in the importer. + Please report it. +- Some importers check the truth value of the attribute, some just check the presence. + `remove="false"` may mean the item stays and may mean it gets removed. + Best is to either use `remove="true"` or leave the entire keyword away. + +### Only Use The Configuration That You Need + +When you export your site's configuration, it will include things that you don't need. + +For example, if you only need to change the 'Allow anonymous to view about' property, this is what your `propertiestool.xml` should look like: + +```xml + + + + True + + + Duck Test + Action: test a duck + ... + +``` + +```{note} +In the portal_actions tool, in the Management Interface, you will see an i18n domain specified for each action. +``` + +- `catalog.xml`: no i18n needed +- `componentregistry.xml`: no i18n needed +- `contenttyperegistry.xml`: no i18n needed +- `controlpanel.xml`: use **your own** domain. + +Example: + +``` + + + + Manage portal + + +``` + +- `diff_tool.xml`: no i18n needed +- `factorytool.xml`: no i18n needed +- `metadata.xml`: no i18n needed +- `portlets.xml`: use the **plone** domain. +- `properties.xml`: no i18n needed +- `propertiestool.xml`: no i18n needed +- `rolemap.xml`: no i18n needed +- `skins.xml`: no i18n needed +- `toolset.xml`: no i18n needed +- `types`: use **your own** domain +- `viewlets.xml`: no i18n needed +- `workflows`: use the **plone** domain + + +(genericsetup-generic-setup-files-label)- + +## Generic Setup Files + + +### actions.xml + +Install actions in the `portal_actions` tool. + +Example: + +```xml + + + + + Check in + + string:${object_url}/@@content-checkin + string:${portal_url}/++resource++checkout.png + python:path('object/@@iterate_control').checkin_allowed() + + + + True + + + +``` + +These actions are used in various parts of Plone. + +These are the object categories in standard Plone: + +`document_actions` + +: Document actions, like rss and print. + +`site_actions` + +: Site actions, like sitemap, accessibility, contact. + +`object` + +: Object tabs, like contents, sharing tab. + +`object_buttons` + +: Object buttons, like delete, rename. + +`portal_tabs` + +: Portal tabs, like Home. + +`user` + +: User actions, like preferences, login, join. + +For adding controlpanel actions, see [controlpanel.xml] instead. + +The objects support `insert-before` and `insert-after` for inserting the action object before or after another action object. + +For removing, use `remove="true"` (or `True`). + +Uninstall example: + +```xml + + + + + + +``` + +```{note} +You can use your own i18n domain. +``` + +### browserlayer.xml + +This registers a specific browser layer, which allows components to be available only when your add-on package is installed. + +```xml + + + + +``` + +For removing, use `remove="true"` (or `True`). + +Uninstall example: + +```xml + + + + +``` + +### componentregistry.xml + + +Setup items in the local component registry of the Plone Site. +The items can be adapters, subscribers or utilities. + +This can also be done in zcml, which puts it in the global registry that is defined at startup. + +The difference is, when you put it in xml, the item is only added to a specific Plone Site when you install the package in the add-ons control panel. + +Both have their uses. + +Example: + +```xml + + + + + + + + + +``` + +```{note} +A subscriber can either have a handler or a factory, not both. +A factory must have a provides and may have a name. +A subscriber will fail with a provides. +``` + +```{note} +If something does not get added, its provider is probably blacklisted. +This list is defined by `Products.GenericSetup.interfaces.IComponentsHandlerBlacklist` utilities. +In standard Plone 5, these interfaces are blacklisted as providers: + +- `Products.GenericSetup.interfaces.IComponentsHandlerBlacklist` +- `plone.portlets.interfaces.IPortletManager` +- `plone.portlets.interfaces.IPortletManagerRenderer` +- `plone.portlets.interfaces.IPortletType` +``` + +Uninstall example: + +```xml + + + + + + + + + + + + +``` + +```{note} +The presence of the `remove` keyword is enough. +Even if it is empty or contains `false` as value, the item is removed. +``` + + +### contentrules.xml + +TODO + + +### controlpanel.xml + +```xml + + + + + Manage portal + + + +``` + +This creates an action in the Site Setup control panel in Plone. +Actions are bundled in categories. + +- `Plone` (Plone Configuration) +- `plone-advanced` (Advanced) +- `plone-content` (Content) +- `plone-general` (General) +- `plone-security` (Security) +- `plone-users` (Users) +- `Products` (Add-on Configuration) + +Any other categories are not displayed in the overview control panel. + +For add-ons, the category `Products` is recommended. + +The `action_id` must be unique over all categories. + +Only one permission is allowed. + +Uninstall example: + +```xml + + + + +``` + +```{note} +The action is removed if the `remove` keyword is `true`. +Upper or lower case does not matter. + +The action is visible if the `visible` keyword is `true`. +Upper or lower case does not matter. +``` + +```{note} +You can use your own i18n domain. +``` + +Code is in `Products.CMFPlone.exportimport.controlpanel` and `Products.CMFPlone.PloneControlPanel`. + + +### diff_tool.xml + +This is the configuration from `plone.app.contenttypes`: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +This configures how the difference between two versions of a field are shown on the history tab. + +The configuration is stored in the `portal_diff` tool. + +For Archetypes content, you need a different `difftype`: + +```xml + + + +``` + +A new `difftype` can be registered by calling `Products.CMFDiffTool.CMFDiffTool.registerDiffType`. +The `difftypes` in standard Plone 5 are: + +- `Lines Diff` +- `Compound Diff for AT types` +- `Binary Diff` +- `Field Diff` +- `List Diff` +- `HTML Diff` +- `Compound Diff for Dexterity types` + +```{note} +There is no uninstall version. +The `remove` keyword is not supported. +The `portal_diff` tool does not show configuration for portal_types that no longer exist. +``` + +Code is in `Products.CMFDiffTool.exportimport.difftool`. + + +### metadata.xml + +The `metadata.xml` file is read during Plone start-up. + +If this file has problems your add-on package might not appear in the installer control panel. + +The `metadata.xml` file contains add-on dependency and version information. + +```xml + + + 1000 + + profile-your.addonpackage:default + + +``` + +The dependencies are optional. + +There is no import step that reads this file. +The `portal_setup` tool uses this information when installing a profile. + +It installs the profiles that are listed as dependencies, before installing your own profile. + +Since `Products.GenericSetup` 1.8.0, dependency profiles that are already installed, are not installed again. + +Instead, their upgrade steps, are applied, if they have them. + +After your profile is installed, `portal_setup` stores the version number. +This is used when determining if any upgrade steps are available for your profile. + +When you search for `metadata.xml` in the documentation, you will find more information in context. + +```{note} +There is no uninstall version of `metadata.xml`. +An `uninstall` profile can have its own `metadata.xml` with a version and even profiles. +But for dependencies no `purge` or `remove` keyword is supported. +``` + + +### portal_placeful_workflow + +This handles the `portal_placeful_workflow.xml` file and the `portal_placeful_workflow` directory. + +This install or configures a placeful workflow. + +For this to work, you must install Workflow Policy Support (CMFPlacefulWorkflow) in the Add-ons control panel. This package is included in standard Plone, but does not come installed by default. + +Standard `portal_placeful_workflow.xml` from `Products.CMFPlacefulWorkflow`: + +```xml + + + + 1 + + + + + +``` + +Standard `portal_placeful_workflow/simple-publication.xml` from `Products.CMFPlacefulWorkflow`: + +```xml + + + Simple publication + + + + + + + + + + + + + + + + +``` + +Uninstall example: + +```xml + + + + +``` + +The import handler is in `Products.CMFPlacefulWorkflow.exportimport.importWorkflowPolicies`. + +### portlets.xml + +Code is in `plone.app.portlets.exportimport.portlets`. + +```{eval-rst} +.. automodule:: plone.app.portlets.exportimport.portlets + +``` + +### propertiestool.xml + +```{deprecated} 5.0 +Most properties are now handled in the configuration registry and can be configured in `registry.xml`. +``` + +In `propertiestool.xml` you can change all values of the `portal_properties` tool. +Example: + +```xml + + + + False + TinyMCE + + +``` + +Uninstall example: + +```xml + + + + + + + + +``` + +### pluginregistry.xml + +This configures PAS plugin orderings and active plugins. +It isn't part of Plone itself, it is used by other frameworks and can be used in Plone with a little extra configuration. + +First, you need a monkey patch in your `` __init__.py` `` to point the importer at where Plone keeps its PAS plugins. + +```python +from Products.PluginRegistry import exportimport +from Products.PluginRegistry.interfaces import IPluginRegistry + + +def getRegistry(site): + return IPluginRegistry(site.acl_users.plugins) + +exportimport._getRegistry = getRegistry +``` + +Secondly, code to handle the import step needs to be activated in Plone: + +```xml + +``` + +Now you can use `pluginregistry.xml` in your generic setup profiles: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### registry.xml + +This edits the configuration registry. + +```{note} +The name of this import step is `plone.app.registry`, **not** `registry`. +``` + +Example for adding all records of an interface: + +```xml + + + + +``` + +Example for adding an individual record: + +```xml + + + + + Timeout + 0 + + 100 + + +``` + +Uninstall example: + +```xml + + + + + +``` + +The item is removed if the `remove` keyword is `true`. +Upper or lower case does not matter. + +Existing values of lists are purged by default. +The values are not purged if the `purge` keyword is `false`. + +Upper or lower case does not matter. + +For more examples, see the [plone.app.registry documentation](https://pypi.python.org/pypi/plone.app.registry#using-genericsetup-to-manipulate-the-registry). + +Code is in `plone.app.registry.exportimport.handler`. + +### repositorytool.xml + +This handles the versioning policy of content. + +The default configuration in Plone is: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +Code is in `Products.CMFEditions.exportimport.repository`. + +### rolemap.xml + +In `rolemap.xml` you define new roles and grant permissions. +Both are optional. + +```xml + + + + + + + + + + + + + + + + + + + + + +``` + +The roles above are the standard roles in Plone 5. +In your profile you only need to list other roles. + +The permission must already exist on the Zope level, otherwise you get an error when installing your profile: + +``` +ValueError: The permission Pass the bridge is invalid. +``` + +A permission is created on the Zope level when it is used in code. +See {doc}`Creating permissions `. + +When a role in a permission does not exist, it is silently ignored. +The roles listed in a permission are not added. + +They replace all existing roles. + +With `acquire="true"` (or `True`, `yes`, `1`) roles are also acquired from the Zope root. + +````{note} +There is no uninstall version for `rolemap.xml`. +`purge` and `remove` are not supported. +You can set different values for a permission if this makes sense in your case. +This will reset the permission to the same settings as on the Zope level: + +```xml + +``` +```` + +```{eval-rst} +.. automodule:: Products.GenericSetup.rolemap + :members: importRolemap RolemapImportConfigurator + +``` + +### sharing.xml + +The sharing.xml file let you add custom roles to the sharing tab. +For reference, visit: {ref}`security-label`. + + +### typeinfo + +This handles the `types.xml` file and the `types` directory. + +```{note} +The name of this import step is `typeinfo`, **not** `types`. +``` + +Partial example from `plone.app.contenttypes`: + +```xml + + + + + + + + + + + + +``` + +This adds content types in the `portal_types` tool. +The `meta_type` can be: + +- `Dexterity FTI` for Dexterity content. + This is probably what you want. +- `Factory-based Type Information with dynamic views` for Archetypes content and for the Plone Site itself +- `Factory-based Type Information` for Archetypes content that does not need dynamic views, + the ability to choose a view in the `display` menu. + +The `types.xml` should be accompanied by a `types` folder with details information on the new types. +If you are editing an already existing type, then `types.xml` is not needed: +a file in the `types` folder is enough. + +If the object name in `types.xml` is `Collection` then you must add a file `types/Collection.xml`. +This file is in `plone.app.contenttypes`: + +```xml + + + + + Collection + Collection + True + False + + False + plone.app.contenttypes.addCollection + plone.app.contenttypes.content.Collection + + + plone.app.contenttypes.schema:collection.xml + + + + + + + + + + + + + + listing_view + False + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +For comparison, here is the `types.xml` from `plone.app.collection` which has an old style Archetypes Collection: + +```xml + + + + + + +``` + +And here is the `types/Collection.xml` from `plone.app.collection`: + +```xml + + + Collection + Collection of searchable information + + Collection + plone.app.collection + addCollection + standard_view + True + True + + False + standard_view + + + + + + + + + + + + + + + + + + +``` + +Uninstall example: + +```xml + + + + +``` + +````{note} +The `remove` keyword is supported for actions. +`remove=""` is enough, but recommended is to use `remove="true"`. + +The `view_methods` property is a list that is always imported fresh. +Elements that are not in the list, are removed. +If you only want to add an element and want to keep any existing elements, +you can tell it not to purge: + +```xml + + + +``` + +This does not work for the `allowed_content_types`: they are always purged. +```` + +```{note} +You can use your own i18n domain. +``` + +### viewlets.xml + +```{eval-rst} +.. automodule:: plone.app.viewletmanager.exportimport.storage + +``` + +### workflows.xml + +This handles the `workflows.xml` file and the `workflows` directory. + +Example from `Products/CMFPlone/profiles/default/workflows.xml` in Plone 5.0: + +```xml + + + Contains workflow definitions for your portal + + + + + + + + + + + + + + + + +``` + +This adds six workflows in the `portal_workflow` tool. +It sets the default workflow to `simple_publication_workflow`. + +It sets several types to not use any workflow. + +Next to this, the `workflows` directory is checked. +This contains sub directories with the same name as the workflows. +Each sub directory contains a file `definition.xml` with the definition for this workflow. + +See {ref}`workflows-label`. diff --git a/docs/backend/index.md b/docs/backend/index.md index 3e7dd3278..74d38c60f 100644 --- a/docs/backend/index.md +++ b/docs/backend/index.md @@ -23,6 +23,7 @@ configuration-registry content-types/index control-panels fields +generic-setup global-utils indexing upgrading/index diff --git a/docs/developer-guide/create-a-backend-add-on.md b/docs/developer-guide/create-a-backend-add-on.md new file mode 100644 index 000000000..500c777c2 --- /dev/null +++ b/docs/developer-guide/create-a-backend-add-on.md @@ -0,0 +1,231 @@ +--- +myst: + html_meta: + "description": "How to create a backend add-on" + "property=og:description": "How to create a backend add-on" + "property=og:title": "Create a backend add-on" + "keywords": "Plone 6, backend, add-on" +--- + +(create-a-backend-add-on-label)= + +# Create a backend add-on + +This section explains how a developer can create an {term}`add-on` for the Plone backend. + +## System requirements + +Follow the section {ref}`create-project-cookieplone-system-requirements` to set up your system. + +## Generate the add-on project with `cookieplone` + +To develop an add-on for backend and/or Classic-UI, run the following command to generate your add-on project using the `backend_addon` Cookieplone template. +See {doc}`plone:install/create-project-cookieplone` for details of the latter scenario. +The following output assumes the former scenario. + +```shell +uvx cookieplone backend_addon +``` + +```console +> uvx cookieplone backend_addon +╭──────────────────────────────── cookieplone ─────────────────────────────────╮ +│ │ +│ ******* │ +│ *************** │ +│ *** *** │ +│ *** *** *** │ +│ *** ***** *** │ +│ *** *** *** │ +│ *** *** *** │ +│ *** ***** *** │ +│ *** *** *** *** │ +│ *** ***** *** │ +│ *** *** *** │ +│ *** *** │ +│ *************** │ +│ ******* │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +You've downloaded /Users//.cookiecutters/cookieplone-templates before. Is +it okay to delete and re-download it? [y/n] (y): +╭──────────────────────────────── Plone Addon ─────────────────────────────────╮ +│ │ +│ Creating a new Plone Addon │ +│ │ +│ Sanity check results: │ +│ │ +│ - Cookieplone: ✓ │ +│ - uv: ✓ │ +│ - git: ✓ │ +│ │ +╰──────────────────────────────────────────────────────────────────────────────╯ + [1/10] Addon Title (Addon): + [2/10] A short description of your addon (A new addon for Plone): + [3/10] Author (Plone Community): + [4/10] Author E-mail (collective@plone.org): + [5/10] GitHub Username or Organization (collective): + [6/10] Should we use prerelease versions? (No): + [7/10] Plone Version (6.1.3): + [8/10] Python package name (collective.addon): + [9/10] Support headless Plone? + 1 - Yes + 2 - No + Choose from [1/2] (1): + [10/10] Would you like to add a documentation scaffold to your project? + 1 - Yes + 2 - No + Choose from [1/2] (1): + -> Remove files used in classic UI setup + -> Create namespace packages + -> Format code + -> Initialize Git repository + -> Generate documentation scaffold +╭────────────────────────── New addon was generated ───────────────────────────╮ +│ │ +│ Addon │ +│ │ +│ Now, enter the repository, start coding, and push to your organization. │ +│ │ +│ Sorry for the convenience, │ +│ The Plone Community. │ +│ │ +│ https://plone.org/ │ +╰──────────────────────────────────────────────────────────────────────────────╯ +``` + +Cookieplone creates a folder with the name of the add-on, in this example, `collective.addon`. + +You can now continue to add subtemplates to your addon {ref}`create-a-backend-add-on-add-subtemplate-label` + + +## Generate the add-on project with `plonecli` + +Run the following command to create an addon project with `plonecli` + +```shell +uvx plonecli create addon +``` + +```console +> uvx plonecli create addon collective.addon +RUN: bobtemplates.plone:addon -O collective.addon + +Welcome to mr.bob interactive mode. Before we generate directory structure, +some questions need to be answered. + +Answer with a question mark to display help. +Values in square brackets at the end of the questions show the default value if +there is no answer. + + +--> Package description [An add-on for Plone]: + +--> Plone version [6.0.0]: + +--> Python version for virtualenv [python3]: + +--> Do you want me to activate VS Code support? (y/n) [y]: + + + +isort-apply: successful: +isort-apply: install_deps> python -I -m pip install isort -c constraints.txt +isort-apply: commands[0]> isort /Users//Development/collective.addon/src +/Users//Development/collective.addon/setup.py +Fixing /Users//Development/collective.addon/src/collective/addon/testing.py +Fixing /Users//Development/collective.addon/src/collective/addon/tests/test_setup.py + isort-apply: OK (2.57=setup[1.94]+cmd[0.63] seconds) + congratulations :) (2.59 seconds) + + +Identified `/` as project root containing a file system root. +Sources to be formatted: "Users//Development/collective.addon/src", + "Users//Development/collective.addon/setup.py" +src/collective/__init__.py wasn't modified on disk since last run. +src/collective/addon/browser/__init__.py wasn't modified on disk since last run. +src/collective/addon/locales/__init__.py wasn't modified on disk since last run. +src/collective/addon/tests/__init__.py wasn't modified on disk since last run. +src/collective/addon/interfaces.py already well formatted, good job. +reformatted src/collective/addon/__init__.py +reformatted src/collective/addon/setuphandlers.py +reformatted src/collective/addon/testing.py +reformatted setup.py +reformatted src/collective/addon/locales/update.py +reformatted src/collective/addon/tests/test_setup.py + +All done! ✨ 🍰 ✨ +6 files reformatted, 5 files left unchanged. + +black-enforce: successful: +black-enforce: install_deps> python -I -m pip install black -c constraints.txt +black-enforce: commands[0]> black -v src setup.py + black-enforce: OK (2.60=setup[2.12]+cmd[0.48] seconds) + congratulations :) (2.61 seconds) + + +git init is disabled! +Generated file structure at /Users//Development/collective.addon/collective.addon +``` + +Plonecli creates a folder with the name of the add-on, in this example, `collective.addon`. + +You can now continue to add subtemplates to your addon {ref}`create-a-backend-add-on-add-subtemplate-label` + + +(create-a-backend-add-on-add-subtemplate-label)= + +## Add `plonecli` subtemplate to an addon + +The generated addon contains a {file}`bobtemplates.cfg` file which lets you add several subtemplates with `plonecli`. + +Run the following command to list the available subtemplates. + +```shell +uvx plonecli -l +``` + +```shell +> uvx plonecli -l +Available mr.bob templates: + - addon + - behavior + - content_type + - controlpanel + - form + - indexer + - mockup_pattern + - portlet + - restapi_service + - site_initialization + - subscriber + - svelte_app + - theme + - theme_barceloneta + - theme_basic + - upgrade_step + - view + - viewlet + - vocabulary + - buildout + ``` + + All templates below `addon` can be added to your newly created addon with: + + ```shell + uvx ploncli add + ``` + +Currently documented subtemplates: + +- behavior: {ref}`backend-behaviors-label` +- content_type: {ref}`creating-content-types-label` +- controlpanel: {ref}`control-panels-label` +- form: {reg}`forms-label` +- mockup_pattern: {ref}`mockup-and-patternslib-label` +- theme_barceloneta: {ref}`create-a-theme-add-on-label` + + +The addon also contains a {term}`GenericSetup` default install/uninstall profile. + +See {ref}`genericsetup-label` for more information. diff --git a/docs/developer-guide/create-a-distribution.md b/docs/developer-guide/create-a-distribution.md index 8a272d566..9b99a78f8 100644 --- a/docs/developer-guide/create-a-distribution.md +++ b/docs/developer-guide/create-a-distribution.md @@ -19,10 +19,9 @@ For a conceptual guide, see {doc}`/conceptual-guides/distributions`. ``` -## Create a backend add-on +## Use a backend add-on -These instructions assume that you already have created a Plone backend add-on package, -and now you want to add a distribution to it. +These instructions assume that you have already {doc}`created a Plone backend add-on package `, and now you want to add a distribution to it. A Plone distribution exists inside a Python package that can be installed by `pip`. diff --git a/docs/developer-guide/index.md b/docs/developer-guide/index.md index 940f95007..37fa582ad 100644 --- a/docs/developer-guide/index.md +++ b/docs/developer-guide/index.md @@ -1,26 +1,95 @@ --- myst: html_meta: - "description": "Plone developer guide" - "property=og:description": "Plone developer guide" - "property=og:title": "Developer guide" - "keywords": "Plone 6, developer guide, development" + "description": "Plone development guide" + "property=og:description": "Plone development guide" + "property=og:title": "Development guide" + "keywords": "Plone 6, development guide, developer, development" --- -# Developer guide +# Development guide + +```{note} +This part of the documentation is under revision, consolidating documentation for development from its various locations into in one section. +Until then, you can use the [search feature](https://6.docs.plone.org/search.html?q=development). +You can also help with this effort, even if it is to report that something is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). +``` This part of the documentation provides information for how to develop in Plone. +This development guide points you, as a developer, to the appropriate resource. + + +## Tests + +Tests ensure that your project functions as expected, and that changes to the code base during development don't break anything. + + +### Volto + +- {doc}`Volto acceptance tests ` +- {doc}`Volto unit tests ` +- {ref}`testing-the-add-on-label` + + +### Classic UI ```{note} -This part of the documentation is under construction. -You can find documentation for development in various locations through the [search feature](https://6.docs.plone.org/search.html?q=development). -You can help consolidate all of development documentation here, even if it is to let us know what is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). +Classic UI testing for Plone 6 is in the process of being written. ``` +### Backend + +```{note} +Backend testing for Plone 6 is in the process of being written. +Until it is complete, Plone 5 documentation is the authoritative source for writing tests for the Plone backend. +``` + +- {doc}`Backend tests ` (Plone 5) + + +## Create an add-on + +- {doc}`create-a-backend-add-on` +- {doc}`/volto/development/add-ons/create-an-add-on-18` + + +## Create a Plone distribution + +{doc}`create-a-distribution` + + +## Create content types + +- {doc}`/backend/content-types/creating-content-types` +- {doc}`plone5:develop/plone/content/index` (Plone 5) + + +## Register views + +{doc}`plone5:develop/plone/views/index` (Plone 5) + + +## Register API services + +{doc}`backend/configuration-registry` + + +## {term}`ZCA` +% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. +{doc}`plone5:develop/addons/components/index` (Plone 5) + + +## {term}`ZCML` +% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. +{doc}`plone5:develop/addons/components/zcml` (Plone 5) + + ```{toctree} :maxdepth: 2 +:hidden: +create-a-backend-add-on develop-volto-add-ons-index create-a-distribution standardize-python-project-configuration diff --git a/docs/glossary.md b/docs/glossary.md index a6c762350..65391effa 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -25,6 +25,10 @@ Buildout [Buildout](https://github.com/buildout/buildout/) is a Python-based tool for building and assembling applications from multiple parts, based on a configuration file. It was the most common way of installing Plone 3, 4, and 5, and can still be used with Plone 6. + Usage of Buildout in Plone appears in various places in this documentation. + For a history and extended usage of Buildout, you can refer to the Plone 4 Documentation's section on [Buildout](https://4.docs.plone.org/old-reference-manuals/buildout/). + The Plone community authored this reference manual, as Buildout's own documentation is suboptimal. + CMS Content Management System diff --git a/docs/i18n-l10n/translating-text-strings.md b/docs/i18n-l10n/translating-text-strings.md index 22d307e88..d69c4ec15 100644 --- a/docs/i18n-l10n/translating-text-strings.md +++ b/docs/i18n-l10n/translating-text-strings.md @@ -56,7 +56,7 @@ Information in the PO file headers is ignored. [`i18ndude`](https://pypi.org/project/i18ndude/) should be used to create a script which searches particular packages for translation strings. -If you have created your add-on using [bobtemplates.plone](https://pypi.org/project/bobtemplates.plone/), then you will already have a script `update.sh` inside your package and a script `update_locale` in your buildout to extract the messages from your code. +If you have created your add-on using [bobtemplates.plone](https://pypi.org/project/bobtemplates.plone/), then you will already have a script `update.sh` inside your package and a script `update_locale` in your {term}`buildout` to extract the messages from your code. After running that script, a new `domain.pot` file will be created in your `locales` directory where all the messages will be saved. @@ -273,7 +273,7 @@ This script hooks into the release process and builds the MO files for you. ### Installing i18ndude -The recommended method is to have {term}`i18ndude` installed via your [buildout](https://www.buildout.org/en/latest/). +The recommended method is to have {term}`i18ndude` installed via your buildout. Add the following to your `buildout.cfg`: