Why and How to Add JSON-LD to Your eZ Platform Site
In the previous post I discussed how metadata helps make sense for data and content on the web. In this post, we'll take a more practical approach and learn how to add JSON-LD to your eZ Platform implementation to make your content shine in search results to drive traffic to your site.
JSON-LD is a form of metadata for the web that helps machines make sense of your content or data. It is a format that can be embedded within your HTML markup to describe your content or data. For this, you need to agree on a common vocabulary. The most popular one for JSON-LD is schema.org, a project founded by search engine providers Google, Microsoft, Yahoo and Yandex.
While the Schema.org site specifies hundreds of different (sub)entity types, not all of them are widely adopted. You can annotate all of your views as it certainly does not hurt in the long run, but for immediate benefits you should focus on ones that can make a real impact today. In practice, this means enhancing your visibility on Search Engine Result Pages (SERPs) with the data.
Google controls the majority of search traffic across many regions, so we'll focus on them for the rest of this post. Still you should note that both Bing and Yandex also support JSON-LD. These are definitely worthwhile in English and Russian-speaking markets, so take some time to read through their docs: Marking up your site with structured data on Bing and JSON-LD on Yandex.
Event Metadata Improves Search Experience
Web projects are often launched with limited capabilities (as an MVP) and work continues post launch with incremental improvements. In the lifespan of a service this is the phase where the most impactful Search Engine Optimization actions are taken. Adjustments are made based on real-world experience and the latest SEO techniques are deployed rapidly as they surface.
eZ Platform has many SEO best practices covered out of the box, but JSON-LD is a bit more specific and can't necessarily be covered with an out-of-the-box solution. One of the most common forms of structural data used on Google are events. They are structured and can be used to relay useful data to potential attendees in search results. Especially on mobile devices.
As a practical example, consider the screenshots of a listing of events that have metadata attached and the one without. The enriched results make the Szeged listing more actionable.
In the next section we will see how you could add similar data to your eZ Platform project that has events that you would like to promote in search results as shown in the screenshot.
Adding JSON-LD to Events to eZ Platform
When working with an open specification like JSON-LD it is likely that there is some prior art in reading and writing data in the format. eZ Platform is built on the Symfony PHP framework, so for our case I did a search on Packagist for find options for generating JSON-LD. Out of the three or four viable options I decided I'd give toran/json-ld a try first. The library has a simple API, 13 contributors, active maintenance (last update in March 2020) and over 140,000 installs.
JSON-LD is most commonly embedded within the <head> section of a HTML document. I decided that I'd create a separate controller action for the data and then render it in place using a sub request from Twig. This would allow moving the metadata to a dedicated URL and referencing it with a <link> tag if that became a common practice in the future. Just a bit of planning ahead.
To begin in earnest I added a controller action to our FragmentController that is used to render fragments in the header and footer. The controller will return a "Hello world" JSONResponse:
public function jsonLdAction(Request $request){
return new Response('Hello world');
}
The next step is to make the action executable. Since we do not need a public route for it, I added an inline rendering call to our main template, wrapped in a script tag with the correct type attribute for serving JSON-LD data:
{% if content is defined %}
{{ render(controller('App\\Controller\\FragmentController::jsonLdAction', {
contentId: content.id,
})) }}
{% endif %}
With the basics in place I added the toran/json-ld package using composer:
$ composer require torann/json-ld
Next I created a basic JSON-LD of for an event by following the documentation examples and copying the test case code snippet to return the serialized data and enclosing script tags:
public function jsonLdAction(Request $request, int $contentId){
$outputBuffer = '';
$context = \JsonLd\Context::create('event', [
'name' => 'Apple Fest',
'startDate' => '2013-10-04T00:00',
'url' => 'https://google.com/events/22',
'offers' => [
[
'name' => 'Beer',
'price' => '4.99'
]
],
'location' => [
'name' => 'Fluff Hut',
'address' => [
'streetAddress' => '112 Apple St.',
'addressLocality' => 'Hamden',
'addressRegion' => 'CT',
'postalCode' => '06514',
],
],
'image' => 'https://google.com/some_logo.png',
'description' => 'A description'
]);
$outputBuffer .= $context->generate();
return new Response($outputBuffer);
}
With this in place I had a valid JSON data entry for every page. At first I would only provide out JSON-LD for events, I added some logic to trigger output only for that specific content type:
$content = $this->contentService->loadContent($contentId);
$contentTypeIdentifier = $content->getContentType()->identifier;
switch ($contentTypeIdentifier) {
case "event":
// populate $context, etc.
$outputBuffer .= $context->generate();
}
Finally populate the static values with dynamic ones from our content object using the eZ Platform PHP API. Adjust to match your data model and confirm to the schema.org event spec:
$eventUrl = $request->getSchemeAndHttpHost() . $this->generateUrl('ez_urlalias', ['locationId' => $content->contentInfo->mainLocationId]);
$context = \JsonLd\Context::create('event', [
'name' => $content->getName(),
'startDate' => $content->getFieldValue('from_time')->value,
'url' => $eventUrl,
'location' => [
'name' => $content->getFieldValue('location_name')->value,
'address' => [
'streetAddress' => $content->getFieldValue('start_date')->value,
'addressLocality' => $content->getFieldValue('city')->value,
'postalCode' => $content->getFieldValue('zip_code')->value,
],
],
'description' => $content->getFieldValue('body')
]);
With this in place you can validate your input with the Structured Data Testing Tool from Google to verify it conforms to the JSON-LD standard. Google will gradually pick up your as the robot crawls through your site. The time it takes depends on how large and popular your site is. You can expedite the process for individual URLs by requesting indexing from Search Console.
Conclusion
Adding metadata is always good, but it is important to understand that not all of what you provide is useful today. Only a limited subset of the schema.org vocabulary is relevant immediately, but going forward it is likely that we will see more and more services taking use of this data. But you shouldn't spend resources in perfecting coverage as you can always adapt later.
The implementation example provided above is a simple example of the mechanics of how you could add JSON-LD to your eZ Platform implementation. It is a functional implementation without too many bells and whistles, but for more complex projects you should invest some time in creating an abstraction that allows maintaining metadata for a multitude of content types.
An interesting example of rapid changes that can take place is the quick roll out of new structured data for Events by Google, because of the large number of events cancelled due to COVID-19 in the first half of 2020. Making changes like this quickly require agility from your technical platform and team. Learn how we can help your team become more effective with eZ Platform by signing up to one of our online training courses.
IbexaLearn
Join one of our eZ Platform Training Courses
Our new courses covering Ibexa Platform v3 have been expanded with more material and adapted to fit better with being online. You’ll get a good grounding in how the system works, and we help you get through several exercises to ensure you learn as much as possible.