Skip to content

Structured Data

Rumen Damyanov edited this page Sep 22, 2025 · 1 revision

Structured Data

Learn how to implement Schema.org structured data with the PHP-SEO package to enhance your search engine visibility and enable rich snippets.

Overview

Structured data helps search engines understand your content better and can result in rich snippets, knowledge panels, and enhanced search results. The PHP-SEO package automatically generates JSON-LD structured data based on your content and configuration.

What is Structured Data?

Structured data is a standardized format for providing information about a page and classifying the page content. It uses Schema.org vocabulary to define entities and their relationships.

Benefits

  • Rich Snippets: Enhanced search results with additional information
  • Better Understanding: Search engines understand content context
  • Voice Search: Improved compatibility with voice assistants
  • Knowledge Graph: Potential inclusion in Google's Knowledge Graph
  • CTR Improvement: Rich snippets often increase click-through rates

Supported Schema Types

The PHP-SEO package supports multiple Schema.org types:

Article Schema

For blog posts, news articles, and editorial content:

use Rumenx\PhpSeo\SeoManager;

$seo = new SeoManager();
$content = '<article><h1>My Article</h1><p>Content...</p></article>';

$structuredData = $seo->analyze($content, [
    'type' => 'article',
    'title' => 'My Article Title',
    'author' => 'John Doe',
    'published_at' => '2024-01-01T10:00:00Z',
    'modified_at' => '2024-01-02T10:00:00Z',
    'image' => 'https://example.com/article-image.jpg'
])->generateStructuredData();

Generated JSON-LD:

{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "My Article Title",
  "author": {
    "@type": "Person",
    "name": "John Doe"
  },
  "datePublished": "2024-01-01T10:00:00Z",
  "dateModified": "2024-01-02T10:00:00Z",
  "image": {
    "@type": "ImageObject",
    "url": "https://example.com/article-image.jpg"
  },
  "publisher": {
    "@type": "Organization",
    "name": "My Website"
  }
}

WebPage Schema

For general web pages:

$structuredData = $seo->analyze($content, [
    'type' => 'webpage',
    'title' => 'Page Title',
    'description' => 'Page description',
    'url' => 'https://example.com/page'
])->generateStructuredData();

Organization Schema

For company and organization pages:

$structuredData = $seo->analyze($content, [
    'type' => 'organization',
    'name' => 'Company Name',
    'url' => 'https://example.com',
    'logo' => 'https://example.com/logo.jpg',
    'contact_point' => [
        'telephone' => '+1-800-555-0199',
        'contact_type' => 'customer service'
    ],
    'address' => [
        'street' => '123 Main St',
        'city' => 'New York',
        'region' => 'NY',
        'postal_code' => '10001',
        'country' => 'US'
    ]
])->generateStructuredData();

Product Schema

For e-commerce product pages:

$structuredData = $seo->analyze($content, [
    'type' => 'product',
    'name' => 'Product Name',
    'description' => 'Product description',
    'image' => 'https://example.com/product.jpg',
    'brand' => 'Brand Name',
    'sku' => 'PRODUCT-123',
    'offers' => [
        'price' => 29.99,
        'currency' => 'USD',
        'availability' => 'in_stock',
        'seller' => 'Company Name'
    ]
])->generateStructuredData();

BreadcrumbList Schema

For navigation breadcrumbs:

$structuredData = $seo->generateBreadcrumbSchema([
    ['name' => 'Home', 'url' => 'https://example.com'],
    ['name' => 'Category', 'url' => 'https://example.com/category'],
    ['name' => 'Current Page', 'url' => 'https://example.com/category/page']
]);

Configuration

Global Structured Data Settings

use Rumenx\PhpSeo\Config\SeoConfig;

$config = new SeoConfig([
    'structured_data' => [
        'enabled' => true,
        'default_publisher' => [
            'name' => 'My Website',
            'logo' => 'https://example.com/logo.jpg',
            'url' => 'https://example.com'
        ],
        'default_author' => [
            'name' => 'Default Author',
            'url' => 'https://example.com/author'
        ],
        'organization' => [
            'name' => 'My Company',
            'url' => 'https://example.com',
            'logo' => 'https://example.com/logo.jpg',
            'social_profiles' => [
                'https://facebook.com/mycompany',
                'https://twitter.com/mycompany',
                'https://linkedin.com/company/mycompany'
            ]
        ]
    ]
]);

Content-Type Specific Configuration

$config = new SeoConfig([
    'structured_data' => [
        'article' => [
            'publisher_required' => true,
            'author_required' => true,
            'image_required' => true,
            'date_published_required' => true
        ],
        'product' => [
            'brand_required' => true,
            'offers_required' => true,
            'review_enabled' => true
        ]
    ]
]);

Advanced Schema Implementation

Custom Schema Types

use Rumenx\PhpSeo\StructuredData\SchemaBuilder;

$schema = new SchemaBuilder();
$customSchema = $schema
    ->setType('Recipe')
    ->setProperty('name', 'Chocolate Chip Cookies')
    ->setProperty('author', [
        '@type' => 'Person',
        'name' => 'Chef John'
    ])
    ->setProperty('cookTime', 'PT15M')
    ->setProperty('prepTime', 'PT10M')
    ->setProperty('recipeIngredient', [
        '2 cups flour',
        '1 cup sugar',
        '1/2 cup butter'
    ])
    ->setProperty('recipeInstructions', [
        [
            '@type' => 'HowToStep',
            'text' => 'Preheat oven to 350°F'
        ],
        [
            '@type' => 'HowToStep',
            'text' => 'Mix ingredients'
        ]
    ])
    ->build();

