Themes#

Diazo themes can be managed programmatically through the @themes endpoint in a Plone site. This endpoint requires plone.app.theming to be installed and the cmf.ManagePortal permission.

It is particularly useful in containerized deployments (such as Kubernetes) where access to the Plone UI may not be available.

Listing themes#

A list of all available themes can be retrieved by sending a GET request to the @themes endpoint:

http

GET /plone/@themes HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET http://nohost/plone/@themes -H "Accept: application/json" --user admin:secret

httpie

http http://nohost/plone/@themes Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@themes', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))

Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "@id": "http://localhost:55001/plone/@themes/plonetheme.barceloneta",
    "id": "plonetheme.barceloneta",
    "title": "Barceloneta Theme",
    "description": "The default Plone 5 theme",
    "active": true,
    "preview": "++theme++plonetheme.barceloneta/preview.png",
    "rules": "++theme++plonetheme.barceloneta/rules.xml"
  }
]

The following fields are returned for each theme:

  • @id: hypermedia link to the theme resource

  • id: the theme identifier

  • title: the friendly name of the theme

  • description: description of the theme

  • active: whether this theme is currently active

  • preview: path to the theme preview image (or null)

  • rules: path to the theme rules file

Reading a theme#

A single theme can be retrieved by sending a GET request with the theme ID as a path parameter:

http

GET /plone/@themes/plonetheme.barceloneta HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET http://nohost/plone/@themes/plonetheme.barceloneta -H "Accept: application/json" --user admin:secret

httpie

http http://nohost/plone/@themes/plonetheme.barceloneta Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@themes/plonetheme.barceloneta', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))

Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "@id": "http://localhost:55001/plone/@themes/plonetheme.barceloneta",
  "id": "plonetheme.barceloneta",
  "title": "Barceloneta Theme",
  "description": "The default Plone 5 theme",
  "active": true,
  "preview": "++theme++plonetheme.barceloneta/preview.png",
  "rules": "++theme++plonetheme.barceloneta/rules.xml"
}

Uploading a theme#

A new theme can be uploaded by sending a POST request with a ZIP archive as multipart/form-data:

http

POST /plone/@themes HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: multipart/form-data; boundary=---------------------------1234567890

-----------------------------1234567890
Content-Disposition: form-data; name="themeArchive"; filename="mytheme.zip"
Content-Type: application/zip

<binary zip data>
-----------------------------1234567890--

curl

curl -i -X POST http://nohost/plone/@themes -H "Accept: application/json" -H "Content-Type: multipart/form-data; boundary=---------------------------1234567890" --data-raw '-----------------------------1234567890

Content-Disposition: form-data; name="themeArchive"; filename="mytheme.zip"

Content-Type: application/zip



<binary zip data>

-----------------------------1234567890--' --user admin:secret

httpie

echo '-----------------------------1234567890

Content-Disposition: form-data; name="themeArchive"; filename="mytheme.zip"

Content-Type: application/zip



<binary zip data>

-----------------------------1234567890--' | http POST http://nohost/plone/@themes Accept:application/json Content-Type:"multipart/form-data; boundary=---------------------------1234567890" -a admin:secret

python-requests

requests.post('http://nohost/plone/@themes', headers={'Accept': 'application/json', 'Content-Type': 'multipart/form-data; boundary=---------------------------1234567890'}, data='-----------------------------1234567890\r\n\nContent-Disposition: form-data; name="themeArchive"; filename="mytheme.zip"\r\n\nContent-Type: application/zip\r\n\n\r\n\n<binary zip data>\r\n\n-----------------------------1234567890--', auth=('admin', 'secret'))

Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
  "@id": "http://localhost:55001/plone/@themes/mytheme",
  "id": "mytheme",
  "title": "My Theme",
  "description": "",
  "active": false,
  "preview": null,
  "rules": "/++theme++mytheme/rules.xml"
}

The following form fields are accepted:

  • themeArchive (required): the ZIP file containing the theme

  • enable (optional): set to true to activate the theme immediately after upload

  • replace (optional): set to true to overwrite an existing theme with the same ID

Activating a theme#

A theme can be activated by sending a PATCH request with {"active": true}:

http

PATCH /plone/@themes/plonetheme.barceloneta HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: application/json

{"active": true}

curl

curl -i -X PATCH http://nohost/plone/@themes/plonetheme.barceloneta -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"active": true}' --user admin:secret

httpie

echo '{
  "active": true
}' | http PATCH http://nohost/plone/@themes/plonetheme.barceloneta Accept:application/json Content-Type:application/json -a admin:secret

python-requests

requests.patch('http://nohost/plone/@themes/plonetheme.barceloneta', headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json={'active': True}, auth=('admin', 'secret'))

Response:

HTTP/1.1 204 No Content

Deactivating a theme#

A theme can be deactivated by sending a PATCH request with {"active": false}:

http

PATCH /plone/@themes/plonetheme.barceloneta HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: application/json

{"active": false}

curl

curl -i -X PATCH http://nohost/plone/@themes/plonetheme.barceloneta -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"active": false}' --user admin:secret

httpie

echo '{
  "active": false
}' | http PATCH http://nohost/plone/@themes/plonetheme.barceloneta Accept:application/json Content-Type:application/json -a admin:secret

python-requests

requests.patch('http://nohost/plone/@themes/plonetheme.barceloneta', headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json={'active': False}, auth=('admin', 'secret'))

Response:

HTTP/1.1 204 No Content