PHPackages                             kalakotra/silverstripe-schemadata - 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. kalakotra/silverstripe-schemadata

ActiveSilverstripe-vendormodule[Utility &amp; Helpers](/categories/utility)

kalakotra/silverstripe-schemadata
=================================

Schema.org JSON-LD generator module for SilverStripe 6.x

1.0.4(3w ago)06↓100%MITPHPPHP ^8.2

Since Apr 17Pushed 3w agoCompare

[ Source](https://github.com/kalakotra/silverstripe-schemadata)[ Packagist](https://packagist.org/packages/kalakotra/silverstripe-schemadata)[ RSS](/packages/kalakotra-silverstripe-schemadata/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (2)Versions (5)Used By (0)

kalakotra/silverstripe-schemadata
=================================

[](#kalakotrasilverstripe-schemadata)

Schema.org JSON-LD generator module for SilverStripe 6.x.

Automatically injects a `` block into the page `` based on interface implementation, with no configuration and no assumptions about your model.

---

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

[](#installation)

```
composer require kalakotra/silverstripe-schemadata
sake dev/build flush=1
```

---

How It Works
------------

[](#how-it-works)

The module adds `SchemaExtension` to `ContentController`. On every request it checks whether the current Page class implements the `SchemaProvider` interface. If it does, it injects JSON-LD into the head. Nothing more.

**You control the data.** Schema classes accept scalar values, not `DataObject` instances. You construct them inside your Page class using data from your own model.

---

Available Schema Classes
------------------------

[](#available-schema-classes)

ClassSchema.org typeDescription`OrganizationSchema`OrganizationCompany / organization`LocalBusinessSchema`LocalBusinessLocal business with address and geo coordinates`ProductSchema`ProductProduct with price and availability`SeminarSchema`EducationEventSingle seminar / education session`EventSeriesSchema`EventSeriesListing page with multiple dates of the same event---

Quick Start
-----------

[](#quick-start)

### 1. Single JSON-LD block (Product, Organization, LocalBusiness, single event...)

[](#1-single-json-ld-block-product-organization-localbusiness-single-event)

Implement `SchemaProvider` on your Page class:

```
use Kalakotra\SchemaData\SchemaProvider;
use Kalakotra\SchemaData\Schema\ProductSchema;

class ProductPage extends Page implements SchemaProvider
{
    public function getSchemaData(): array
    {
        return (new ProductSchema(
            title:        $this->Title,
            url:          $this->AbsoluteLink(),
            description:  $this->Summary,
            price:        (float) $this->Price,
            currency:     'BAM',
            availability: $this->InStock ? 'in_stock' : 'out_of_stock',
            sku:          $this->SKU,
        ))->getSchemaData();
    }
}
```

### 2. EventSeries + multiple dates (listing page)

[](#2-eventseries--multiple-dates-listing-page)

Implement `EventSeriesProvider`, which extends `SchemaProvider`:

```
use Kalakotra\SchemaData\Contract\EventSeriesProvider;
use Kalakotra\SchemaData\Schema\EventSeriesSchema;
use Kalakotra\SchemaData\Schema\SeminarSchema;

class SeminarListingPage extends Page implements EventSeriesProvider
{
    public function getSchemaData(): array
    {
        $seminar = $this->Seminar();

        return (new EventSeriesSchema(
            title:         $seminar->Title,
            description:   $seminar->Summary,
            url:           $this->AbsoluteLink(),
            organizerName: 'My Company Ltd.',
            lecturerName:  $seminar->LecturerName,
        ))->getSchemaData();
    }

    public function getSubEventProviders(): array
    {
        $seminar = $this->Seminar();

        return $seminar->UpcomingDates()->map(
            fn($date) => new SeminarSchema(
                title:          $seminar->Title,
                startDate:      $date->dbObject('StartDate')->Rfc3339(),
                endDate:        $date->dbObject('EndDate')->Rfc3339(),
                url:            $date->SeminarPage()->AbsoluteLink(),
                seriesUrl:      $this->AbsoluteLink(),
                lecturerName:   $seminar->LecturerName,
                attendanceMode: $seminar->AttendanceMode,
                location: [
                    'name'   => $date->VenueName,
                    'street' => $date->Street,
                    'city'   => $date->City,
                ],
                price:   (float) $seminar->Price,
                soldOut: $date->Seats === 0,
            )
        )->toArray();
    }
}
```

### 3. Single date (child page)

[](#3-single-date-child-page)

```
use Kalakotra\SchemaData\SchemaProvider;
use Kalakotra\SchemaData\Schema\SeminarSchema;

class SeminarPage extends Page implements SchemaProvider
{
    public function getSchemaData(): array
    {
        $date    = $this->SeminarDate();
        $seminar = $date->Seminar();

        return (new SeminarSchema(
            title:          $seminar->Title,
            startDate:      $date->dbObject('StartDate')->Rfc3339(),
            endDate:        $date->dbObject('EndDate')->Rfc3339(),
            url:            $this->AbsoluteLink(),
            seriesUrl:      $this->Parent()->AbsoluteLink(),
            lecturerName:   $seminar->LecturerName,
            attendanceMode: $seminar->AttendanceMode,
            location: [
                'name'   => $date->VenueName,
                'street' => $date->Street,
                'city'   => $date->City,
            ],
            price:   (float) $seminar->Price,
            soldOut: $date->Seats === 0,
        ))->getSchemaData();
    }
}
```

---

SeminarSchema: Location Format
------------------------------

[](#seminarschema-location-format)

**Offline:**

```
location: [
    'name'    => 'Venue name',
    'street'  => 'Main Street 1',
    'city'    => 'Sarajevo',
    'country' => 'BA', // default
]
```

**Online:**

```
attendanceMode: 'online',
location: [
    'streamUrl' => 'https://zoom.us/j/...',
]
```

**Mixed:**

```
attendanceMode: 'mixed',
location: [
    'name'      => 'Venue name',
    'street'    => 'Main Street 1',
    'city'      => 'Sarajevo',
    'streamUrl' => 'https://zoom.us/j/...',
]
```

---

Custom Schema Class
-------------------

[](#custom-schema-class)

You can create any custom schema class, as long as it implements `SchemaProvider`:

```
use Kalakotra\SchemaData\SchemaProvider;

final class CourseSchema implements SchemaProvider
{
    public function __construct(
        private readonly string $name,
        private readonly string $provider,
        // ...
    ) {}

    public function getSchemaData(): array
    {
        return [
            '@context' => 'https://schema.org',
            '@type'    => 'Course',
            'name'     => $this->name,
            'provider' => ['@type' => 'Organization', 'name' => $this->provider],
        ];
    }
}
```

---

Disable on a Specific Page
--------------------------

[](#disable-on-a-specific-page)

Return an empty array from `getSchemaData()` and the module will inject nothing:

```
public function getSchemaData(): array
{
    if (!$this->ShowSchema) {
        return [];
    }
    // ...
}
```

---

Compatibility
-------------

[](#compatibility)

- PHP 8.2+
- SilverStripe 6.x
- No external dependencies

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance95

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~10 days

Total

4

Last Release

21d ago

### Community

Maintainers

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

---

Top Contributors

[![kalakotra](https://avatars.githubusercontent.com/u/3845734?v=4)](https://github.com/kalakotra "kalakotra (5 commits)")

### Embed Badge

![Health badge](/badges/kalakotra-silverstripe-schemadata/health.svg)

```
[![Health](https://phpackages.com/badges/kalakotra-silverstripe-schemadata/health.svg)](https://phpackages.com/packages/kalakotra-silverstripe-schemadata)
```

###  Alternatives

[silverstripe/userforms

UserForms enables CMS users to create dynamic forms via a drag and drop interface and without getting involved in any PHP code

1371.1M83](/packages/silverstripe-userforms)[symbiote/silverstripe-advancedworkflow

Adds configurable workflow support to the CMS, with a GUI for creating custom workflow definitions.

46299.9k9](/packages/symbiote-silverstripe-advancedworkflow)[silverstripe/sharedraftcontent

Share draft page content with non-CMS users

21419.6k11](/packages/silverstripe-sharedraftcontent)

PHPackages © 2026

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