Nested Schema Objects

$articleWithAuthor = $schema
    ->setType('Article')
    ->setProperty('headline', 'Article Title')
    ->setProperty('author', [
        '@type' => 'Person',
        'name' => 'Author Name',
        'jobTitle' => 'Senior Writer',
        'worksFor' => [
            '@type' => 'Organization',
            'name' => 'Publisher Name'
        ]
    ])
    ->setProperty('publisher', [
        '@type' => 'Organization',
        'name' => 'Publisher Name',
        'logo' => [
            '@type' => 'ImageObject',
            'url' => 'https://example.com/logo.jpg'
        ]
    ])
    ->build();

Multiple Schema Objects

$multipleSchemas = [
    $schema->setType('Organization')->setProperty('name', 'Company')->build(),
    $schema->setType('WebSite')->setProperty('url', 'https://example.com')->build(),
    $schema->setType('Article')->setProperty('headline', 'Article')->build()
];

$jsonLd = $seo->renderStructuredData($multipleSchemas);

Laravel Integration

Automatic Schema Generation

// In your Laravel controller
public function show(Post $post, SeoManager $seo)
{
    $structuredData = $seo->analyze($post->content, [
        'type' => 'article',
        'title' => $post->title,
        'author' => $post->author->name,
        'published_at' => $post->published_at->toISOString(),
        'image' => $post->featured_image_url
    ])->generateStructuredData();
    
    return view('posts.show', [
        'post' => $post,
        'structured_data' => $structuredData
    ]);
}

Blade Template

@section('head')
    @if($structured_data)
        {!! $seo->renderStructuredData($structured_data) !!}
    @endif
@endsection

Blade Directive

@section('head')
    @seoStructuredData($post, 'article')
@endsection

Symfony Integration

Twig Extension

{% block head %}
    {{ seo_structured_data(article, 'article')|raw }}
{% endblock %}

Service Configuration

# config/services.yaml
services:
    App\Service\StructuredDataService:
        arguments:
            $seoManager: '@Rumenx\PhpSeo\SeoManager'
        tags: ['twig.extension']

Testing and Validation

Google Rich Results Test

Test your structured data with Google's tools:

// Test URL programmatically
$validator = new StructuredDataValidator();
$results = $validator->testUrl('https://example.com/page');

foreach ($results->getErrors() as $error) {
    echo "Error: {$error->getMessage()}\n";
}

Manual Validation

$schema = $seo->generateStructuredData();
$validator = new JsonLdValidator();

if ($validator->isValid($schema)) {
    echo "Schema is valid!";
} else {
    foreach ($validator->getErrors() as $error) {
        echo "Validation error: {$error}\n";
    }
}

Best Practices

General Guidelines

  1. Use Specific Types: Choose the most specific Schema.org type
  2. Required Properties: Always include required properties
  3. Consistent Data: Ensure data matches visible content
  4. Image Quality: Use high-quality, relevant images
  5. Date Formats: Use ISO 8601 format for dates

Common Patterns

Article Best Practices

$articleData = [
    'type' => 'article',
    'headline' => 'Specific, descriptive title (under 110 chars)',
    'author' => [
        'name' => 'Full author name',
        'url' => 'Author profile URL'
    ],
    'datePublished' => '2024-01-01T10:00:00Z',
    'dateModified' => '2024-01-02T15:30:00Z',
    'image' => [
        'url' => 'https://example.com/image.jpg',
        'width' => 1200,
        'height' => 630
    ],
    'publisher' => [
        'name' => 'Publisher Name',
        'logo' => 'Publisher logo URL'
    ]
];

Product Best Practices

$productData = [
    'type' => 'product',
    'name' => 'Product Name',
    'image' => 'Product image URL',
    'description' => 'Detailed product description',
    'brand' => 'Brand Name',
    'sku' => 'Unique SKU',
    'offers' => [
        'price' => 29.99,
        'priceCurrency' => 'USD',
        'availability' => 'https://schema.org/InStock',
        'seller' => 'Seller Name'
    ],
    'aggregateRating' => [
        'ratingValue' => 4.5,
        'reviewCount' => 127
    ]
];

Troubleshooting

Common Issues

  1. Missing Required Properties

    // Enable validation to catch missing properties
    $config = new SeoConfig([
        'structured_data' => [
            'validation' => true,
            'strict_mode' => true
        ]
    ]);
  2. Invalid Date Formats

    // Use proper ISO 8601 format
    $datePublished = $post->created_at->toISOString(); // ✓ Correct
    $datePublished = $post->created_at->format('Y-m-d'); // ✗ Incorrect
  3. Image URL Issues

    // Ensure absolute URLs
    $imageUrl = asset('images/product.jpg'); // Laravel
    $imageUrl = $request->getSchemeAndHttpHost() . '/images/product.jpg'; // Symfony

Debug Mode

$config = new SeoConfig([
    'debug' => true,
    'structured_data' => [
        'validate_output' => true,
        'log_errors' => true
    ]
]);

Performance Considerations

Caching

// Cache structured data for static content
$cacheKey = 'structured_data_' . md5($content);
$structuredData = cache()->remember($cacheKey, 3600, function() use ($seo, $content) {
    return $seo->generateStructuredData();
});

Lazy Loading

// Generate structured data only when needed
$seo->setLazyStructuredData(true);

Structured data is a powerful tool for improving your content's visibility and understanding by search engines. The PHP-SEO package makes it easy to implement and maintain structured data across your website.

Clone this wiki locally