Weave Code
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

Schema Org Laravel Package

spatie/schema-org

Fluent PHP builder for Schema.org: generate any type and property from the full core vocabulary and output valid JSON-LD (ld+json) script tags. Generated from the official Schema.org JSON-LD, with documented classes and methods.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/schema-org
    

    No additional configuration is required—just autoload the package.

  2. First Use Case: Generate a basic Person type with minimal properties:

    use Spatie\SchemaOrg\Schema;
    
    $person = Schema::person()
        ->name('John Doe')
        ->jobTitle('Developer')
        ->sameAs('https://example.com/john-doe');
    echo $person->toHtml();
    

    Outputs:

    <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "Person",
      "name": "John Doe",
      "jobTitle": "Developer",
      "sameAs": "https://example.com/john-doe"
    }
    </script>
    
  3. Where to Look First:

    • Type Registry: Browse vendor/spatie/schema-org/src/Types/ for all available Schema.org types (e.g., Article, Product, LocalBusiness).
    • Documentation: The README includes a quick-start guide and examples.
    • Generated Code: The package auto-generates fluent builders from Schema.org’s JSON-LD schema, so the API mirrors the official types.

Implementation Patterns

Core Workflows

  1. Fluent Chaining for Types: Build complex nested structures (e.g., BreadcrumbList with ListItem):

    $breadcrumbs = Schema::breadcrumbList()
        ->addItem(
            Schema::listItem()
                ->position(1)
                ->name('Home')
                ->item(Schema::thing()->name('Homepage'))
        )
        ->addItem(
            Schema::listItem()
                ->position(2)
                ->name('Products')
                ->item(Schema::thing()->name('Products Page'))
        );
    
  2. Dynamic Property Assignment: Use addProperty() for unsupported properties or future-proofing:

    $product = Schema::product()
        ->name('Laptop')
        ->addProperty('mpn', '123456789'); // Manufacturer Part Number (custom)
    
  3. Reusable Components: Extract common schemas into helper methods or services:

    function generateOrganizationSchema(string $name, string $url): Schema\Organization
    {
        return Schema::organization()
            ->name($name)
            ->url($url)
            ->logo('https://example.com/logo.png');
    }
    
  4. SEO Optimization: Combine multiple schemas in a single page (e.g., WebPage + BreadcrumbList):

    $pageSchema = Schema::webPage()
        ->name('Blog Post')
        ->addProperty('@type', ['BlogPost', 'WebPage'])
        ->addProperty('mainEntityOfPage', Schema::webPage()->url('/blog/post'))
        ->addProperty('breadcrumb', $breadcrumbs->toArray());
    
  5. API Integration: Serve schemas via API responses:

    return response()->json([
        'data' => $product->toArray(),
        'schema' => $product->toJson(),
    ]);
    

Integration Tips

  • Blade Directives: Create a Blade directive for easy schema injection:

    Blade::directive('schema', function ($type) {
        return "<?php echo \\Spatie\\SchemaOrg\\Schema::$type()->toHtml(); ?>";
    });
    

    Usage:

    @schema('webPage')
    
  • Caching: Cache generated schemas if they’re static (e.g., business hours):

    $cacheKey = 'business_hours_schema';
    $hours = Cache::remember($cacheKey, now()->addHours(1), function () {
        return Schema::openingHoursSpecification()
            ->opens('09:00')
            ->closes('17:00');
    });
    
  • Validation: Validate properties against Schema.org constraints (e.g., URL format):

    use Spatie\SchemaOrg\Exceptions\InvalidPropertyValue;
    
    try {
        $schema = Schema::product()->addProperty('url', 'invalid-url');
    } catch (InvalidPropertyValue $e) {
        // Handle invalid URL
    }
    

Gotchas and Tips

Pitfalls

  1. Property Overrides:

    • Fluent methods override existing properties. Use addProperty() to append without replacing:
      // Wrong: Overrides 'name' entirely
      Schema::person()->name('John')->name('Jane'); // 'name' = 'Jane'
      
      // Correct: Appends to existing properties
      Schema::person()->name('John')->addProperty('name', 'Jane'); // 'name' = ['John', 'Jane']
      
  2. Nested Schema Limitations:

    • Nested schemas (e.g., Offer inside Product) must be fully built before assignment:
      // Wrong: Incomplete nested schema
      $product = Schema::product()->offers(Schema::offer()->price('100'));
      
      // Correct: Fully built nested schema
      $offer = Schema::offer()->price('100')->url('/offer');
      $product = Schema::product()->offers($offer);
      
  3. Context Management:

    • The @context is hardcoded to https://schema.org. For custom contexts, use addProperty('@context', 'custom-context'), but validate compatibility with Schema.org validators.
  4. Type Conflicts:

    • Avoid mixing incompatible types (e.g., Person and Organization as author of an Article). Schema.org validators may flag this as invalid.
  5. Dynamic Property Validation:

    • Custom properties (via addProperty()) bypass built-in validation. Use Schema::validate() to enforce rules:
      Schema::validate($schema, [
          'url' => 'required|url',
          'price' => 'numeric',
      ]);
      

Debugging

  1. Schema Validation: Use Google’s Rich Results Test or Schema Markup Validator to debug issues. The package includes a toJson() method for easy testing:

    echo $schema->toJson(JSON_PRETTY_PRINT);
    
  2. Type Autocompletion: IDEs (PHPStorm, VSCode) may not autocomplete dynamically added properties. Cast to array first:

    $schema->addProperty('customField', 'value');
    $array = $schema->toArray(); // IDE now sees all properties
    
  3. Deprecation Warnings: Monitor Schema.org’s changelog for deprecated properties/types. The package updates annually but may lag behind minor Schema.org changes.

Extension Points

  1. Custom Types: Extend the package by creating a custom type class:

    namespace App\SchemaOrg;
    
    use Spatie\SchemaOrg\Contracts\Schema;
    use Spatie\SchemaOrg\SchemaOrg;
    
    class CustomType extends SchemaOrg
    {
        protected $type = 'CustomType';
    
        public function customMethod(string $value): self
        {
            $this->properties['customProperty'] = $value;
            return $this;
        }
    }
    

    Register it in Schema::macro():

    Schema::macro('customType', function () {
        return new CustomType();
    });
    
  2. Property Macros: Add reusable property chains:

    Schema::macro('addAuthor', function (string $name, string $url) {
        return $this->addProperty('author', Schema::person()
            ->name($name)
            ->url($url)
            ->toArray());
    });
    
  3. Event Listeners: Hook into schema generation (e.g., log all schemas):

    Schema::macro('toJson', function () {
        $json = parent::toJson();
        Log::info('Generated schema:', ['schema' => $json]);
        return $json;
    });
    
  4. Testing: Use Schema::fake() to mock schemas in tests:

    Schema::fake([
        'person' => fn() => Schema::person()->name('Test User'),
    ]);
    
    $schema = Schema::person(); // Returns mocked schema
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder
psr/simple-cache-implementation