Addressing the Missing Author Information in Plone 6 with Volto
One of the limitations I've noticed in Plone 6 when using Volto is the absence of detailed author information in the content returned by plone.restapi. Currently, the content GET service only provides the author's ID, making it challenging to display a comprehensive author "signature" on the content. In this blog post, I'll walk you through a simple workaround I've implemented to solve this issue.
Introducing the Authors Service
To address this limitation, I've introduced a new service called Authors. This service is accessible via the @authors endpoint and returns essential details about the content's author.
Create the Authors Service
Firstly, in the backend code, create a new folder named services/authors. Inside this folder, add a new Python file called get.py with the following content:
from plone import api
from plone.restapi.interfaces import IExpandableElement
from plone.restapi.services import Service
from zope.component import adapter
from zope.interface import implementer
from zope.interface import Interface
DEFAULT_USER = "Érico Andrei"
@implementer(IExpandableElement)
@adapter(Interface, Interface)
class Authors:
def __init__(self, context, request):
self.context = context
self.request = request
def __call__(self, expand=True):
result = {"authors": {"@id": f"{self.context.absolute_url()}/@authors"}}
if not expand:
return result
portal_url = api.portal.get().absolute_url()
data = []
authors = self.context.creators
for author_username in authors:
user = api.user.get(username=author_username)
author_info = {
"@id": f"{portal_url}/author/{author_username}",
"fullname": DEFAULT_USER,
}
if user:
fullname = user.getProperty("fullname")
author_info["fullname"] = fullname or DEFAULT_USER
data.append(author_info)
return {"authors": data}
class AuthorsGet(Service):
def reply(self):
authors = Authors(self.context, self.request)
return authors(expand=True)["authors"]
Register the New Endpoint
Next, you'll need to register this new endpoint. Add the following code to a new file services/authors/configure.zcml:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:cache="http://namespaces.zope.org/cache"
xmlns:plone="http://namespaces.plone.org/plone"
xmlns:zcml="http://namespaces.zope.org/zcml"
>
<adapter
factory=".get.Authors"
name="authors"
/>
<plone:service
method="GET"
factory=".get.AuthorsGet"
for="zope.interface.Interface"
permission="zope2.View"
name="@authors"
/>
<cache:ruleset
for=".get.AuthorsGet"
ruleset="plone.content.dynamic"
/>
</configure>
Also, you need to register the authors package in the services/configure.zcml file
<configure xmlns="http://namespaces.zope.org/zope">
<include package=".authors" />
</configure>
After restarting your Plone instance, you can test the new service endpoint by making a request to mysite.com/++api++/<posturl>/@authors. You should receive a response like this:
[
{
"@id": "https://ericof.com/author/ericof",
"fullname": "Erico Andrei"
}
]
Voila! It's that simple.
Enhancements
While this approach works, it does require an additional HTTP request to fetch the author's information, which is not ideal. Fortunately, plone.restapi offers a feature called Content Expanders to mitigate this.
In your services/authors/get.py file, line 12, we register the Authors class as an IExpandableElement. This allows the class to be invoked internally by the content endpoint. Now, a request to mysite.com/++api++/<posturl>?expand=authors will also include the author's information under @components.authors in the content response.
{
"@components": {
"authors": [
{
"@id": "https://ericof.com/author/ericof",
"fullname": "Erico Andrei"
}
],
},
"@id": "https://ericof.com/en/posts/2023/addressing-the-missing-author-information-in-plone-6-with-volto",
"@type": "Post"
}
To make Volto utilize this content expander by default, register it under config.settings.apiExpanders like so:
const applyConfig = (config) => {
config.settings = {
...config.settings,
apiExpanders: [
...config.settings.apiExpanders,
{
match: '',
GET_CONTENT: [
'breadcrumbs',
'navigation',
'actions',
'authors',
'types',
],
querystring: {
'expand.navigation.depth': 2,
},
},
]
};
}
Conclusion
While I anticipate that the Volto team will likely introduce a more elegant solution in the future, this workaround has served me well in numerous projects. It's a practical way to include author information without waiting for an official update.