Honeystone SEO for Laravel

repository·master·Indexed 43 days ago

https://github.com/honeystone/laravel-seo

A Laravel package for simplifying the configuration and management of SEO metadata. It provides built-in generators for general metadata, X (Twitter) Cards, Open Graph, and JSON-LD Schema, with support for exporting data as arrays for Inertia.js and React integration.

Tokens
6K
Snippets
19
Records
19
Agent score
56%

What's inside Honeystone SEO

  1. Use JSON-LD Expectations and Check-ins

    master

    To ensure complex JSON-LD graphs are built correctly across different parts of your application (middleware, controllers, components), you can use an expectation system.

    1. Set an expectation: Use jsonLdExpect(string ...$keys) to declare which parts of the graph must be present.
    2. Check in: Use jsonLdCheckIn(string $key) when a component or service provides its part of the data.

    If an expected key is not checked in, or if an unexpected key is checked in, an exception is thrown.

    // In a controller: declare what is needed
    seo()
        ->title('Something awesome')
        ->jsonLdExpect('featured-tags', 'gallery', 'contact');
    
    // In a view component: fulfill the requirement
    seo()
        ->jsonLdCheckIn('gallery')
        ->jsonLdGraph()
            ->imageGallery()
                ->image([...]);
  2. Integrate SEO with Eloquent Models

    master

    A recommended pattern for integrating SEO with your models is to add a method to your model that returns a MetadataDirector instance, mapping model attributes to SEO methods. This allows you to centralize SEO logic within the model.

    Then, in your controller, you can call this method and chain additional context-specific metadata.

    // In your Model
    class Page extends Model
    {
        public function seo(): MetadataDirector
        {
            return seo()
                ->title($this->meta_title)
                ->description($this->meta_description)
                ->jsonLdExpect('featured-items');
        }
    }
    
    // In your Controller
    public function __invoke(Page $page): View
    {
        $page->seo()
            ->jsonLdCheckIn('featured-items')
            ->jsonLdGraph()
                ->itemList()
                    ->name('Featured items');
    
        return view('...', ['page' => $page]);
    }
  3. Setup Inertia React SEO Head

    master

    To render SEO tags in an Inertia React application, follow these steps:

    1. Register the \Honeystone\Seo\Http\Middleware\GenerateInertiaMetadataReact::class middleware in your HandleInertiaRequests.php file to ensure $page.props.seoPayload is shared.
    2. Import and render the SeoHead component in your main React layout.

    Note: When using this method, you must remove the @metadata Blade directive from your layouts as Inertia handles the tag replacement.

    // app/Http/Middleware/HandleInertiaRequests.php
    protected $middleware = [
        // ...
        \Honeystone\Seo\Http\Middleware\GenerateInertiaMetadataReact::class,
    ];
    // resources/js/Layouts/AppLayout.tsx
    import SeoHead from '@/inertia/react/SeoHead';
    
    export default function AppLayout({ children }) {
        return (
            <>
                <SeoHead defaultTitleSuffix="My App" />
                {children}
            </>
        );
    }
  4. Exporting metadata as arrays for Inertia.js

    master

    Every generator implements the Honeystone\Seo\Contracts\ExportsArrayMetadata contract. This allows you to export structured SEO data as an array, which is ideal for passing to Inertia.js or other frontend frameworks.

    • Use seo()->toArray() to get all generators.
    • Use seo()->toArray('generator_name') to limit the payload to a specific generator (e.g., 'meta').

    If you use the bundled GenerateInertiaMetadata middleware, the payload is automatically available in $page.props.seoPayload.

    // Export all
    $seo = seo()->toArray();            // ['meta' => [...], 'twitter' => [...], ...]
    
    // Export specific generator
    $metaOnly = seo()->toArray('meta');
    
    // Sharing with Inertia
    return Inertia::render('Pages/Show', [
        'page' => $page,
        'seo' => seo()->toArray(),
    ]);
  5. Basic Usage of Honeystone SEO

    master

    You can manage SEO metadata using the seo() helper function or by typehinting Honeystone\Seo\MetadataDirector for dependency injection. Metadata is set by chaining methods like title(), description(), and images().

    To render the metadata in your Blade templates, use either seo()->generate() or the @metadata Blade directive.

    seo()
        ->title('A fantastic blog post', 'My Awesome Website!')
        ->description('Theres really a lot of great stuff in here...')
        ->images(
            'https://mywebsite.com/images/blog-1/cover-image.webp',
            'https://mywebsite.com/images/blog-1/another-image.webp',
        );
    
    // To render:
    {{ seo()->generate() }}
    
    // Or using the directive:
    @metadata
  6. Configure Default SEO Methods

    master

    The seo() helper provides several default methods that propagate values to all configured generators. These include:

    • locale(string): Sets the locale (e.g., 'en_GB').
    • title(string, array $options): Sets the title. Use template: false to disable title templates (useful for homepages).
    • description(string): Sets the site description.
    • keywords(string ...$keywords): Sets meta keywords.
    • url(string): Sets the canonical URL (defaults to current URL).
    • canonical(string): Sets the canonical URL.
    • canonicalEnabled(bool): Enables/disables canonical tags.
    • images(string ...$urls): Sets images for OG and Twitter.
    • robots(string ...$values): Sets robots meta tags.
    seo()
        ->locale('en_GB')
        ->title('A fantastic blog post', template: '🔥🔥 {title} 🔥🔥')
        ->description('Theres really a lot of great stuff in here...')
        ->keywords('foo', 'bar', 'baz')
        ->url('https://mywebsite.com/blog/a-fantastic-blog-post')
        ->canonical('https://mywebsite.com/blog/a-fantastic-blog-post')
        ->canonicalEnabled(true)
        ->images(
            'https://mywebsite.com/images/blog-1/cover-image.webp',
            'https://mywebsite.com/images/blog-1/another-image.webp',
        )
        ->robots('🤖', '🤖', '🤖');
  7. Configure JSON-LD Metadata

    master

    The JsonLdGenerator creates structured data. It supports integration with the spatie/schema-org package via jsonLdImport(), jsonLdGraph(), or jsonLdMulti().

    Key methods:

    • jsonLdEnabled(bool)
    • jsonLdType(string): Defaults to WebPage.
    • jsonLdName(string): Defaults to title().
    • jsonLdDescription(string): Defaults to description().
    • jsonLdImage(string) or jsonLdImages(array)
    • jsonLdUrl(string): Defaults to url().
    • jsonLdNonce(string): Sets a nonce for Content Security Policy.
    • jsonLdProperty(string, mixed): Adds custom properties.
    seo()
        ->jsonLdEnabled(true)
        ->jsonLdType('WebPage')
        ->jsonLdName('A fantastic blog post')
        ->jsonLdDescription('Theres really a lot of great stuff in here...')
        ->jsonLdImage('https://mywebsite.com/images/blog-1/cover-image.webp')
        ->jsonLdUrl('https://mywebsite.com/blog/a-fantastic-blog-post')
        ->jsonLdNonce('some-value')
        ->jsonLdProperty('alternateName', 'Foo');
  8. Configure Open Graph Metadata

    master

    The OpenGraphGenerator handles Open Graph (OG) tags. It supports standard properties and complex types like ArticleProperties, BookProperties, and ProfileProperties.

    Key methods:

    • openGraphEnabled(bool)
    • openGraphSite(string)
    • openGraphType(mixed): Can be a string or a property class (e.g., ArticleProperties).
    • openGraphTitle(string): Defaults to title().
    • openGraphDescription(string): Defaults to description().
    • openGraphImage(string) or openGraphImages(array)
    • openGraphUrl(string): Defaults to url().
    • openGraphLocale(string): Defaults to locale().
    • openGraphProperty(string, string): For custom properties.

    To set the prefix in Blade, use @openGraphPrefix or seo()->openGraphPrefix().

    // Using ArticleProperties
    use Honeystone\Seo\OpenGraph\ArticleProperties;
    use Honeystone\Seo\OpenGraph\ProfileProperties;
    
    seo()->openGraphType(new ArticleProperties(
        publishedTime: new DateTime('now'),
        modifiedTime: new DateTime('now'),
        author: new ProfileProperties(username: 'PiranhaGeorge'),
        section: 'Foo',
        tag: 'Bar',
    ));
    <head prefix="@openGraphPrefix">
        ...
    </head>
  9. Configure Twitter Metadata

    master

    The TwitterGenerator handles Twitter Card metadata. Methods include:

    • twitterEnabled(bool): Enables/disables Twitter tags.
    • twitterSite(string): The @twitterUsername for the site.
    • twitterCreator(string): The @twitterUsername for the creator.
    • twitterTitle(string): Defaults to title().
    • twitterDescription(string): Defaults to description().
    • twitterImage(string): Defaults to the first image in images().
    seo()
        ->twitterEnabled(true)
        ->twitterSite('@MyWebsite')
        ->twitterCreator('@MyTwitter')
        ->twitterTitle('A fantastic blog post')
        ->twitterDescription('Theres really a lot of great stuff in here...')
        ->twitterImage('https://mywebsite.com/images/blog-1/cover-image.webp');
  10. Reference: SEO Configuration Keys

    master

    The package is configured via a configuration file. Below are the available keys for each generator:

    MetaGenerator

    • title: Default title.
    • titleTemplate: Template for the title (e.g., {title} - {app_name}).
    • description: Default description.
    • keywords: Array of keywords.
    • canonicalEnabled: Boolean.
    • canonical: URL or null.
    • robots: Array of robots settings.
    • custom: Key-value pairs for custom meta tags.

    TwitterGenerator

    • enabled: Boolean.
    • site: @twitterUsername.
    • creator: @twitterUsername.
    • title, description, image: Default values.

    OpenGraphGenerator

    • enabled: Boolean.
    • site: Site name.
    • type: OG type (e.g., website).
    • title, description, images, audio, videos, url, locale: Default values.
    • determiner: OG determiner.
    • alternateLocales: Array of locales.
    • custom: Key-value pairs.

    JsonLdGenerator

    • enabled: Boolean.
    • pretty: Boolean (uses APP_DEBUG).
    • type: Schema type (e.g., WebPage).
    • name, description, images, url, custom: Default values.
    • place-on-graph: Boolean (determines if it's automatically added to the graph).
    return [
        'generators' => [
            Generators\MetaGenerator::class => [
                'title' => env('APP_NAME'),
                'titleTemplate' => '{title} - '.env('APP_NAME'),
                'description' => '',
                'keywords' => [],
                'canonicalEnabled' => true,
                'canonical' => null,
                'robots' => [],
                'custom' => [],
            ],
            Generators\TwitterGenerator::class => [
                'enabled' => true,
                'site' => '',
                'creator' => '',
                'title' => '',
                'description' => '',
                'image' => '',
            ],
            Generators\OpenGraphGenerator::class => [
                'enabled' => true,
                'site' => env('APP_NAME'),
                'type' => 'website',
                'title' => '',
                'description' => '',
                'images' => [],
                'audio' => [],
                'videos' => [],
                'determiner' => '',
                'url' => null,
                'locale' => '',
                'alternateLocales' => [],
                'custom' => [],
            ],
            Generators\JsonLdGenerator::class => [
                'enabled' => true,
                'pretty' => env('APP_DEBUG'),
                'type' => 'WebPage',
                'name' => '',
                'description' => '',
                'images' => [],
                'url' => null,
                'custom' => [],
                'place-on-graph' => true,
            ],
        ],
        'sync' => [
            'url-canonical' => true,
            'keywords-tags' => false,
        ],
    ];