PHPackages                             blackpig-creatif/sceau - 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. blackpig-creatif/sceau

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

blackpig-creatif/sceau
======================

SEO and social media optimization for FilamentPHP v5

v2.0.1(2mo ago)075MITPHPPHP ^8.3|^8.4

Since Feb 9Pushed 2mo agoCompare

[ Source](https://github.com/Blackpig/sceau)[ Packagist](https://packagist.org/packages/blackpig-creatif/sceau)[ Docs](https://github.com/blackpig-creatif/sceau)[ RSS](/packages/blackpig-creatif-sceau/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (33)Versions (15)Used By (0)

Sceau
=====

[](#sceau)

**SEO metadata management plugin for FilamentPHP v5**

Sceau provides comprehensive SEO metadata management for Laravel applications using Filament v5. It offers a polymorphic approach to SEO data, allowing any Eloquent model to have associated meta tags, Open Graph data, Twitter Cards, and JSON-LD structured data.

Features
--------

[](#features)

- **Polymorphic SEO Data** - Attach SEO metadata to any Eloquent model
- **Filament Integration** - Manage SEO through a clean RelationManager interface
- **Meta Tags** - Title, description, canonical URLs, robots directives
- **Social Media** - Open Graph and Twitter Card support
- **Structured Data** - Extensible JSON-LD schema generators for Schema.org markup
- **Settings Management** - Database-backed global SEO settings via Filament panel
- **Image Processing** - Integrated with Chambre Noir for optimized OG/Twitter images
- **Atelier Integration** - Automatic schema generation from content blocks with no controller boilerplate
- **Blade Component** - Simple `@seo($model)` directive for frontend rendering

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 11.0+ or 12.0+
- Filament 5.0+

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

[](#installation)

```
composer require blackpig-creatif/sceau
```

Run the migration:

```
php artisan migrate
```

Optionally publish the config file:

```
php artisan vendor:publish --tag=sceau-config
```

Basic Usage
-----------

[](#basic-usage)

### 1. Add the Trait to Your Model

[](#1-add-the-trait-to-your-model)

```
use BlackpigCreatif\Sceau\Concerns\HasSeoData;

class Page extends Model
{
    use HasSeoData;
}
```

### 2. Add the RelationManager to Your Filament Resource

[](#2-add-the-relationmanager-to-your-filament-resource)

```
use BlackpigCreatif\Sceau\Filament\RelationManagers\SeoDataRelationManager;

class PageResource extends Resource
{
    public static function getRelations(): array
    {
        return [
            SeoDataRelationManager::class,
        ];
    }
}
```

### 3. Render SEO Tags in Your Layout

[](#3-render-seo-tags-in-your-layout)

```

    @seo($page)

```

Or use the component directly:

```

```

Configuration
-------------

[](#configuration)

The config file (`config/sceau.php`) allows you to customize:

- **Upload disk and directory** for OG/Twitter images
- **Character limits** for titles and descriptions
- **Default values** for robots directives, OG types, Twitter card types
- **Available schema types** (filter which types appear in the select)

### Global SEO Settings

[](#global-seo-settings)

Sceau includes a settings page accessible from your Filament panel at **Settings &gt; SEO Settings**. Configure:

- Site name and URL
- Contact information (phone, email)
- Business address
- Price range and opening hours (for LocalBusiness schema)

To add the settings page to your panel, register the plugin:

```
use BlackpigCreatif\Sceau\SceauPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            SceauPlugin::make(),
        ]);
}
```

Schema Architecture
-------------------

[](#schema-architecture)

Sceau uses a **dual-layer approach** to schema generation:

1. **Model-Level Schemas** (SeoData) - For entity-specific metadata (Organization, LocalBusiness, Product models)
2. **Runtime Schemas** (SchemaStack) - For page-specific content assembled at request time

This separation aligns with how modern web applications work: pages are built dynamically from blocks, products are fetched by controllers, and breadcrumbs depend on the current route.

### Model-Level Schemas (SeoData)

[](#model-level-schemas-seodata)

These schemas describe entities that exist as models in your database:

- **Organization** - Company/organization data from settings
- **LocalBusiness** - Business with address/hours from settings
- **Product** - For dedicated Product models with SEO data
- **Person** - For author/profile models

Configure these through the Filament RelationManager on your models.

### Runtime Schemas (SchemaStack)

[](#runtime-schemas-schemastack)

These schemas describe content assembled at runtime:

- **Article/BlogPosting** - Built from Atelier blocks
- **ItemList** - Product listings, search results
- **BreadcrumbList** - Navigation breadcrumbs
- **FAQPage** - FAQ blocks on pages
- **VideoObject** - Video blocks

Runtime Schema Generation
-------------------------

[](#runtime-schema-generation)

### The Schema Facade

[](#the-schema-facade)

Push schemas onto the stack during request processing:

```
use BlackpigCreatif\Sceau\Facades\Schema;

public function show(Page $page)
{
    $products = Product::where('category_id', $page->category_id)->paginate(24);

    Schema::push([
        '@context' => 'https://schema.org',
        '@type' => 'ItemList',
        'numberOfItems' => $products->total(),
        'itemListElement' => $products->map(fn ($product, $index) => [
            '@type' => 'ListItem',
            'position' => $index + 1,
            'item' => [
                '@type' => 'Product',
                'name' => $product->name,
                'url' => route('products.show', $product),
            ],
        ])->values()->toArray(),
    ]);

    return view('pages.show', compact('page', 'products'));
}
```

### Runtime Schema Helpers

[](#runtime-schema-helpers)

Use helper classes for common patterns:

```
use BlackpigCreatif\Sceau\Facades\Schema;
use BlackpigCreatif\Sceau\Schemas\Runtime\ProductListSchema;
use BlackpigCreatif\Sceau\Schemas\Runtime\BreadcrumbListSchema;

public function show(Page $page)
{
    $products = Product::paginate(24);

    Schema::push(ProductListSchema::makeDetailed($products));

    Schema::push(BreadcrumbListSchema::make([
        ['name' => 'Home', 'url' => route('home')],
        ['name' => 'Products', 'url' => route('products.index')],
        ['name' => $page->category->name, 'url' => route('category', $page->category)],
    ]));

    return view('pages.show', compact('page', 'products'));
}
```

**Available helpers:**

- `ArticleSchema::fromBlocks($blocks, $seoData)` - Generate Article from Atelier blocks
- `ProductListSchema::make($products, $transformer)` - Generate ItemList
- `ProductListSchema::makeDetailed($products)` - ItemList with pricing/images
- `BreadcrumbListSchema::make($breadcrumbs)` - Generate BreadcrumbList

### Multiple Schemas Per Page

[](#multiple-schemas-per-page)

Schema.org supports (and Google expects) multiple independent schemas on a single page:

```
public function show(Page $page)
{
    // Article content + typed block schemas from Atelier (auto-wired via Head component)

    // Additional runtime schemas pushed from the controller
    Schema::push(ProductListSchema::make($featuredProducts));

    Schema::push(BreadcrumbListSchema::make($breadcrumbs));
}
```

Final output will be an array of schemas, each validated independently by Google.

---

Atelier Block Integration
-------------------------

[](#atelier-block-integration)

When [Atelier](https://github.com/blackpig-creatif/atelier) is installed alongside Sceau, the `` component automatically generates Schema.org output from your page's blocks. No controller code is required.

```
{{-- This is all you need --}}

```

For the complete integration reference, see [docs/atelier-integration.md](docs/atelier-integration.md).

### How it works

[](#how-it-works)

The `Head` component calls `PageSchemaBuilder::build($page)` automatically for any model that has `publishedBlocks`. The builder runs three passes over the blocks:

1. **Article schema** — assembled from all blocks implementing `HasCompositeSchema` (text content, image URLs)
2. **Legacy standalone schemas** — blocks implementing `HasStandaloneSchema` that build the full schema array themselves
3. **Driver-based typed schemas** — blocks implementing `HasSchemaContribution` that declare a `SchemaType` and provide data; `SceauBlockSchemaDriver` constructs the schema array using Sceau's generators

### Wiring the driver

[](#wiring-the-driver)

In your application's `config/atelier.php`:

```
'schema_driver' => \BlackpigCreatif\Sceau\Schema\Drivers\SceauBlockSchemaDriver::class,
```

This registers `SceauBlockSchemaDriver` as the singleton implementation of `BlockSchemaDriverInterface`. The driver matches on `SchemaType` value and delegates construction to Sceau's schema generators.

### Built-in block schemas

[](#built-in-block-schemas)

BlockSchema output`TextBlock`Article body text`TextWithImageBlock`Article body text + image`TextWithTwoImagesBlock`Article body text + two images`GalleryBlock`Article image URLs`CarouselBlock`Article image URLs`VideoBlock``VideoObject``FaqsBlock``FAQPage`### Adding a new SchemaType

[](#adding-a-new-schematype)

To support a new type in `SceauBlockSchemaDriver`:

1. Add a case to the `match` expression in `resolveSchema()`
2. Add a `protected buildXxxSchema(array $data): ?array` method
3. Add a `fromXxx(array $data): array` static method to the corresponding schema generator

---

Extending SeoData Schemas
-------------------------

[](#extending-seodata-schemas)

### Overriding Methods in a Subclass

[](#overriding-methods-in-a-subclass)

Create a local schema class that extends one of the base generators:

```
namespace App\SEO\Schemas;

use BlackpigCreatif\Sceau\SchemaGenerators\ArticleSchema;
use BlackpigCreatif\Sceau\Models\SeoData;

class CustomArticleSchema extends ArticleSchema
{
    protected function getAuthor(SeoData $seoData): array|null
    {
        $page = $seoData->seoable;

        if ($page->authors && $page->authors->count() > 0) {
            return $page->authors->map(fn ($author) => [
                '@type' => 'Person',
                'name'  => $author->name,
                'url'   => route('authors.show', $author),
            ])->toArray();
        }

        return parent::getAuthor($seoData);
    }
}
```

Register your custom schema in `AppServiceProvider`:

```
use BlackpigCreatif\Sceau\Services\JsonLdGenerator;
use BlackpigCreatif\Sceau\Enums\SchemaType;
use App\SEO\Schemas\CustomArticleSchema;

public function boot(): void
{
    $generator = app(JsonLdGenerator::class);
    $generator->registerGenerator(
        SchemaType::Article,
        new CustomArticleSchema
    );
}
```

### Creating Custom Schema Types

[](#creating-custom-schema-types)

For schema types not included in the package:

```
namespace App\SEO\Schemas;

use BlackpigCreatif\Sceau\SchemaGenerators\BaseSchema;
use BlackpigCreatif\Sceau\Models\SeoData;

class CourseSchema extends BaseSchema
{
    public function getType(): string
    {
        return 'Course';
    }

    public function generate(SeoData $seoData): array
    {
        $schema = $this->baseSchema();
        $course = $seoData->seoable;

        $schema['name']        = $this->getName($seoData);
        $schema['description'] = $this->getDescription($seoData);
        $schema['provider']    = [
            '@type' => 'Organization',
            'name'  => config('app.name'),
        ];

        if ($course->price) {
            $schema['offers'] = [
                '@type'         => 'Offer',
                'price'         => $course->price,
                'priceCurrency' => 'USD',
            ];
        }

        return $this->removeNullValues($schema);
    }
}
```

### Container Binding for Global Override

[](#container-binding-for-global-override)

To replace a schema generator globally without touching the package:

```
use BlackpigCreatif\Sceau\SchemaGenerators\ArticleSchema;
use App\SEO\Schemas\CustomArticleSchema;

public function register(): void
{
    $this->app->bind(ArticleSchema::class, CustomArticleSchema::class);
}
```

---

Accessing SEO Data
------------------

[](#accessing-seo-data)

The `HasSeoData` trait provides convenient accessor methods:

```
$page = Page::with('seoData')->first();

$title       = $page->getSeoTitle();        // Falls back to $page->title or $page->name
$description = $page->getSeoDescription();
$hasSchema   = $page->seoData?->hasSchemaMarkup();
$hasFaq      = $page->seoData?->hasFaqPairs();

$ogTitle = $page->getSeoAttribute('open_graph.title', 'Default Title');
```

Advanced: Image Resolution
--------------------------

[](#advanced-image-resolution)

Sceau integrates with **Chambre Noir** for image processing and supports **Atelier** blocks for hero image resolution.

When rendering OG/Twitter images, the package will:

1. Check for explicitly uploaded images in SEO data
2. Fall back to the first published Atelier hero block's background image
3. Apply the appropriate Chambre Noir conversion (`og`, `twitter`, etc.)

Override this behavior by extending `SeoData` and customizing the image resolution methods.

---

Documentation
-------------

[](#documentation)

- [Atelier Integration](docs/atelier-integration.md) -- automatic block schema generation reference

---

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance83

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity60

Established project with proven stability

 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 ~13 days

Recently: every ~23 days

Total

9

Last Release

85d ago

Major Versions

v1.1.2 → v2.0.02026-04-01

PHP version history (2 changes)v1.0.0PHP ^8.2|^8.3|^8.4

v2.0.0PHP ^8.3|^8.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1029317?v=4)[Blackpig Créatif](/maintainers/Blackpig)[@Blackpig](https://github.com/Blackpig)

---

Top Contributors

[![Blackpig](https://avatars.githubusercontent.com/u/1029317?v=4)](https://github.com/Blackpig "Blackpig (11 commits)")

---

Tags

laravelseosocial mediafilamentfilamentphpopen-graphmeta-tagstwitter cardsblackpig-creatifsceau

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/blackpig-creatif-sceau/health.svg)

```
[![Health](https://phpackages.com/badges/blackpig-creatif-sceau/health.svg)](https://phpackages.com/packages/blackpig-creatif-sceau)
```

###  Alternatives

[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3915.5k](/packages/rawilk-profile-filament-plugin)[finity-labs/fin-mail

A powerful email template manager and composer for Filament with dynamic token replacement, template versioning, and inline email sending.

316.8k2](/packages/finity-labs-fin-mail)[statikbe/laravel-filament-flexible-content-blocks

The Laravel Filament Flexible Content Blocks package helps you to easily create content in Filament for any model, with predefined or custom blocks, and foreach block an extendable Blade view component.

17927.9k6](/packages/statikbe-laravel-filament-flexible-content-blocks)[codewithdennis/filament-select-tree

The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.

329575.9k35](/packages/codewithdennis-filament-select-tree)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17861.9k3](/packages/stephenjude-filament-jetstream)[mradder/filament-logger

Audit logging, activity tracking, exports, alerts, and dashboards for Filament admin panels.

2324.4k1](/packages/mradder-filament-logger)

PHPackages © 2026

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