This package extend the Neos Content Respository Node Type configuration to convert Node or collection of Nodes to JSON-LD.
composer require ttree/linkeddata
- Support simple document
- Use EEL queries
- Support relation between document(s)
- Validation of the generated LinkedData
First you need to edit your Node Type configuration (NodeTypes.yaml), the example bellow is for a course (Workshop) that can contains many sessions (Course Instance in the Schema.org terminology). Each Session can have a dedicated Location:
'Your.Package:Workshop':
options:
TtreeLinkedData:Generator:
default:
context:
sessions: "${q(node).children('sessions').children('[instanceof Your.Package:Session]').sort('begin', 'ASC').get()}"
nextSessions: "${sessions ? q(sessions).filterByDate('end', Date.now()).get() : null}"
description: "${q(node).children('main').find('[instanceof Neos.NodeTypes:Text]').get(0)}"
fragment:
'@context': http://schema.org
'@type': Course
name: "${q(node).property('title')}"
description: "${String.stripTags(String.cropAtSentence(q(description).property('text'), 180, '...'))}"
hasCourseInstance: "${nextSessions ? LinkedData.List(nextSessions, preset, false) : null}"
'Your.Package:Session':
options:
TtreeLinkedData:Generator:
default:
context:
ISO8601: "Y-m-d\TH:i:sO"
where: "${q(node).property('where')}"
course: "${q(node).closest('[instanceof Neos.Neos:Document]').get(0)}"
description: "${q(course).children('main').find('[instanceof Neos.NodeTypes:Text]').get(0)}"
fragment:
'@context': http://schema.org
'@type': CourseInstance
name: "${q(course).property('title')}"
description: "${String.stripTags(String.cropAtSentence(q(description).property('text'), 180, '...'))}"
startDate: "${Date.format(q(node).property('begin'), ISO8601)}"
endDate: "${Date.format(q(node).property('end'), ISO8601)}"
location: "${LinkedData.item(where, preset, false)}"
'Your.Package:Location':
options:
TtreeLinkedData:Generator:
default:
fragment:
'@context': http://schema.org
'@type': Place
name: "${q(node).property('title')}"
address:
@type: PostalAddress
addressLocality: "${q(node).property('addressLocality')}"
addressRegion: "${q(node).property('addressRegion')}"
postalCode: "${q(node).property('postalCode')}"
streetAddress: "${q(node).property('streetAddress')}"
You can use multiple presets (default
is the preset name). Most LinkedData
EEL helper accept a preset paramater.
Each presets contains two section, the context
configuration and the linked data fragment
.
The context contains a list of key value pairs. All values are available in the EEL context during expression parsing.
The framgment contains the template of the JSON-LD graph. The template can be nested. The value of each keys can be a static string or an EEL expression (see bellow to the list of EEL helpers available in the package).
To render the JSON-LD graph from all Workshop pages:
prototype(Your.Package:WorkshopDocument) {
head.linkedData = Neos.Fusion:Array {
document = ${LinkedData.render(documentNode, 'default')}
}
}
With this snippet, Neos will render automatically the JSON-LD content in hte HEAD section of your document.
You can also render JSON-LD inside the body of your document, in the case, the prototype Ttree.LinkedData:Decorator
can be useful.
Let's say you have a prototype to render your Workshop page content, name Your.Package:WorkshopDocument
,
the following snippet will add the JSON-LD after your title.
Your.Package:WorkshopDocument.@process.jsonld = Ttree.LinkedData:Decorator
By default this prototype use the default preset and the current document, but you can configure it:
Your.Package:WorkshopDocument.@process.jsonld = Ttree.LinkedData:Decorator {
preset = 'myCustomPreset'
node = ${node}
}
In some case you can render static JSON-LD (like Organization or Website) and need to use custom EEL helper to prepare the data.
Your:
Package:
linkedData:
website:
'@context': http://schema.org
'@type': WebSite
'@id': '#website'
url: http://yourdomain.com/
name: Your website name
potentialAction:
'@type': SearchAction
target: http://yourdomain.com/?s={search_term_string}
query-input: "required name=search_term_string"
organization:
'@context': http://schema.org
'@type': Organization
'@id': "#organization"
url: http://yourdomain.com/
name: Your organization name
The Website
and Organization
needs to be rendered on the homepage only:
prototype(Your.Package:HomeDocument) {
head.linkedData = Neos.Fusion:Array {
website = ${LinkedData.renderRaw(Configuration.setting('Your.Package.linkedData.website'))}
organization = ${LinkedData.renderRaw(Configuration.setting('Your.Package.linkedData.organization'))}
}
}
Replace the Configuration
EEL helper by your own if you need dynamic data.
LinkedData.render(NodeInterface $node, $preset = 'default'): string
This helper accept a NodeInterface
instance and preset name. The helper will render the full JSON-LD graph
and output a valid HTML5 script tag.
LinkedData.renderRaw(array $data): string
This helper accept an array. The helper will render the full JSON-LD graph and output a valid HTML5 script tag.
LinkedData.list(array $collection, $preset = 'default', bool $withContext = true): array
This helper a collection of NodeInterface
instance, a preset name and boolean switch to print of not the @context
key. The helper will return an array of the JSON-LD graph.
You can use this helper in your preset configuration to render a one to one/many relation (see the hasCourseInstance in the default preset for the Your.Package:Workshop node type.)
LinkedData.item(NodeInterface $node, $preset = 'default', bool $withContext = true): array
This helper a NodeInterface
instance, a preset name and boolean switch to print of not the @context
key. The helper will return an array of the JSON-LD graph.
You can use this helper in your preset configuration to render a one to one relation.
Development sponsored by ttree ltd - neos solution provider.
We try our best to craft this package with a lots of love, we are open to sponsoring, support request, ... just contact us.
Licensed under MIT, see LICENSE