Collection of building blocks and viewhelpers for TYPO3 projects by tollwerk
The structuredData
viewhelpers provide a simple interface for adding JSON-LD snippets to a page. They use the http://schema.org vocabulary.
Data objects can be added in any Fluid template during the rendering process. The output of the JSON-LD representation, however, is intended to happen only once, preferably at the end of the rendering process / at the end of the page in one single JSON-LD script block. The StructuredDataManager
singleton is taking care of aggregating all the registered data objects.
The Structured Data Manager acts as a singleton in the background and provides 3 important and 2 lesser important public methods. While it's possible to call these directly from within PHP code, they're usually utilized via the viewhelpers (see below).
register(string $type, string $id, array $data): array
for registering a new top-level data object.$type
is a schema.org data type (e.g.'Person'
).$id
is a unique URI referencing the data object (if an anchor-style URI is given, like#john-doe
, the current page's base URI will be prepended automatically, resolving to e.g.https://mysite.com#john-doe
). The 3rd parameter$data
is an array of object properties, e.g.['givenName' => 'John', 'familyName' => 'Doe']
, adhering to the schema.org vocabulary. The created data object / node will be returned.public function set(string $id, $key, $value): void
to set a single property for a previously registered object. The object is referenced by it's URI. Example:set('#john-doe', 'additionalName', 'Jack')
.createNode(string $type, string $id, array $data): array
for registering a new non-top-level data object. It works the same asregister()
except that the object / node will just be returned without being added to the object graph. Useful for adding nested objects (see example below).getGraph(): stdClass
to return the complete object graph (used internally).getBaseUri(): string
to return the current page's base URI.
It should be common practice to add at least one data object to each page denoting the main type of the page, usually using the WebPage object. This can easily be achieved by "priming" the StructuredDataManager
using an initialization hook, as shown in the following example.
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['structuredData']['initialize'][] = \Your\Extension\Utility\StructuredDataUtility::class.'->initialize';
class StructuredDataUtility
{
/**
* Custom Structured Data Initialization
*
* @param array $params Parameters (empty)
* @param StructuredDataManager $structuredDataManager Structured data manager
*/
public function initialize(array $params, StructuredDataManager $structuredDataManager): void
{
// Register a top-level WebPage data object
$structuredDataManager->register('WebPage', $structuredDataManager->getBaseUri(), []);
}
}
You can also add additional default data objects, e.g. the publisher (example also adds a nested image object using createNode()
):
$webPage = $structuredDataManager->register('WebPage', $structuredDataManager->getBaseUri(), []);
$structuredDataManager->register(
'Organization',
'https://tollwerk.de/#organization',
[
'@reverse' => [
'publisher' => [
['@id' => $webPage['@id']],
]
],
'name' => 'tollwerk GmbH',
'url' => 'https://tollwerk.de',
'logo' => $structuredDataManager->createNode(
'ImageObject',
'https://tollwerk.de/#logo',
['url' => 'https://tollwerk.de/t.png']
)
]
);
Use this viewhelper to register a new data object:
<base:structuredData.register type="Person" id="#john-doe" data="{givenName: 'John', familyName: 'Doe'}"/>
Use this viewhelper to set an additional property to an already existing data object:
<base:structuredData.set id="#john-doe" key="additionalName" value="Jack"/>
Use this viewhelper to add an additional value to an already existing data object property. Non-list properties will automatically be converted to a list, keeping the current value as the first list item. If the property doesn't exist yet, it will be created.
<base:structuredData.add id="#john-doe" key="sameAs" value="https://johndoe.com"/>
Resolves and returns an ID reference to a data object (as full URI). The return value is either an ID string or a JSON object referencing a data object by ID string.
<!-- Return the current page's base URI -->
<base:structuredData.idref id=""/>
<!-- Return the normalized ID of the john-doe object (based on the current page URL as) -->
<base:structuredData.idref id="#john-doe"/>
<!-- Return the ID of the john-doe object as top-level object (based on the current site URL) -->
<base:structuredData.idref id="#john-doe" global="1"/>
<!-- Return a JSON reference to the john-doe object ({@id: '...#john-doe'}) -->
<base:structuredData.idref id="#john-doe" object="1"/>
Enables you to register a particular data object as "main entity" for nested fluid operations. <base:structuredData.entityContext.get>
will return the ID of the current main entity, also within nested partials.
<base:structuredData.entityContext.wrap id="#john-doe">
<!-- Inside here the john-doe object is considered the "main entity" -->
<f:variable name="mainEntity" value="{base:structuredData.entityContext.get()}"/>
<base:structuredData.set id="{$mainEntity}" key="additionalName" value="Jack"/>
</base:structuredData.entityContext.wrap>
Use this viewhelper to output the aggregated structured data objects. This can be placed in the footer of a page, e.g. in a Fluid layout. The boolean pretty
parameter can be used to pretty-print the output (just for readabilty).
<base:structuredData pretty="true"/>
This will e.g. output:
<script type="application/ld+json">{
"@context": "http:\/\/schema.org",
"@graph": [
{
"@type": "WebPage",
"@id": "https:\/\/stage.tollwerk.de\/"
},
{
"@type": "Organization",
"@id": "https:\/\/tollwerk.de\/#organization",
"@reverse": {
"publisher": [
{
"@id": "https:\/\/stage.tollwerk.de\/"
}
]
},
"name": "tollwerk GmbH",
"url": "https:\/\/tollwerk.de",
"logo": {
"@type": "ImageObject",
"@id": "https:\/\/tollwerk.de\/#logo",
"url": "https:\/\/tollwerk.de\/t.png"
}
}
]
}</script>