PHPackages                             rasuvaeff/yii3-seo - 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. rasuvaeff/yii3-seo

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

rasuvaeff/yii3-seo
==================

Next.js-style typed SEO metadata for Yii3: title templates, OpenGraph, Twitter cards, hreflang, canonical URL, robots directives and JSON-LD

v1.0.2(3w ago)02BSD-3-ClausePHPPHP 8.3 - 8.5CI passing

Since Jun 4Pushed 1w agoCompare

[ Source](https://github.com/rasuvaeff/yii3-seo)[ Packagist](https://packagist.org/packages/rasuvaeff/yii3-seo)[ Docs](https://github.com/rasuvaeff/yii3-seo)[ RSS](/packages/rasuvaeff-yii3-seo/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependencies (23)Versions (4)Used By (0)

rasuvaeff/yii3-seo
==================

[](#rasuvaeffyii3-seo)

[![Stable Version](https://camo.githubusercontent.com/84dc9279c2bc796c696933054e69e87a99bff365273d580d192ed0ffd3deca4c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7261737576616566662f796969332d73656f2e737667)](https://packagist.org/packages/rasuvaeff/yii3-seo)[![Total Downloads](https://camo.githubusercontent.com/db3410b2fd57267733d75f96a83ecc328a320cb2a15395017685169c9f4764aa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7261737576616566662f796969332d73656f2e737667)](https://packagist.org/packages/rasuvaeff/yii3-seo)[![Build](https://github.com/rasuvaeff/yii3-seo/actions/workflows/build.yml/badge.svg)](https://github.com/rasuvaeff/yii3-seo/actions/workflows/build.yml)[![Static analysis](https://github.com/rasuvaeff/yii3-seo/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/rasuvaeff/yii3-seo/actions/workflows/static-analysis.yml)[![Quality](https://github.com/rasuvaeff/yii3-seo/actions/workflows/code-quality.yml/badge.svg)](https://github.com/rasuvaeff/yii3-seo/actions/workflows/code-quality.yml)[![Security](https://github.com/rasuvaeff/yii3-seo/actions/workflows/security.yml/badge.svg)](https://github.com/rasuvaeff/yii3-seo/actions/workflows/security.yml)[![Psalm level](https://camo.githubusercontent.com/fdc04eeb7aa15c2728142c33d987263e60451bc54f2dc67dbab7684fc37f0dc7/68747470733a2f2f73686570686572642e6465762f6769746875622f7261737576616566662f796969332d73656f2f6c6576656c2e737667)](https://shepherd.dev/github/rasuvaeff/yii3-seo)[![PHP](https://camo.githubusercontent.com/603dd348db5cbbbde3903f4fd100e4f2fac32695581c3305a56b6b1216161bc2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f7261737576616566662f796969332d73656f2f706870)](https://packagist.org/packages/rasuvaeff/yii3-seo)[![License](https://camo.githubusercontent.com/7c8924bcb941bf1201b4f42e8ae00a200101f8ae76fe97dc42b312926cb2643b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7261737576616566662f796969332d73656f2e737667)](LICENSE.md)[Русская версия](README.ru.md)

Next.js-style typed SEO metadata for Yii3. Describe a page with one declarative `Metadata` object — title templates, OpenGraph, Twitter cards, hreflang, canonical URL, robots directives, icons, verification and JSON-LD — and a single `MetadataDefaults` instance supplies site-wide values. Tags land in `` automatically via `WebViewRenderer`.

> Using an AI coding assistant? [llms.txt](llms.txt) has a compact API reference ready to paste into context.

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

[](#requirements)

- PHP 8.3+
- `yiisoft/html` ^3.13
- `yiisoft/yii-view-renderer` ^7.4

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

[](#installation)

```
composer require rasuvaeff/yii3-seo
```

Concept
-------

[](#concept)

The API mirrors the Next.js Metadata API:

Next.jsyii3-seo`export const metadata = { ... }` (page)`new Metadata(...)` dispatched per requestlayout `metadata` (defaults)`MetadataDefaults` in DI params`title.template` / `default` / `absolute``Title::template()` / `Title::absolute()``alternates.canonical` / `languages``Alternates``openGraph` / `twitter``OpenGraph` + `OgImage` / `TwitterCard``metadataBase``MetadataDefaults(metadataBase: ...)`Defaults are merged with the page metadata: the title template wraps the page title, OpenGraph/Twitter inherit unset fields, and relative URLs are resolved against `metadataBase`.

Usage
-----

[](#usage)

### 1. Site-wide defaults (params)

[](#1-site-wide-defaults-params)

```
// config/common/params.php
use Rasuvaeff\Yii3Seo\MetadataDefaults;
use Rasuvaeff\Yii3Seo\OpenGraph;
use Rasuvaeff\Yii3Seo\Title;
use Rasuvaeff\Yii3Seo\TwitterCard;

return [
    'rasuvaeff/yii3-seo' => [
        'defaults' => new MetadataDefaults(
            metadataBase: 'https://example.com',
            title: Title::template('%s | My Store', default: 'My Store'),
            openGraph: new OpenGraph(siteName: 'My Store', locale: 'en_US'),
            twitter: new TwitterCard(card: 'summary_large_image', site: '@mystore'),
        ),
    ],
];
```

### 2. Register `SeoInjection` in the view DI config

[](#2-register-seoinjection-in-the-view-di-config)

```
// config/common/di.php
use Rasuvaeff\Yii3Seo\SeoInjection;
use Yiisoft\Yii\View\Renderer\CsrfViewInjection;
use Yiisoft\Yii\View\Renderer\WebViewRenderer;

return [
    WebViewRenderer::class => [
        '__construct()' => [
            'injections' => [
                CsrfViewInjection::class,
                SeoInjection::class,
            ],
        ],
    ],
];
```

### 3. Wire the event handler

[](#3-wire-the-event-handler)

```
// config/common/events.php
use Rasuvaeff\Yii3Seo\SeoMetadataEvent;
use Rasuvaeff\Yii3Seo\SetSeoMetadataEventHandler;

return [
    SeoMetadataEvent::class => [[SetSeoMetadataEventHandler::class, '__invoke']],
];
```

### 4. Dispatch `SeoMetadataEvent` from your action

[](#4-dispatch-seometadataevent-from-your-action)

```
use Psr\EventDispatcher\EventDispatcherInterface;
use Rasuvaeff\Yii3Seo\Alternates;
use Rasuvaeff\Yii3Seo\Metadata;
use Rasuvaeff\Yii3Seo\OgImage;
use Rasuvaeff\Yii3Seo\OpenGraph;
use Rasuvaeff\Yii3Seo\SeoMetadataEvent;

final readonly class ProductAction
{
    public function __construct(
        private EventDispatcherInterface $eventDispatcher,
        private ProductResponder $responder,
    ) {}

    public function __invoke(): ResponseInterface
    {
        $this->eventDispatcher->dispatch(new SeoMetadataEvent(
            metadata: new Metadata(
                title: 'Awesome Product',                 // -> "Awesome Product | My Store"
                description: 'Buy the awesome product.',
                alternates: new Alternates(
                    canonical: '/products/awesome',        // resolved against metadataBase
                    languages: [
                        'en'        => '/en/products/awesome',
                        'ru'        => '/ru/products/awesome',
                        'x-default' => '/products/awesome',
                    ],
                ),
                openGraph: new OpenGraph(
                    type: 'product',
                    images: [new OgImage(url: '/og/awesome.jpg', width: 1200, height: 630, alt: 'Awesome')],
                ),
            ),
        ));

        return $this->responder->render('product/view');
    }
}
```

`og:title`/`og:description` fall back to the page title/description, and `twitter:*` falls back to OpenGraph — no need to repeat them.

### 5. Title and JSON-LD in layout

[](#5-title-and-json-ld-in-layout)

`` and `` are not covered by the injection interfaces. Inject `SeoInjection` into your layout and render manually:

```

```

Public API
----------

[](#public-api)

### `Metadata`

[](#metadata)

Immutable declarative object (all fields optional). A `string` title is normalized to `Title::of()`.

FieldTypeRenders`title``string|Title``` (template applied)`description``string````keywords``list````authors``list``` + ```applicationName`, `generator`, `creator`, `publisher``string`matching ```themeColor`, `colorScheme``string``theme-color`, `color-scheme``robots``Robots``` / `googlebot``alternates``Alternates`canonical + hreflang links`openGraph``OpenGraph``og:*``twitter``TwitterCard``twitter:*``icons``Icons``` etc.`manifest``string````verification``Verification`verification ```jsonLd``list````other``list`custom ``### `MetadataDefaults`

[](#metadatadefaults)

Site-wide defaults: `metadataBase`, `title` (template/default), `applicationName`, `generator`, `themeColor`, `colorScheme`, `robots`, `openGraph`, `twitter`, `icons`, `verification`, `jsonLd`, `other`. Provide via the `rasuvaeff/yii3-seo` → `defaults` parameter.

### `Title`

[](#title)

FactoryUse`Title::of('Home')`page title, template applied`Title::absolute('Home')`page title, template bypassed`Title::template('%sAcme', default: 'Acme')`### `Alternates`

[](#alternates)

```
new Alternates(
    canonical: '/page',
    languages: ['en' => '/en', 'en-US' => '/us', 'x-default' => '/'],
)
```

Locales match `/^(?:[a-z]{2}(?:-[A-Z]{2})?|x-default)$/`.

### `OpenGraph` + `OgImage`

[](#opengraph--ogimage)

```
new OpenGraph(
    title: null,            // falls back to Metadata title
    description: null,      // falls back to Metadata description
    type: null,             // inherits defaults; renders og:type "website" if unset everywhere
    url: '/page',           // resolved against metadataBase
    siteName: 'My Site',
    locale: 'en_US',
    images: [new OgImage(url: '/og.jpg', width: 1200, height: 630, alt: 'Alt', type: 'image/jpeg')],
)
```

### `TwitterCard`

[](#twittercard)

```
new TwitterCard(
    card: null,                     // summary | summary_large_image | app | player; inherits defaults, renders "summary_large_image" if unset everywhere
    site: '@site',
    creator: '@creator',
    title: null,                    // falls back to OpenGraph/title
    description: null,              // falls back to OpenGraph/description
    images: [],                     // falls back to OpenGraph images
)
```

### `Robots`

[](#robots)

Factory / methodDirective`Robots::index()``index, follow``Robots::noindex()` / `nofollow()` / `none()` / `noarchive()`matching directives`new Robots(['noindex', 'nosnippet'])`custom combination`->withNoSnippet()` / `->withNoImageIndex()`append directive`->withMaxSnippet(-1)` / `->withMaxImagePreview('large')` / `->withMaxVideoPreview(30)`Google `max-*``->withGoogleBot('noindex', ...)`separate ``### `Icons` / `Icon`, `Verification`, `Author`

[](#icons--icon-verification-author)

```
new Icons(icon: '/favicon.ico', shortcut: '/favicon.ico', apple: '/apple.png', other: [
    new Icon(rel: 'mask-icon', url: '/safari.svg'),
]);

new Verification(google: 'g-token', yandex: 'y-token', bing: 'b-token', other: ['me' => 'token']);

new Author(name: 'Alice', url: 'https://example.com/alice');
```

### `MetaTag`

[](#metatag)

FactoryAttribute`MetaTag::name(name, content)``name="..."``MetaTag::property(property, content)``property="..."``MetaTag::httpEquiv(httpEquiv, content)``http-equiv="..."`### `JsonLd`

[](#jsonld)

```
JsonLd::fromArray(['@context' => 'https://schema.org', '@type' => 'WebPage', 'name' => 'Home'])
```

Renders as `` with `JSON_HEX_TAG` to prevent `` injection.

### `SeoInjection`

[](#seoinjection)

Singleton registered in DI. Implements `MetaTagsInjectionInterface` + `LinkTagsInjectionInterface`. The package DI config also registers a service `reset` hook, so stale per-request metadata is cleared between requests in reusable runtimes.

MethodDescription`setMetadata(Metadata)`Set metadata for the current request`clear()`Reset (useful in tests)`getTitle(): string`Resolved title for ```getMetaTags(): list`Called by `WebViewRenderer``getLinkTags(): array`Called by `WebViewRenderer``getJsonLdHtml(): string`Rendered JSON-LD `` blocksSecurity
--------

[](#security)

- Crawler-facing URLs (canonical, hreflang, `og:image`, `og:url`, `twitter:image`) are resolved against `metadataBase`; absolute URLs are validated with `FILTER_VALIDATE_URL`. A relative URL with no base throws `InvalidArgumentException`.
- HTML escaping is handled by `Yiisoft\Html` — no raw string concatenation.
- JSON-LD uses `JSON_HEX_TAG` to prevent `` injection.

Examples
--------

[](#examples)

See [`examples/`](examples/) for runnable scripts and a Yii3 integration sketch: [`examples/yii3-app.php`](examples/yii3-app.php).

Development
-----------

[](#development)

```
make install    # composer install
make build      # full gate: validate + normalize + require-checker + cs + psalm + test
make cs-fix     # fix code style
make test       # run testo
make test-coverage  # run testo with pcov coverage
make mutation       # run infection with pcov coverage
```

License
-------

[](#license)

BSD-3-Clause. See [LICENSE.md](LICENSE.md).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance97

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 73.1% 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 ~12 days

Total

3

Last Release

25d ago

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

v1.0.1PHP 8.3 - 8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/b0812d5572a7041dfe36e222d295b2e6dc55833a605350fcde58a51a5965ed30?d=identicon)[rasuvaeff](/maintainers/rasuvaeff)

---

Top Contributors

[![rasuvaeff](https://avatars.githubusercontent.com/u/1352718?v=4)](https://github.com/rasuvaeff "rasuvaeff (19 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (7 commits)")

---

Tags

canonicaljson-ldmetadataopengraphrobotsseo-optimizationtwitter-cardsyii3yii3-extensionsmetadataJSON-LDseometaopengraphyii3twitter cardshreflang

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/rasuvaeff-yii3-seo/health.svg)

```
[![Health](https://phpackages.com/badges/rasuvaeff-yii3-seo/health.svg)](https://phpackages.com/packages/rasuvaeff-yii3-seo)
```

###  Alternatives

[artesaos/seotools

SEO Tools for Laravel and Lumen

3.4k5.4M63](/packages/artesaos-seotools)[honeystone/laravel-seo

SEO metadata and JSON-LD package for Laravel.

35590.0k](/packages/honeystone-laravel-seo)[nystudio107/craft-seomatic

SEOmatic facilitates modern SEO best practices &amp; implementation for Craft CMS 5. It is a turnkey SEO system that is comprehensive, powerful, and flexible.

1741.5M68](/packages/nystudio107-craft-seomatic)[vaersaagod/seomate

SEO, mate! It's important.

4442.8k2](/packages/vaersaagod-seomate)[kunstmaan/seo-bundle

Annotating content with metadata for social sharing and seo purposes cannot be overlooked nowadays. The KunstmaanSeoBundle contains default editing functionality for OpenGraph data, meta descriptions, keywords and titles and Metriweb tags. Because the metatagging and tracking options are always changing, a free field to add custom header information is provided as well.

24132.1k2](/packages/kunstmaan-seo-bundle)[pedroborges/meta-tags

HTML meta tags generator for PHP.

4628.9k1](/packages/pedroborges-meta-tags)

PHPackages © 2026

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