SEO - v1.1.1
Schema.org / JSON-LD
Structured data helps search engines understand your content and can enable rich search results. This guide covers implementing Schema.org markup using JSON-LD format.
Overview
The package provides 14 built-in schema types with customizable JSON-LD generation. Schema markup is stored with your SEO metadata and rendered automatically.
Setting Schema Type
Basic Usage
$post->updateSeoMeta([
'schema_type' => 'Article',
]);
With Custom Data
$post->updateSeoMeta([
'schema_type' => 'Article',
'schema_data' => [
'author' => [
'@type' => 'Person',
'name' => 'John Doe',
'url' => 'https://example.com/authors/john',
],
'publisher' => [
'@type' => 'Organization',
'name' => 'My Site',
'logo' => [
'@type' => 'ImageObject',
'url' => 'https://example.com/logo.png',
],
],
'datePublished' => $post->created_at->toIso8601String(),
'dateModified' => $post->updated_at->toIso8601String(),
],
]);
Available Schema Types
Article
For blog posts and news articles:
$post->updateSeoMeta([
'schema_type' => 'Article',
'schema_data' => [
'headline' => 'Article Headline',
'author' => ['@type' => 'Person', 'name' => 'Author Name'],
'datePublished' => '2024-01-15T10:00:00Z',
'dateModified' => '2024-01-16T14:30:00Z',
'image' => 'https://example.com/article-image.jpg',
'articleSection' => 'Technology',
'wordCount' => 1500,
],
]);
BlogPosting
Specifically for blog posts:
$post->updateSeoMeta([
'schema_type' => 'BlogPosting',
'schema_data' => [
'headline' => 'My Blog Post Title',
'author' => ['@type' => 'Person', 'name' => 'Blogger Name'],
'datePublished' => '2024-01-15',
'mainEntityOfPage' => $post->url,
],
]);
Product
For e-commerce products:
$product->updateSeoMeta([
'schema_type' => 'Product',
'schema_data' => [
'name' => 'Amazing Product',
'description' => 'Product description here.',
'image' => 'https://example.com/product.jpg',
'brand' => ['@type' => 'Brand', 'name' => 'Brand Name'],
'sku' => 'SKU123',
'offers' => [
'@type' => 'Offer',
'price' => '99.99',
'priceCurrency' => 'USD',
'availability' => 'https://schema.org/InStock',
'url' => $product->url,
],
'aggregateRating' => [
'@type' => 'AggregateRating',
'ratingValue' => '4.5',
'reviewCount' => '89',
],
],
]);
Event
For events and happenings:
$event->updateSeoMeta([
'schema_type' => 'Event',
'schema_data' => [
'name' => 'Tech Conference 2024',
'startDate' => '2024-06-15T09:00:00-05:00',
'endDate' => '2024-06-17T18:00:00-05:00',
'location' => [
'@type' => 'Place',
'name' => 'Convention Center',
'address' => [
'@type' => 'PostalAddress',
'streetAddress' => '123 Main St',
'addressLocality' => 'Chicago',
'addressRegion' => 'IL',
'postalCode' => '60601',
'addressCountry' => 'US',
],
],
'offers' => [
'@type' => 'Offer',
'price' => '299',
'priceCurrency' => 'USD',
'availability' => 'https://schema.org/InStock',
'validFrom' => '2024-01-01',
],
'performer' => [
'@type' => 'Person',
'name' => 'Keynote Speaker',
],
],
]);
Organization
For company/organization pages:
$page->updateSeoMeta([
'schema_type' => 'Organization',
'schema_data' => [
'name' => 'My Company',
'url' => 'https://example.com',
'logo' => 'https://example.com/logo.png',
'contactPoint' => [
'@type' => 'ContactPoint',
'telephone' => '+1-800-555-1234',
'contactType' => 'customer service',
],
'sameAs' => [
'https://facebook.com/mycompany',
'https://twitter.com/mycompany',
'https://linkedin.com/company/mycompany',
],
],
]);
LocalBusiness
For local businesses:
$business->updateSeoMeta([
'schema_type' => 'LocalBusiness',
'schema_data' => [
'name' => 'My Local Shop',
'image' => 'https://example.com/shop.jpg',
'telephone' => '+1-555-123-4567',
'address' => [
'@type' => 'PostalAddress',
'streetAddress' => '456 Oak Street',
'addressLocality' => 'Springfield',
'addressRegion' => 'IL',
'postalCode' => '62701',
'addressCountry' => 'US',
],
'geo' => [
'@type' => 'GeoCoordinates',
'latitude' => '39.7817',
'longitude' => '-89.6501',
],
'openingHoursSpecification' => [
[
'@type' => 'OpeningHoursSpecification',
'dayOfWeek' => ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
'opens' => '09:00',
'closes' => '17:00',
],
],
'priceRange' => '$$',
],
]);
WebSite
For the main website (usually homepage):
$homepage->updateSeoMeta([
'schema_type' => 'WebSite',
'schema_data' => [
'name' => 'My Website',
'url' => 'https://example.com',
'potentialAction' => [
'@type' => 'SearchAction',
'target' => 'https://example.com/search?q={search_term_string}',
'query-input' => 'required name=search_term_string',
],
],
]);
WebPage
For general web pages:
$page->updateSeoMeta([
'schema_type' => 'WebPage',
'schema_data' => [
'name' => 'About Us',
'description' => 'Learn about our company.',
'isPartOf' => ['@type' => 'WebSite', 'name' => 'My Website'],
],
]);
Service
For service offerings:
$service->updateSeoMeta([
'schema_type' => 'Service',
'schema_data' => [
'name' => 'Web Development',
'description' => 'Professional web development services.',
'provider' => [
'@type' => 'Organization',
'name' => 'My Agency',
],
'serviceType' => 'Web Development',
'areaServed' => 'United States',
],
]);
FAQPage
For FAQ sections:
$faqPage->updateSeoMeta([
'schema_type' => 'FAQPage',
'schema_data' => [
'mainEntity' => [
[
'@type' => 'Question',
'name' => 'What is your return policy?',
'acceptedAnswer' => [
'@type' => 'Answer',
'text' => 'We offer 30-day returns on all items.',
],
],
[
'@type' => 'Question',
'name' => 'Do you ship internationally?',
'acceptedAnswer' => [
'@type' => 'Answer',
'text' => 'Yes, we ship to over 50 countries.',
],
],
],
],
]);
BreadcrumbList
For breadcrumb navigation:
$page->updateSeoMeta([
'schema_type' => 'BreadcrumbList',
'schema_data' => [
'itemListElement' => [
['@type' => 'ListItem', 'position' => 1, 'name' => 'Home', 'item' => 'https://example.com'],
['@type' => 'ListItem', 'position' => 2, 'name' => 'Products', 'item' => 'https://example.com/products'],
['@type' => 'ListItem', 'position' => 3, 'name' => 'Widget', 'item' => 'https://example.com/products/widget'],
],
],
]);
Review
For review content:
$review->updateSeoMeta([
'schema_type' => 'Review',
'schema_data' => [
'itemReviewed' => ['@type' => 'Product', 'name' => 'Product Name'],
'reviewRating' => ['@type' => 'Rating', 'ratingValue' => '4', 'bestRating' => '5'],
'author' => ['@type' => 'Person', 'name' => 'Reviewer Name'],
'reviewBody' => 'Great product, highly recommended!',
],
]);
AggregateRating
For aggregate ratings:
$product->updateSeoMeta([
'schema_type' => 'AggregateRating',
'schema_data' => [
'itemReviewed' => ['@type' => 'Product', 'name' => 'Product Name'],
'ratingValue' => '4.5',
'bestRating' => '5',
'ratingCount' => '127',
],
]);
Schema Type Definitions API
Added in v1.1.0
The package provides a Schema Type Definitions API that returns rich metadata for each schema type, including human-readable descriptions and field definitions. This is designed for building dynamic schema editing forms in React or Vue frontends.
API Endpoint
GET /api/seo/schema/types
Response Format
{
"data": [
{
"name": "Article",
"label": "Article",
"description": "Represents a news or scholarly article.",
"fields": [
{
"name": "headline",
"type": "text",
"label": "Headline",
"required": true,
"description": "The headline of the article."
},
{
"name": "datePublished",
"type": "date",
"label": "Date Published",
"required": true,
"description": "The date the article was published."
}
]
}
]
}
Using the SchemaFactory Directly
use ArtisanPackUI\SEO\Schema\SchemaFactory;
$factory = app(SchemaFactory::class);
// Get all type definitions with descriptions and fields
$definitions = $factory->getTypeDefinitions();
// Each definition includes: name, label, description, fields[]
foreach ($definitions as $definition) {
echo $definition['name']; // e.g., "Article"
echo $definition['description']; // e.g., "Represents a news or scholarly article."
foreach ($definition['fields'] as $field) {
echo $field['name']; // e.g., "headline"
echo $field['type']; // e.g., "text", "date", "url", "select", "textarea"
echo $field['label']; // e.g., "Headline"
echo $field['required']; // true or false
echo $field['description'];
}
}
Custom Schema Types with Field Definitions
When creating custom schema types, implement getDescription() and getFieldDefinitions() to have them appear in the API:
use ArtisanPackUI\SEO\Schema\Builders\AbstractSchema;
use Illuminate\Database\Eloquent\Model;
class RecipeSchema extends AbstractSchema
{
public function getType(): string
{
return 'Recipe';
}
public function getDescription(): string
{
return 'A recipe for preparing a food dish.';
}
public function getFieldDefinitions(): array
{
return [
[
'name' => 'recipeName',
'type' => 'text',
'label' => 'Recipe Name',
'required' => true,
'description' => 'The name of the recipe.',
],
[
'name' => 'cookTime',
'type' => 'text',
'label' => 'Cook Time',
'required' => false,
'description' => 'The time it takes to cook the dish (ISO 8601 duration).',
],
];
}
public function generate(?Model $model = null): array
{
return $this->filterEmpty(array_merge($this->getBaseSchema(), [
'name' => $this->get('recipeName'),
'cookTime' => $this->get('cookTime'),
]));
}
}
Register your custom type:
$factory = app(\ArtisanPackUI\SEO\Schema\SchemaFactory::class);
$factory->register('Recipe', RecipeSchema::class);
Rendering Schema
Using Blade Component
<x-seo-schema :model="$post" />
Generated Output
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "My Article Title",
"author": {
"@type": "Person",
"name": "John Doe"
},
"datePublished": "2024-01-15T10:00:00Z",
"image": "https://example.com/article.jpg"
}
</script>
Using the Schema Service
For programmatic schema generation:
use ArtisanPackUI\Seo\Services\SchemaService;
$schemaService = app(SchemaService::class);
// Generate schema for a model
$jsonLd = $schemaService->generate($post);
// Generate specific schema type
$articleSchema = $schemaService->buildArticle($post, [
'author' => ['@type' => 'Person', 'name' => 'Author'],
]);
Testing Structured Data
Validate your schema markup using:
Best Practices
- Choose the most specific type - Use
BlogPostinginstead ofArticlefor blogs - Include required properties - Check Google's documentation for each type
- Use absolute URLs - Always use full URLs for images and links
- Keep data accurate - Schema should match visible page content
- Test regularly - Validate after any changes
Next Steps
- Meta Tags - Basic meta tag management
- Social Media - Open Graph and Twitter Cards
- Hreflang - Multi-language support
- Configuration - Schema settings