-
-
Notifications
You must be signed in to change notification settings - Fork 1
Advanced Examples
Rumen Damyanov edited this page Sep 22, 2025
·
1 revision
Comprehensive examples demonstrating advanced usage patterns, real-world scenarios, and best practices with the PHP-SEO package.
<?php
use Rumenx\PhpSeo\SeoManager;
use Rumenx\PhpSeo\Config\SeoConfig;
class ProductSeoManager
{
private SeoManager $seoManager;
private array $defaultConfig;
public function __construct()
{
$this->defaultConfig = [
'default_title' => 'E-commerce Store',
'default_description' => 'Premium products at great prices',
'meta_tags' => [
'author' => 'E-commerce Store',
'robots' => 'index,follow',
'og:site_name' => 'E-commerce Store',
'twitter:site' => '@ecommercestore'
],
'structured_data' => [
'enabled' => true,
'default_publisher' => [
'name' => 'E-commerce Store',
'logo' => 'https://store.com/logo.jpg'
]
]
];
$config = new SeoConfig($this->defaultConfig);
$this->seoManager = new SeoManager($config);
}
public function generateProductSeo(array $product): array
{
$content = $this->buildProductHtml($product);
$options = [
'type' => 'product',
'title' => $product['name'] . ' - ' . $product['brand'],
'description' => $this->generateProductDescription($product),
'keywords' => $this->generateProductKeywords($product),
'url' => $product['url'],
'image' => $product['images'][0] ?? null,
'product_data' => [
'name' => $product['name'],
'brand' => $product['brand'],
'sku' => $product['sku'],
'price' => $product['price'],
'currency' => $product['currency'],
'availability' => $product['in_stock'] ? 'in_stock' : 'out_of_stock',
'condition' => $product['condition'] ?? 'new',
'images' => $product['images'],
'reviews' => $product['reviews'] ?? []
]
];
$analysis = $this->seoManager->analyze($content, $options);
return [
'meta_tags' => $analysis->getMetaTags(),
'structured_data' => $analysis->generateStructuredData(),
'recommendations' => $analysis->getRecommendations(),
'social_tags' => $this->generateSocialTags($product),
'breadcrumbs' => $this->generateBreadcrumbs($product)
];
}
private function buildProductHtml(array $product): string
{
return "
<div class='product' itemscope itemtype='http://schema.org/Product'>
<h1 itemprop='name'>{$product['name']}</h1>
<div class='brand' itemprop='brand'>{$product['brand']}</div>
<div class='description' itemprop='description'>
{$product['description']}
</div>
<div class='price' itemprop='offers' itemscope itemtype='http://schema.org/Offer'>
<span itemprop='price'>{$product['price']}</span>
<span itemprop='priceCurrency'>{$product['currency']}</span>
</div>
<div class='images'>
" . implode('', array_map(function($img) {
return "<img src='{$img['url']}' alt='{$img['alt']}' itemprop='image'>";
}, $product['images'])) . "
</div>
<div class='features'>
" . implode('', array_map(function($feature) {
return "<div class='feature'>{$feature}</div>";
}, $product['features'] ?? [])) . "
</div>
</div>
";
}
private function generateProductDescription(array $product): string
{
$description = $product['short_description'] ?? substr(strip_tags($product['description']), 0, 155);
return $description . ' | Free shipping available.';
}
private function generateProductKeywords(array $product): array
{
$keywords = [$product['name'], $product['brand']];
if (isset($product['category'])) {
$keywords[] = $product['category'];
}
if (isset($product['tags'])) {
$keywords = array_merge($keywords, $product['tags']);
}
return array_unique($keywords);
}
private function generateSocialTags(array $product): string
{
$tags = [
'<meta property="product:brand" content="' . htmlspecialchars($product['brand']) . '">',
'<meta property="product:availability" content="' . ($product['in_stock'] ? 'in stock' : 'out of stock') . '">',
'<meta property="product:condition" content="' . ($product['condition'] ?? 'new') . '">',
'<meta property="product:price:amount" content="' . $product['price'] . '">',
'<meta property="product:price:currency" content="' . $product['currency'] . '">'
];
return implode("\n", $tags);
}
private function generateBreadcrumbs(array $product): array
{
return [
['name' => 'Home', 'url' => '/'],
['name' => $product['category'] ?? 'Products', 'url' => '/category/' . ($product['category_slug'] ?? 'products')],
['name' => $product['name'], 'url' => $product['url']]
];
}
}class CategorySeoManager
{
private SeoManager $seoManager;
public function generateCategorySeo(array $category, array $products): array
{
$content = $this->buildCategoryHtml($category, $products);
$options = [
'type' => 'webpage',
'title' => $category['name'] . ' - Shop Online',
'description' => $this->generateCategoryDescription($category, count($products)),
'url' => $category['url'],
'image' => $category['image'] ?? null,
'keywords' => $this->generateCategoryKeywords($category, $products)
];
$analysis = $this->seoManager->analyze($content, $options);
return [
'meta_tags' => $analysis->getMetaTags(),
'structured_data' => $this->generateCategoryStructuredData($category, $products),
'recommendations' => $analysis->getRecommendations(),
'pagination_tags' => $this->generatePaginationTags($category)
];
}
private function generateCategoryStructuredData(array $category, array $products): string
{
$itemList = [
'@context' => 'https://schema.org',
'@type' => 'ItemList',
'name' => $category['name'],
'numberOfItems' => count($products),
'itemListElement' => []
];
foreach ($products as $index => $product) {
$itemList['itemListElement'][] = [
'@type' => 'ListItem',
'position' => $index + 1,
'item' => [
'@type' => 'Product',
'name' => $product['name'],
'url' => $product['url'],
'image' => $product['image'],
'offers' => [
'@type' => 'Offer',
'price' => $product['price'],
'priceCurrency' => $product['currency']
]
]
];
}
return json_encode($itemList, JSON_PRETTY_PRINT);
}
}class ArticleSeoManager
{
private SeoManager $seoManager;
public function generateArticleSeo(array $article): array
{
$content = $this->prepareArticleContent($article);
$options = [
'type' => 'article',
'title' => $article['title'],
'description' => $article['excerpt'] ?? $this->generateExcerpt($article['content']),
'url' => $article['url'],
'image' => $article['featured_image'],
'author' => $article['author']['name'],
'published_at' => $article['published_at'],
'modified_at' => $article['updated_at'] ?? $article['published_at'],
'keywords' => $this->extractKeywords($article),
'reading_time' => $this->calculateReadingTime($article['content'])
];
$analysis = $this->seoManager->analyze($content, $options);
return [
'meta_tags' => $analysis->getMetaTags(),
'structured_data' => $this->generateArticleStructuredData($article),
'social_tags' => $this->generateSocialMediaTags($article),
'recommendations' => $analysis->getRecommendations(),
'related_articles' => $this->findRelatedArticles($article)
];
}
private function generateArticleStructuredData(array $article): string
{
$schema = [
'@context' => 'https://schema.org',
'@type' => 'Article',
'headline' => $article['title'],
'description' => $article['excerpt'] ?? $this->generateExcerpt($article['content']),
'image' => $this->processImageForSchema($article['featured_image']),
'author' => [
'@type' => 'Person',
'name' => $article['author']['name'],
'url' => $article['author']['url'] ?? null,
'image' => $article['author']['avatar'] ?? null
],
'publisher' => [
'@type' => 'Organization',
'name' => 'Blog Name',
'logo' => [
'@type' => 'ImageObject',
'url' => 'https://blog.com/logo.jpg'
]
],
'datePublished' => $article['published_at'],
'dateModified' => $article['updated_at'] ?? $article['published_at'],
'mainEntityOfPage' => [
'@type' => 'WebPage',
'@id' => $article['url']
]
];
// Add article sections if available
if (!empty($article['sections'])) {
$schema['articleSection'] = $article['sections'];
}
// Add word count
$schema['wordCount'] = str_word_count(strip_tags($article['content']));
return json_encode($schema, JSON_PRETTY_PRINT);
}
private function calculateReadingTime(string $content): int
{
$wordCount = str_word_count(strip_tags($content));
return max(1, round($wordCount / 200)); // 200 words per minute
}
private function extractKeywords(array $article): array
{
$keywords = [];
// From tags
if (!empty($article['tags'])) {
$keywords = array_merge($keywords, $article['tags']);
}
// From categories
if (!empty($article['categories'])) {
$keywords = array_merge($keywords, $article['categories']);
}
// From content analysis
$contentKeywords = $this->analyzeContentKeywords($article['content']);
$keywords = array_merge($keywords, $contentKeywords);
return array_unique(array_slice($keywords, 0, 10));
}
private function analyzeContentKeywords(string $content): array
{
// Simple keyword extraction (in real implementation, use more sophisticated NLP)
$text = strtolower(strip_tags($content));
$words = preg_split('/\W+/', $text);
$words = array_filter($words, function($word) {
return strlen($word) > 3 && !in_array($word, $this->getStopWords());
});
$frequency = array_count_values($words);
arsort($frequency);
return array_slice(array_keys($frequency), 0, 5);
}
private function getStopWords(): array
{
return ['this', 'that', 'with', 'have', 'will', 'from', 'they', 'know', 'want', 'been', 'good', 'much', 'some', 'time', 'very', 'when', 'come', 'here', 'just', 'like', 'long', 'make', 'many', 'over', 'such', 'take', 'than', 'them', 'well', 'were'];
}
}class InternationalSeoManager
{
private SeoManager $seoManager;
private array $languages;
private string $defaultLanguage;
public function __construct(array $languages = ['en', 'es', 'fr', 'de'], string $defaultLanguage = 'en')
{
$this->languages = $languages;
$this->defaultLanguage = $defaultLanguage;
$this->seoManager = new SeoManager();
}
public function generateMultiLanguageSeo(array $page, string $currentLanguage): array
{
$content = $page['content'][$currentLanguage] ?? $page['content'][$this->defaultLanguage];
$options = [
'title' => $page['title'][$currentLanguage] ?? $page['title'][$this->defaultLanguage],
'description' => $page['description'][$currentLanguage] ?? $page['description'][$this->defaultLanguage],
'url' => $page['urls'][$currentLanguage],
'language' => $currentLanguage,
'keywords' => $page['keywords'][$currentLanguage] ?? []
];
$analysis = $this->seoManager->analyze($content, $options);
return [
'meta_tags' => $analysis->getMetaTags(),
'hreflang_tags' => $this->generateHreflangTags($page['urls']),
'structured_data' => $this->generateMultiLanguageStructuredData($page, $currentLanguage),
'language_selector' => $this->generateLanguageSelector($page['urls'], $currentLanguage)
];
}
private function generateHreflangTags(array $urls): string
{
$tags = [];
foreach ($urls as $language => $url) {
$tags[] = '<link rel="alternate" hreflang="' . $language . '" href="' . $url . '">';
}
// Add x-default for default language
if (isset($urls[$this->defaultLanguage])) {
$tags[] = '<link rel="alternate" hreflang="x-default" href="' . $urls[$this->defaultLanguage] . '">';
}
return implode("\n", $tags);
}
private function generateMultiLanguageStructuredData(array $page, string $currentLanguage): string
{
$schema = [
'@context' => 'https://schema.org',
'@type' => 'WebPage',
'name' => $page['title'][$currentLanguage],
'description' => $page['description'][$currentLanguage],
'url' => $page['urls'][$currentLanguage],
'inLanguage' => $currentLanguage
];
// Add translations
if (count($page['urls']) > 1) {
$schema['translationOfWork'] = [];
foreach ($page['urls'] as $lang => $url) {
if ($lang !== $currentLanguage) {
$schema['translationOfWork'][] = [
'@type' => 'WebPage',
'name' => $page['title'][$lang] ?? $page['title'][$this->defaultLanguage],
'url' => $url,
'inLanguage' => $lang
];
}
}
}
return json_encode($schema, JSON_PRETTY_PRINT);
}
}class RecipeSeoManager
{
private SeoManager $seoManager;
public function generateRecipeSeo(array $recipe): array
{
$content = $this->buildRecipeHtml($recipe);
$options = [
'type' => 'recipe',
'title' => $recipe['name'],
'description' => $recipe['description'],
'image' => $recipe['image'],
'recipe_data' => $recipe
];
$analysis = $this->seoManager->analyze($content, $options);
return [
'meta_tags' => $analysis->getMetaTags(),
'structured_data' => $this->generateRecipeStructuredData($recipe),
'social_tags' => $this->generateRecipeSocialTags($recipe)
];
}
private function generateRecipeStructuredData(array $recipe): string
{
$schema = [
'@context' => 'https://schema.org',
'@type' => 'Recipe',
'name' => $recipe['name'],
'description' => $recipe['description'],
'image' => $this->processRecipeImages($recipe['images']),
'author' => [
'@type' => 'Person',
'name' => $recipe['author']['name']
],
'datePublished' => $recipe['published_at'],
'prepTime' => $this->formatDuration($recipe['prep_time']),
'cookTime' => $this->formatDuration($recipe['cook_time']),
'totalTime' => $this->formatDuration($recipe['total_time']),
'recipeYield' => $recipe['servings'],
'recipeCategory' => $recipe['category'],
'recipeCuisine' => $recipe['cuisine'],
'keywords' => implode(',', $recipe['keywords'] ?? []),
'recipeIngredient' => $recipe['ingredients'],
'recipeInstructions' => $this->formatInstructions($recipe['instructions']),
'nutrition' => $this->formatNutrition($recipe['nutrition'] ?? [])
];
// Add ratings if available
if (!empty($recipe['rating'])) {
$schema['aggregateRating'] = [
'@type' => 'AggregateRating',
'ratingValue' => $recipe['rating']['average'],
'reviewCount' => $recipe['rating']['count']
];
}
// Add video if available
if (!empty($recipe['video'])) {
$schema['video'] = [
'@type' => 'VideoObject',
'name' => $recipe['name'] . ' - Video Recipe',
'description' => $recipe['description'],
'thumbnailUrl' => $recipe['video']['thumbnail'],
'contentUrl' => $recipe['video']['url'],
'uploadDate' => $recipe['video']['upload_date'] ?? $recipe['published_at']
];
}
return json_encode($schema, JSON_PRETTY_PRINT);
}
private function formatInstructions(array $instructions): array
{
return array_map(function($instruction, $index) {
return [
'@type' => 'HowToStep',
'position' => $index + 1,
'text' => $instruction['text'],
'url' => $instruction['url'] ?? null,
'image' => $instruction['image'] ?? null
];
}, $instructions, array_keys($instructions));
}
private function formatDuration(int $minutes): string
{
$hours = floor($minutes / 60);
$mins = $minutes % 60;
$duration = 'PT';
if ($hours > 0) {
$duration .= $hours . 'H';
}
if ($mins > 0) {
$duration .= $mins . 'M';
}
return $duration;
}
private function formatNutrition(array $nutrition): array
{
if (empty($nutrition)) {
return [];
}
return [
'@type' => 'NutritionInformation',
'calories' => $nutrition['calories'] ?? null,
'carbohydrateContent' => $nutrition['carbs'] ?? null,
'proteinContent' => $nutrition['protein'] ?? null,
'fatContent' => $nutrition['fat'] ?? null,
'fiberContent' => $nutrition['fiber'] ?? null,
'sugarContent' => $nutrition['sugar'] ?? null,
'sodiumContent' => $nutrition['sodium'] ?? null
];
}
}use Psr\SimpleCache\CacheInterface;
class CachedSeoManager
{
private SeoManager $seoManager;
private CacheInterface $cache;
private int $ttl;
public function __construct(SeoManager $seoManager, CacheInterface $cache, int $ttl = 3600)
{
$this->seoManager = $seoManager;
$this->cache = $cache;
$this->ttl = $ttl;
}
public function analyze(string $content, array $options = []): SeoAnalysis
{
$cacheKey = $this->generateCacheKey($content, $options);
$cached = $this->cache->get($cacheKey);
if ($cached !== null) {
return unserialize($cached);
}
$analysis = $this->seoManager->analyze($content, $options);
$this->cache->set($cacheKey, serialize($analysis), $this->ttl);
return $analysis;
}
public function batchAnalyze(array $items): array
{
$results = [];
$uncachedItems = [];
// Check cache for all items
foreach ($items as $key => $item) {
$cacheKey = $this->generateCacheKey($item['content'], $item['options']);
$cached = $this->cache->get($cacheKey);
if ($cached !== null) {
$results[$key] = unserialize($cached);
} else {
$uncachedItems[$key] = $item;
}
}
// Process uncached items
foreach ($uncachedItems as $key => $item) {
$analysis = $this->seoManager->analyze($item['content'], $item['options']);
$results[$key] = $analysis;
// Cache the result
$cacheKey = $this->generateCacheKey($item['content'], $item['options']);
$this->cache->set($cacheKey, serialize($analysis), $this->ttl);
}
return $results;
}
private function generateCacheKey(string $content, array $options): string
{
return 'seo_analysis_' . md5($content . serialize($options));
}
}class StreamingSeoProcessor
{
private SeoManager $seoManager;
private int $chunkSize;
public function __construct(SeoManager $seoManager, int $chunkSize = 100000)
{
$this->seoManager = $seoManager;
$this->chunkSize = $chunkSize;
}
public function processLargeContent(string $content): SeoAnalysis
{
if (strlen($content) <= $this->chunkSize) {
return $this->seoManager->analyze($content);
}
// Extract head and key content
$importantContent = $this->extractImportantContent($content);
return $this->seoManager->analyze($importantContent);
}
private function extractImportantContent(string $content): string
{
$dom = new DOMDocument();
@$dom->loadHTML($content);
$xpath = new DOMXPath($dom);
$important = '';
// Extract head
$head = $xpath->query('//head')->item(0);
if ($head) {
$important .= $dom->saveHTML($head);
}
// Extract main content areas
$selectors = [
'//main',
'//article',
'//*[@id="content"]',
'//*[@class="content"]',
'//h1 | //h2 | //h3'
];
foreach ($selectors as $selector) {
$elements = $xpath->query($selector);
foreach ($elements as $element) {
$important .= $dom->saveHTML($element);
// Stop if we've collected enough content
if (strlen($important) >= $this->chunkSize) {
break 2;
}
}
}
return '<html><head></head><body>' . $important . '</body></html>';
}
}These advanced examples demonstrate real-world usage patterns and provide a foundation for implementing comprehensive SEO solutions with the PHP-SEO package.