Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Json Ld Bundle Laravel Package

secit-pl/json-ld-bundle

A Symfony bundle for generating JSON-LD structured data in your applications. It provides services and Twig helpers to define schema.org objects, embed SEO-friendly rich snippets, and improve search visibility with minimal configuration and flexible integration.

View on GitHub
Deep Wiki
Context7

Getting Started

First, re-scope the framing. secit-pl/json-ld-bundle is a Symfony bundle (2.8 / 3.0+), not a Laravel package. There is no extra.laravel.providers, no facade, no publishable config, no migrations. A Laravel developer's day-one task is therefore not "install and configure" but "decide how much of this I actually need."

Minimal steps:

  1. Check what you'd be pulling in. composer require secit-pl/json-ld-bundle --dry-run and read the dependency diff. The bundle's own composer.json will require symfony/framework-bundle (or symfony/symfony), which drags Symfony DI/HttpKernel/Config into an app that already has illuminate/*. Some overlap is harmless; the boot-time bundle registration never runs because Laravel has no Symfony kernel bundle loop.
  2. Read the source, not the docs. The docs describe Twig helpers and services.yaml wiring that are dead weight in Laravel. What you actually want is the small set of plain-PHP builder classes behind them (Thing, Organization, Product, BreadcrumbList, and their property traits). Confirm they have no constructor dependencies on the container.
  3. First use case: one page, one graph. Take a product detail page and emit a Product with offers and a BreadcrumbList. Do it in a controller or a view composer, dump the string to the log, and paste it into Google's Rich Results Test before you touch a Blade template.
  4. Set the abandonment expectation now. Last release 2017-11-10, 6 stars, single maintainer. Treat this as source you are adopting, not a dependency you are tracking. Budget for vendoring the builder classes into app/Support/JsonLd/ and owning them.

If you want a Laravel-native, maintained alternative on the same problem, spatie/schema-org is the obvious comparison and is worth 20 minutes before you commit to this one.

Implementation Patterns

Pattern 1 — Builder as a plain object, rendered in a controller.

$product = (new Product())
    ->setName($model->name)
    ->setDescription(Str::limit($model->description, 200))
    ->setSku($model->sku)
    ->setOffers((new Offer())->setPrice($model->price)->setPriceCurrency('GBP'));

return view('products.show', ['jsonLd' => $product->toJson()]);

The value of the package is entirely in these fluent setters and the nesting behaviour — the json_encode is trivial. If the builders are clean, this is a 20-line extraction, not a bundle.

Pattern 2 — Blade directive for output.

// AppServiceProvider::boot()
Blade::directive('jsonLd', fn ($expr) => "<?php echo '<script type=\"application/ld+json\">' . ($expr) . '</script>'; ?>");

Then in your layout: @jsonLd($jsonLd ?? ''). Keep it out of {{ }} — Blade escapes, and you'd get &quot; everywhere.

Pattern 3 — Global site graph via a view composer. Organization, WebSite with a SearchAction, and the logo belong on every page, not per-controller. Register one composer on your layout and merge it with page-level entities into a single @graph block:

{"@context":"https://schema.org","@graph":[ {...org...}, {...product...} ]}

One script block per page, not five. Multiple ld+json blocks are legal but you lose the ability to cross-reference nodes by @id.

Pattern 4 — Nesting and arrays. Breadcrumbs and ItemList are where the builder earns its keep: BreadcrumbList → array of ListItem with position and item. Build them in a dedicated BreadcrumbBuilder service so the trail logic lives in one place (route name → label mapping is not something the package can do for you).

Pattern 5 — Cache the string, not the object. For static-ish pages (homepage org graph, category pages), cache the rendered JSON with Cache::remember("jsonld:product:{$id}", 3600, fn () => $builder->toJson()). The builders build fast, but you don't want to re-run them in a layout that renders on every request.

Pattern 6 — Test the structure, not the string.

$data = json_decode($response->viewData('jsonLd'), true);
$this->assertSame('https://schema.org', $data['@context']);
$this->assertSame('Product', $data['@type']);
$this->assertArrayHasKey('offers', $data);

Assert on @type and required properties per Google's rich-result requirements — that's the contract that actually matters, and it survives a refactor or a swap to Spatie.

Gotchas and Tips

Framework coupling is the headline gotcha. The SecIT\JsonLdBundle class extends Symfony's Bundle; nothing instantiates it in Laravel. The Twig extension is unusable. Any services.yaml / Extension::load() examples in the README must be translated to a service provider — or, more likely, skipped entirely because the builders need no DI.

PHP 8 compatibility is unverified and likely. Code from 2017 predates PHP 7.2's object type, readonly, and strict dynamic-property handling in 8.2. Run php -l over the vendored classes and a single builder instantiation under your actual PHP version before building anything on top of it. If it errors on PHP 8.2+, you're now maintaining a fork on day one — factor that in.

Don't let the builders choose your escaping strategy. If any value comes from user input (product names, seller names, review text), json_encode alone can emit </script> inside a string and break out of the tag. Always encode with JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT if you're writing your own serializer; verify what the package's toJson() actually passes.

Missing properties fail silently. These builders set what you tell them to and nothing else. There is no schema validation. A Product without offers or image is invalid JSON-LD that nobody will tell you about — validate manually against the Rich Results Test during development and keep a feature test asserting the required keys.

@context and @type may be yours to set. Confirm the emitted output includes both at the root. When composing a @graph, @context goes once at the top level only.

Beware array vs single object. offers may legitimately be an object or an array; image likewise. Check exactly what the builder emits for one child vs many, and match Google's expectations — a single-element array where an object is expected is a common cause of "no rich result."

Config caching, Octane, and queues are non-issues if you vendor. Because there's no service provider, there's no boot cost, no cached-config drift, and no request-scoped state in singletons. This is the package's accidental strength in Laravel: adopted as plain classes, its operational footprint is zero. If you instead write a Laravel provider with a singleton builder, you've reintroduced exactly the state-leak risk the bundle avoided — make builders bind() (fresh per resolution), not singleton().

Extension point is inheritance, not configuration. Because the bundle is a thin wrapper, custom schema.org types mean extending the base Thing/Abstract type class and adding setters, then registering your subclass in whatever factory you write. There is no plugin registry here; that's fine for 3–4 custom types and painful beyond.

Write down why you chose this. Two years from now the next engineer will see a 2017-dated, 6-star Symfony bundle in composer.json and assume it's load-bearing framework glue. A // vendored from secit-pl/json-ld-bundle, builders only, no Symfony boot comment in composer.json and a one-paragraph ADR in the repo saves a half-day of confused archaeology — probably more than the package itself saves you.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource