PHPackages                             ttree/linkeddata - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. ttree/linkeddata

ActiveNeos-package[Utility &amp; Helpers](/categories/utility)

ttree/linkeddata
================

Neos CMS helpers to generate JSON-LD (LinkedData)

1.1.0(1mo ago)1111.7k5[2 issues](https://github.com/ttreeagency/LinkedData/issues)2MITPHP

Since Jun 20Pushed 1mo ago5 watchersCompare

[ Source](https://github.com/ttreeagency/LinkedData)[ Packagist](https://packagist.org/packages/ttree/linkeddata)[ RSS](/packages/ttree-linkeddata/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependencies (2)Versions (9)Used By (2)

JSON Linked Data Helpers for Neos CMS
=====================================

[](#json-linked-data-helpers-for-neos-cms)

This package extend the Neos Content Respository Node Type configuration to convert Node or collection of Nodes to JSON-LD.

Installation
------------

[](#installation)

```
composer require ttree/linkeddata

```

Features
--------

[](#features)

- Support simple document
- Use EEL queries
- Support relation between document(s)
- Validation of the generated LinkedData

Add presets to your Node Type configuration
-------------------------------------------

[](#add-presets-to-your-node-type-configuration)

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`.

Understanding `context`
-----------------------

[](#understanding-context)

The context contains a list of key value pairs. All values are available in the EEL context during expression parsing.

Understanding `fragment`
------------------------

[](#understanding-fragment)

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).

Render the JSON-LD Graph in the HEAD section
--------------------------------------------

[](#render-the-json-ld-graph-in-the-head-section)

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.

Render the JSON-LD Graph inside your document BODY
--------------------------------------------------

[](#render-the-json-ld-graph-inside-your-document-body)

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}
}

```

Render JSON-LD from Settings or custom EEL helpers
--------------------------------------------------

[](#render-json-ld-from-settings-or-custom-eel-helpers)

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.

Available EEL Helpers
---------------------

[](#available-eel-helpers)

LinkedData.render
-----------------

[](#linkeddatarender)

```
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
--------------------

[](#linkeddatarenderraw)

```
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
---------------

[](#linkeddatalist)

```
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
---------------

[](#linkeddataitem)

```
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.

Acknowledgments
---------------

[](#acknowledgments)

Development sponsored by [ttree ltd - neos solution provider](http://ttree.ch).

We try our best to craft this package with a lots of love, we are open to sponsoring, support request, ... just contact us.

License
-------

[](#license)

Licensed under MIT, see [LICENSE](LICENSE)

###  Health Score

56

—

FairBetter than 97% of packages

Maintenance88

Actively maintained with recent releases

Popularity34

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 80% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~463 days

Recently: every ~711 days

Total

8

Last Release

43d ago

Major Versions

0.2.1 → 1.0.02018-07-26

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/145363?v=4)[ttree](/maintainers/ttree)[@ttree](https://github.com/ttree)

---

Top Contributors

[![dfeyer](https://avatars.githubusercontent.com/u/221173?v=4)](https://github.com/dfeyer "dfeyer (12 commits)")[![73nici](https://avatars.githubusercontent.com/u/30949443?v=4)](https://github.com/73nici "73nici (1 commits)")[![gjwnc](https://avatars.githubusercontent.com/u/19683930?v=4)](https://github.com/gjwnc "gjwnc (1 commits)")[![lcherpit](https://avatars.githubusercontent.com/u/490499?v=4)](https://github.com/lcherpit "lcherpit (1 commits)")

### Embed Badge

![Health badge](/badges/ttree-linkeddata/health.svg)

```
[![Health](https://phpackages.com/badges/ttree-linkeddata/health.svg)](https://phpackages.com/packages/ttree-linkeddata)
```

###  Alternatives

[sitegeist/kaleidoscope

Responsive-images for Neos

29364.3k11](/packages/sitegeist-kaleidoscope)[kaufmanndigital/gdpr-cookieconsent

A ready-to-run package, that integrates an advanced cookie consent banner into your Neos CMS site.

2541.8k](/packages/kaufmanndigital-gdpr-cookieconsent)[neos/seo

SEO configuration and tools for Neos

131.0M28](/packages/neos-seo)[techdivision/ckstyles

Neos package which enables you adding your custom style classes for the CkEditor with a simple Yaml configuration

21175.8k](/packages/techdivision-ckstyles)[sitegeist/taxonomy

Manage vocabularies and taxonomies as separate node-hierarchy.

1593.1k1](/packages/sitegeist-taxonomy)[shel/neos-colorpicker

A plugin for Neos CMS which provides a colorpicker editor

14101.5k6](/packages/shel-neos-colorpicker)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
