brick/structured-data
Generate, parse, and validate Schema.org structured data in PHP. brick/structured-data helps you build JSON-LD and other formats with a typed API, ensuring correct properties and values for SEO-rich pages and interoperable metadata.
Installation
composer require brick/structured-data:^0.2.0
composer.json if using a monorepo or custom package management.First Use Case: Reading Structured Data
use Brick\StructuredData\Reader\Reader;
use Brick\StructuredData\Reader\ReaderFactory;
$reader = ReaderFactory::create();
$data = $reader->readFromHtml('<div itemscope itemtype="https://schema.org/Person">...</div>');
Where to Look First
src/Reader/ for core parsing logic (all classes are now final in v0.2.0)tests/ for real-world examples (e.g., JSON-LD, Microdata, RDFa)$html = file_get_contents('https://example.com');
$reader = ReaderFactory::create();
$structuredData = $reader->readFromHtml($html);
// Extract specific data (e.g., Schema.org Person)
$people = $structuredData->getItemsOfType('Person');
foreach ($people as $person) {
echo $person->getPropertyValue('name');
}
$jsonLd = json_decode(file_get_contents('data.json'), true);
$reader = ReaderFactory::create();
$structuredData = $reader->readFromJsonLd($jsonLd);
// Validate or transform data
$valid = $structuredData->validate();
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind(Reader::class, function () {
return ReaderFactory::create();
});
}
// app/Http/Middleware/ParseStructuredData.php
public function handle($request, Closure $next)
{
$reader = app(Reader::class);
$data = $reader->readFromHtml($request->getContent());
$request->merge(['structured_data' => $data]);
return $next($request);
}
$urls = ['https://example.com/page1', 'https://example.com/page2'];
$reader = ReaderFactory::create();
foreach ($urls as $url) {
$html = file_get_contents($url);
$data = $reader->readFromHtml($html);
// Store in DB or process
}
$item = $structuredData->getItemsOfType('Product')->first();
$price = $item->getPropertyValue('offers', 'price'); // Nested properties
// Compatible with `sabre/uri` v3 (updated dependency)
$reader = ReaderFactory::create(['uri_resolver' => new \Sabre\Uri\Uri()]);
PHP 8.1 Requirement (Breaking Change)
php -v # Verify version
composer.json constraints if needed:
"require": {
"php": "^8.1"
}
Final Classes (Breaking Change)
Brick\StructuredData are now final. No inheritance possible.HTML Parsing Quirks
DOMDocument to clean input first:
$dom = new DOMDocument();
@$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$cleanHtml = $dom->saveHTML();
$reader->readFromHtml($cleanHtml);
Namespace Conflicts
Person vs. custom types (e.g., App\\Person). Prefix or validate types explicitly:
if ($item->getType() !== 'https://schema.org/Person') {
continue;
}
Performance with Large JSON-LD
$reader->readFromJsonLdStream(fopen('large.jsonld', 'r'));
$reader = ReaderFactory::create(['verbose' => true]);
$rawData = $reader->readFromHtml($html)->getRawData();
dd($rawData); // Debug with Laravel's `dd()`
Decorators for Extensibility
Since classes are final, use decorators to wrap functionality:
class StructuredDataDecorator {
private $reader;
public function __construct(Reader $reader) {
$this->reader = $reader;
}
public function readWithCustomLogic(string $html): StructuredData {
$data = $this->reader->readFromHtml($html);
// Add custom logic here
return $data;
}
}
Plugin System via Callbacks Use listener-like patterns (if supported) or attach callbacks:
$reader = ReaderFactory::create();
$reader->addPostProcessCallback(function (StructuredData $data) {
// Post-process all items
foreach ($data->getItems() as $item) {
// Custom logic
}
});
Laravel Service Extensions
Publish config or extend the reader via boot() in a service provider:
public function boot()
{
$reader = app(Reader::class);
$reader->setDefaultNamespace('https://myapp.org/');
}
Default Namespaces
Configure globally in ReaderFactory:
$reader = ReaderFactory::create([
'default_namespaces' => [
'schema' => 'https://schema.org/',
'myapp' => 'https://myapp.org/',
]
]);
Case Sensitivity Property names are case-sensitive. Normalize inputs:
$normalized = strtolower($propertyName);
URI Resolver (New in v0.2.0)
Explicitly set a sabre/uri v3-compatible resolver:
$reader = ReaderFactory::create([
'uri_resolver' => new \Sabre\Uri\Uri(),
]);
How can I help you explore Laravel packages today?