Skip to content

Plain PHP Examples

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

Plain PHP Examples

This guide provides comprehensive examples for using the PHP-SEO package in plain PHP applications without any framework. Perfect for custom applications, legacy systems, or learning the core functionality.

Quick Start

Installation

Install the package via Composer:

composer require rumenx/php-seo

Basic Setup

Create a simple PHP file to get started:

<?php

require_once 'vendor/autoload.php';

use Rumenx\PhpSeo\Config\SeoConfig;
use Rumenx\PhpSeo\SeoManager;

// Basic configuration
$config = new SeoConfig([
    'ai' => [
        'enabled' => false, // Start without AI
    ],
    'cache' => [
        'enabled' => false, // No caching for simple start
    ],
]);

// Create SEO manager
$seoManager = new SeoManager($config);

// Example content
$content = '<h1>Welcome to My Website</h1><p>This is a great website about web development and SEO best practices.</p>';

// Analyze content
$analysis = $seoManager->analyze($content);

// Generate SEO elements
$title = $seoManager->generateTitle($analysis);
$description = $seoManager->generateDescription($analysis);
$keywords = $seoManager->generateKeywords($analysis);

echo "Generated Title: " . $title . "\n";
echo "Generated Description: " . $description . "\n";
echo "Generated Keywords: " . implode(', ', $keywords) . "\n";

Content Analysis

Basic Content Analysis

<?php

require_once 'vendor/autoload.php';

use Rumenx\PhpSeo\Config\SeoConfig;
use Rumenx\PhpSeo\SeoManager;

$config = new SeoConfig();
$seoManager = new SeoManager($config);

// Sample blog post content
$blogContent = '
    <article>
        <h1>The Ultimate Guide to PHP SEO</h1>
        <h2>Introduction to SEO</h2>
        <p>Search Engine Optimization (SEO) is crucial for web developers. 
           This comprehensive guide will teach you everything about PHP SEO.</p>
        
        <h2>Why SEO Matters</h2>
        <p>SEO helps your website rank higher in search results, bringing more 
           organic traffic and potential customers to your business.</p>
        
        <h3>Benefits of Good SEO</h3>
        <ul>
            <li>Increased organic traffic</li>
            <li>Better user experience</li>
            <li>Higher conversion rates</li>
            <li>Brand credibility</li>
        </ul>
        
        <h2>PHP SEO Best Practices</h2>
        <p>When developing PHP applications, consider these SEO factors...</p>
    </article>
';

// Analyze the content
$analysis = $seoManager->analyze($blogContent);

// Display analysis results
echo "<h2>Content Analysis Results:</h2>\n";
echo "<pre>\n";
echo "Word Count: " . $analysis['word_count'] . "\n";
echo "Character Count: " . $analysis['char_count'] . "\n";
echo "Reading Time: " . $analysis['reading_time'] . " minutes\n";

echo "\nHeading Structure:\n";
foreach ($analysis['headings'] as $heading) {
    echo "  {$heading['level']}: {$heading['text']}\n";
}

echo "\nTitle Tags Found:\n";
foreach ($analysis['title_tags'] as $title) {
    echo "  {$title['text']} (Level {$title['level']})\n";
}

echo "\nImages:\n";
echo "  Total: " . $analysis['images']['total'] . "\n";
echo "  Without Alt: " . $analysis['images']['without_alt'] . "\n";

echo "\nLinks:\n";
echo "  Internal: " . $analysis['links']['internal'] . "\n";
echo "  External: " . $analysis['links']['external'] . "\n";
echo "</pre>\n";

Advanced Analysis with Options

<?php

$advancedContent = file_get_contents('sample-article.html');

// Analyze with custom options
$analysis = $seoManager->analyze($advancedContent, [
    'url' => 'https://example.com/article',
    'target_keywords' => ['PHP SEO', 'search optimization', 'web development'],
    'competitors' => ['https://competitor1.com', 'https://competitor2.com'],
    'language' => 'en',
]);

// Keyword density analysis
echo "<h2>Keyword Analysis:</h2>\n";
if (isset($analysis['keyword_density'])) {
    foreach ($analysis['keyword_density'] as $keyword => $density) {
        echo "{$keyword}: {$density}%\n";
    }
}

// SEO score calculation
echo "<h2>SEO Score:</h2>\n";
echo "Overall Score: " . $analysis['seo_score'] . "/100\n";

echo "<h2>Recommendations:</h2>\n";
foreach ($analysis['recommendations'] as $recommendation) {
    echo "- {$recommendation}\n";
}

SEO Generation

Title Generation

<?php

// Different approaches to title generation
$content = '<h1>PHP Performance Tips</h1><p>Learn how to optimize your PHP applications for better performance and user experience.</p>';

$analysis = $seoManager->analyze($content);

// Basic title generation
$basicTitle = $seoManager->generateTitle($analysis);
echo "Basic Title: {$basicTitle}\n";

// Title with custom options
$customTitle = $seoManager->generateTitle($analysis, [
    'max_length' => 50,
    'include_brand' => true,
    'brand_name' => 'DevTips',
    'style' => 'question', // question, how-to, listicle, guide
]);
echo "Custom Title: {$customTitle}\n";

// Multiple title variations
$titleVariations = $seoManager->generateTitleVariations($analysis, [
    'count' => 5,
    'max_length' => 60,
]);

echo "\nTitle Variations:\n";
foreach ($titleVariations as $i => $title) {
    echo ($i + 1) . ". {$title}\n";
}

Description Generation

<?php

$description = $seoManager->generateDescription($analysis, [
    'max_length' => 160,
    'include_keywords' => true,
    'style' => 'benefit-focused', // benefit-focused, feature-focused, question
    'call_to_action' => true,
]);

echo "Generated Description: {$description}\n";
echo "Description Length: " . strlen($description) . " characters\n";

// Multiple description variations
$descriptionVariations = $seoManager->generateDescriptionVariations($analysis, [
    'count' => 3,
    'max_length' => 155,
]);

echo "\nDescription Variations:\n";
foreach ($descriptionVariations as $i => $desc) {
    echo ($i + 1) . ". {$desc}\n";
}

Keyword Generation

<?php

$keywords = $seoManager->generateKeywords($analysis, [
    'max_keywords' => 15,
    'focus' => 'long-tail', // long-tail, short-tail, mixed
    'include_related' => true,
]);

echo "Generated Keywords:\n";
foreach ($keywords as $keyword) {
    echo "- {$keyword}\n";
}

// Keyword analysis with competition data
$keywordAnalysis = $seoManager->analyzeKeywords($keywords, [
    'check_competition' => true,
    'include_search_volume' => true,
]);

echo "\nKeyword Analysis:\n";
foreach ($keywordAnalysis as $keyword => $data) {
    echo "{$keyword}:\n";
    echo "  Competition: {$data['competition']}\n";
    echo "  Search Volume: {$data['search_volume']}\n";
    echo "  Difficulty: {$data['difficulty']}\n";
}

Website Integration

Blog System Example

<?php

class SimpleBlog
{
    private SeoManager $seoManager;
    private array $articles = [];

    public function __construct(SeoManager $seoManager)
    {
        $this->seoManager = $seoManager;
    }

    public function addArticle(array $article): void
    {
        // Auto-generate SEO data if not provided
        if (empty($article['meta_title']) || empty($article['meta_description'])) {
            $seoData = $this->generateSeoForArticle($article);
            $article = array_merge($article, $seoData);
        }

        $this->articles[$article['slug']] = $article;
    }

    private function generateSeoForArticle(array $article): array
    {
        $content = $article['title'] . ' ' . $article['content'];
        $analysis = $this->seoManager->analyze($content);

        return [
            'meta_title' => $this->seoManager->generateTitle($analysis, [
                'max_length' => 60,
                'include_brand' => true,
                'brand_name' => 'My Blog',
            ]),
            'meta_description' => $this->seoManager->generateDescription($analysis, [
                'max_length' => 160,
                'call_to_action' => true,
            ]),
            'keywords' => $this->seoManager->generateKeywords($analysis, [
                'max_keywords' => 10,
            ]),
        ];
    }

    public function renderArticle(string $slug): string
    {
        if (!isset($this->articles[$slug])) {
            return $this->render404();
        }

        $article = $this->articles[$slug];
        
        return $this->renderPage([
            'title' => $article['meta_title'],
            'description' => $article['meta_description'],
            'keywords' => implode(', ', $article['keywords']),
            'content' => $this->renderArticleContent($article),
            'canonical' => "https://myblog.com/article/{$slug}",
        ]);
    }

    private function renderPage(array $data): string
    {
        return "<!DOCTYPE html>
<html lang=\"en\">
<head>
    <meta charset=\"UTF-8\">
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
    <title>{$data['title']}</title>
    <meta name=\"description\" content=\"{$data['description']}\">
    <meta name=\"keywords\" content=\"{$data['keywords']}\">
    <link rel=\"canonical\" href=\"{$data['canonical']}\">
    
    <!-- Open Graph -->
    <meta property=\"og:title\" content=\"{$data['title']}\">
    <meta property=\"og:description\" content=\"{$data['description']}\">
    <meta property=\"og:url\" content=\"{$data['canonical']}\">
    <meta property=\"og:type\" content=\"article\">
    
    <!-- Twitter Card -->
    <meta name=\"twitter:card\" content=\"summary\">
    <meta name=\"twitter:title\" content=\"{$data['title']}\">
    <meta name=\"twitter:description\" content=\"{$data['description']}\">
</head>
<body>
    <header>
        <h1>My Blog</h1>
        <nav>
            <a href=\"/\">Home</a>
            <a href=\"/articles\">Articles</a>
            <a href=\"/about\">About</a>
        </nav>
    </header>
    
    <main>
        {$data['content']}
    </main>
    
    <footer>
        <p>&copy; 2024 My Blog. All rights reserved.</p>
    </footer>
</body>
</html>";
    }

    private function renderArticleContent(array $article): string
    {
        return "<article>
    <header>
        <h1>{$article['title']}</h1>
        <time datetime=\"{$article['published_at']}\">{$article['published_at']}</time>
    </header>
    
    <div class=\"content\">
        {$article['content']}
    </div>
    
    <footer>
        <div class=\"tags\">
            " . implode(' ', array_map(fn($tag) => "<span class=\"tag\">{$tag}</span>", $article['tags'] ?? [])) . "
        </div>
    </footer>
</article>";
    }

    public function renderBlogIndex(): string
    {
        $indexAnalysis = $this->seoManager->analyze('Blog articles about web development, PHP, and SEO');
        
        return $this->renderPage([
            'title' => 'My Blog - Web Development Articles',
            'description' => 'Latest articles about web development, PHP programming, and SEO best practices.',
            'keywords' => 'web development, PHP, SEO, programming, blog',
            'content' => $this->renderArticleList(),
            'canonical' => 'https://myblog.com/',
        ]);
    }

    private function renderArticleList(): string
    {
        $html = '<section class="articles">';
        $html .= '<h1>Latest Articles</h1>';
        
        foreach ($this->articles as $slug => $article) {
            $html .= "<article class=\"article-preview\">
                <h2><a href=\"/article/{$slug}\">{$article['title']}</a></h2>
                <p>{$article['excerpt']}</p>
                <time>{$article['published_at']}</time>
            </article>";
        }
        
        $html .= '</section>';
        return $html;
    }
}

// Usage example
$config = new SeoConfig();
$seoManager = new SeoManager($config);
$blog = new SimpleBlog($seoManager);

// Add some articles
$blog->addArticle([
    'slug' => 'php-performance-tips',
    'title' => 'PHP Performance Optimization Tips',
    'content' => '<p>Learn how to optimize your PHP applications...</p>',
    'excerpt' => 'Essential tips for optimizing PHP application performance.',
    'published_at' => '2024-01-15',
    'tags' => ['PHP', 'Performance', 'Optimization'],
]);

$blog->addArticle([
    'slug' => 'seo-best-practices',
    'title' => 'SEO Best Practices for Developers',
    'content' => '<p>Every developer should know these SEO fundamentals...</p>',
    'excerpt' => 'Essential SEO knowledge for web developers.',
    'published_at' => '2024-01-10',
    'tags' => ['SEO', 'Web Development'],
]);

// Render pages
echo $blog->renderBlogIndex();
echo $blog->renderArticle('php-performance-tips');

E-commerce Product Pages

<?php

class ProductCatalog
{
    private SeoManager $seoManager;
    private array $products = [];

    public function __construct(SeoManager $seoManager)
    {
        $this->seoManager = $seoManager;
    }

    public function addProduct(array $product): void
    {
        // Generate SEO data for product
        $seoData = $this->generateProductSeo($product);
        $product = array_merge($product, $seoData);
        
        $this->products[$product['sku']] = $product;
    }

    private function generateProductSeo(array $product): array
    {
        $content = $this->buildProductContent($product);
        $analysis = $this->seoManager->analyze($content);

        $title = $this->seoManager->generateTitle($analysis, [
            'max_length' => 60,
            'include_brand' => true,
            'brand_name' => 'TechStore',
            'style' => 'product',
        ]);

        $description = $this->seoManager->generateDescription($analysis, [
            'max_length' => 160,
            'style' => 'benefit-focused',
            'call_to_action' => true,
        ]);

        // Product-specific keywords
        $keywords = array_merge(
            [$product['name'], $product['brand'], $product['category']],
            $this->seoManager->generateKeywords($analysis, ['max_keywords' => 8])
        );

        return [
            'meta_title' => $title,
            'meta_description' => $description,
            'keywords' => array_unique($keywords),
            'schema_org' => $this->generateProductSchema($product),
        ];
    }

    private function buildProductContent(array $product): string
    {
        return implode(' ', [
            $product['name'],
            $product['brand'],
            $product['category'],
            $product['description'],
            implode(' ', $product['features'] ?? []),
        ]);
    }

    private function generateProductSchema(array $product): array
    {
        return [
            '@context' => 'https://schema.org',
            '@type' => 'Product',
            'name' => $product['name'],
            'description' => $product['description'],
            'brand' => [
                '@type' => 'Brand',
                'name' => $product['brand'],
            ],
            'sku' => $product['sku'],
            'offers' => [
                '@type' => 'Offer',
                'price' => $product['price'],
                'priceCurrency' => $product['currency'] ?? 'USD',
                'availability' => $product['in_stock'] ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock',
            ],
            'aggregateRating' => isset($product['rating']) ? [
                '@type' => 'AggregateRating',
                'ratingValue' => $product['rating'],
                'reviewCount' => $product['review_count'] ?? 0,
            ] : null,
        ];
    }

    public function renderProduct(string $sku): string
    {
        if (!isset($this->products[$sku])) {
            return $this->render404();
        }

        $product = $this->products[$sku];
        
        return "<!DOCTYPE html>
<html lang=\"en\">
<head>
    <meta charset=\"UTF-8\">
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
    <title>{$product['meta_title']}</title>
    <meta name=\"description\" content=\"{$product['meta_description']}\">
    <meta name=\"keywords\" content=\"" . implode(', ', $product['keywords']) . "\">
    
    <!-- Product Schema -->
    <script type=\"application/ld+json\">
    " . json_encode($product['schema_org'], JSON_PRETTY_PRINT) . "
    </script>
    
    <!-- Open Graph -->
    <meta property=\"og:title\" content=\"{$product['meta_title']}\">
    <meta property=\"og:description\" content=\"{$product['meta_description']}\">
    <meta property=\"og:type\" content=\"product\">
    <meta property=\"og:image\" content=\"{$product['image']}\">
    <meta property=\"product:price:amount\" content=\"{$product['price']}\">
    <meta property=\"product:price:currency\" content=\"{$product['currency']}\">
</head>
<body>
    <main>
        <div class=\"product\">
            <h1>{$product['name']}</h1>
            <img src=\"{$product['image']}\" alt=\"{$product['name']}\">
            <div class=\"price\">${$product['price']}</div>
            <div class=\"description\">{$product['description']}</div>
            <button>Add to Cart</button>
        </div>
    </main>
</body>
</html>";
    }
}

// Usage
$catalog = new ProductCatalog($seoManager);

$catalog->addProduct([
    'sku' => 'LAPTOP-001',
    'name' => 'Gaming Laptop Pro X1',
    'brand' => 'TechBrand',
    'category' => 'Laptops',
    'description' => 'High-performance gaming laptop with RTX graphics and Intel i7 processor.',
    'price' => 1299.99,
    'currency' => 'USD',
    'image' => '/images/laptop-001.jpg',
    'in_stock' => true,
    'features' => ['RTX 4060', 'Intel i7', '16GB RAM', '512GB SSD'],
    'rating' => 4.5,
    'review_count' => 127,
]);

echo $catalog->renderProduct('LAPTOP-001');

AI Integration

Setting Up AI Providers

<?php

// Configuration with AI enabled
$config = new SeoConfig([
    'ai' => [
        'enabled' => true,
        'provider' => 'openai',
        'fallback_enabled' => true,
        'fallback_providers' => ['manual'],
    ],
    'providers' => [
        'openai' => [
            'api_key' => $_ENV['OPENAI_API_KEY'] ?? 'your-api-key',
            'model' => 'gpt-3.5-turbo',
            'timeout' => 30,
        ],
    ],
    'cache' => [
        'enabled' => true,
        'ttl' => 3600,
        'driver' => 'file',
    ],
]);

$seoManager = new SeoManager($config);

// Test AI integration
$content = '<h1>Artificial Intelligence in Web Development</h1>
<p>Explore how AI is revolutionizing web development, from automated testing to intelligent user interfaces.</p>';

$analysis = $seoManager->analyze($content);

// Generate with AI
$aiTitle = $seoManager->generateTitle($analysis, [
    'use_ai' => true,
    'max_length' => 60,
    'style' => 'engaging',
]);

$aiDescription = $seoManager->generateDescription($analysis, [
    'use_ai' => true,
    'max_length' => 160,
    'target_audience' => 'developers',
]);

$aiKeywords = $seoManager->generateKeywords($analysis, [
    'use_ai' => true,
    'max_keywords' => 10,
    'focus' => 'long-tail',
]);

echo "AI-Generated Title: {$aiTitle}\n";
echo "AI-Generated Description: {$aiDescription}\n";
echo "AI-Generated Keywords: " . implode(', ', $aiKeywords) . "\n";

Batch Processing with AI

<?php

class BatchSeoProcessor
{
    private SeoManager $seoManager;
    private array $results = [];

    public function __construct(SeoManager $seoManager)
    {
        $this->seoManager = $seoManager;
    }

    public function processUrls(array $urls): array
    {
        foreach ($urls as $url) {
            try {
                $this->processUrl($url);
                // Rate limiting to respect API limits
                usleep(100000); // 0.1 second delay
            } catch (Exception $e) {
                $this->results[$url] = [
                    'error' => $e->getMessage(),
                ];
            }
        }

        return $this->results;
    }

    private function processUrl(string $url): void
    {
        // Fetch content (you would implement actual HTTP fetching)
        $content = $this->fetchContent($url);
        
        if (!$content) {
            throw new Exception("Could not fetch content from {$url}");
        }

        $analysis = $this->seoManager->analyze($content, ['url' => $url]);

        $this->results[$url] = [
            'title' => $this->seoManager->generateTitle($analysis, ['use_ai' => true]),
            'description' => $this->seoManager->generateDescription($analysis, ['use_ai' => true]),
            'keywords' => $this->seoManager->generateKeywords($analysis, ['use_ai' => true]),
            'analysis' => [
                'word_count' => $analysis['word_count'],
                'seo_score' => $analysis['seo_score'],
                'recommendations' => $analysis['recommendations'],
            ],
        ];
    }

    private function fetchContent(string $url): ?string
    {
        // Simple content fetching (in real implementation, use a proper HTTP client)
        $context = stream_context_create([
            'http' => [
                'timeout' => 10,
                'user_agent' => 'SEO-Bot/1.0',
            ],
        ]);

        return @file_get_contents($url, false, $context);
    }

    public function saveResults(string $filename): void
    {
        $csv = fopen($filename, 'w');
        
        // CSV headers
        fputcsv($csv, ['URL', 'Title', 'Description', 'Keywords', 'Word Count', 'SEO Score', 'Recommendations']);

        foreach ($this->results as $url => $data) {
            if (isset($data['error'])) {
                fputcsv($csv, [$url, 'ERROR', $data['error'], '', '', '', '']);
            } else {
                fputcsv($csv, [
                    $url,
                    $data['title'],
                    $data['description'],
                    implode('; ', $data['keywords']),
                    $data['analysis']['word_count'],
                    $data['analysis']['seo_score'],
                    implode('; ', $data['analysis']['recommendations']),
                ]);
            }
        }

        fclose($csv);
    }
}

// Usage
$processor = new BatchSeoProcessor($seoManager);

$urls = [
    'https://example.com/page1',
    'https://example.com/page2',
    'https://example.com/page3',
];

$results = $processor->processUrls($urls);
$processor->saveResults('seo-analysis-results.csv');

echo "Processed " . count($urls) . " URLs\n";
echo "Results saved to seo-analysis-results.csv\n";

Sitemap Generation

XML Sitemap

<?php

class SitemapGenerator
{
    private SeoManager $seoManager;

    public function __construct(SeoManager $seoManager)
    {
        $this->seoManager = $seoManager;
    }

    public function generateSitemap(array $urls): string
    {
        $sitemap = $this->seoManager->generateSitemap([
            'domain' => 'https://example.com',
            'routes' => $this->prepareRoutes($urls),
        ]);

        return $sitemap;
    }

    private function prepareRoutes(array $urls): array
    {
        $routes = [];

        foreach ($urls as $url => $data) {
            $routes[] = [
                'url' => $url,
                'lastmod' => $data['lastmod'] ?? date('c'),
                'changefreq' => $data['changefreq'] ?? 'weekly',
                'priority' => $data['priority'] ?? '0.5',
            ];
        }

        return $routes;
    }

    public function saveSitemap(string $filename, array $urls): void
    {
        $sitemap = $this->generateSitemap($urls);
        file_put_contents($filename, $sitemap);
    }
}

// Usage
$sitemapGenerator = new SitemapGenerator($seoManager);

$urls = [
    'https://example.com/' => [
        'lastmod' => '2024-01-15T10:00:00+00:00',
        'changefreq' => 'daily',
        'priority' => '1.0',
    ],
    'https://example.com/about' => [
        'lastmod' => '2024-01-10T10:00:00+00:00',
        'changefreq' => 'monthly',
        'priority' => '0.8',
    ],
    'https://example.com/products' => [
        'lastmod' => '2024-01-12T10:00:00+00:00',
        'changefreq' => 'weekly',
        'priority' => '0.9',
    ],
];

$sitemapGenerator->saveSitemap('sitemap.xml', $urls);
echo "Sitemap generated: sitemap.xml\n";

Caching Implementation

File-based Caching

<?php

class FileCache
{
    private string $cacheDir;

    public function __construct(string $cacheDir = 'cache')
    {
        $this->cacheDir = $cacheDir;
        if (!is_dir($cacheDir)) {
            mkdir($cacheDir, 0755, true);
        }
    }

    public function get(string $key): mixed
    {
        $filename = $this->getCacheFilename($key);
        
        if (!file_exists($filename)) {
            return null;
        }

        $data = unserialize(file_get_contents($filename));
        
        if ($data['expires'] < time()) {
            unlink($filename);
            return null;
        }

        return $data['value'];
    }

    public function set(string $key, mixed $value, int $ttl = 3600): void
    {
        $filename = $this->getCacheFilename($key);
        $data = [
            'value' => $value,
            'expires' => time() + $ttl,
        ];

        file_put_contents($filename, serialize($data));
    }

    private function getCacheFilename(string $key): string
    {
        return $this->cacheDir . '/' . md5($key) . '.cache';
    }
}

// SEO Manager with caching
class CachedSeoManager
{
    private SeoManager $seoManager;
    private FileCache $cache;

    public function __construct(SeoManager $seoManager, FileCache $cache)
    {
        $this->seoManager = $seoManager;
        $this->cache = $cache;
    }

    public function generateCachedTitle(string $content, array $options = []): string
    {
        $cacheKey = 'title_' . md5($content . serialize($options));
        
        $cached = $this->cache->get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        $analysis = $this->seoManager->analyze($content);
        $title = $this->seoManager->generateTitle($analysis, $options);
        
        $this->cache->set($cacheKey, $title, 3600);
        
        return $title;
    }

    public function generateCachedDescription(string $content, array $options = []): string
    {
        $cacheKey = 'description_' . md5($content . serialize($options));
        
        $cached = $this->cache->get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        $analysis = $this->seoManager->analyze($content);
        $description = $this->seoManager->generateDescription($analysis, $options);
        
        $this->cache->set($cacheKey, $description, 3600);
        
        return $description;
    }
}

// Usage
$cache = new FileCache('seo_cache');
$cachedSeoManager = new CachedSeoManager($seoManager, $cache);

$content = '<h1>PHP Caching Strategies</h1><p>Learn about different caching strategies...</p>';

// These will be cached after first call
$title1 = $cachedSeoManager->generateCachedTitle($content);
$title2 = $cachedSeoManager->generateCachedTitle($content); // Returns cached version

echo "Title: {$title1}\n";
echo "Cached title: {$title2}\n";

Error Handling

Robust Error Handling

<?php

class RobustSeoManager
{
    private SeoManager $seoManager;
    private array $errorLog = [];

    public function __construct(SeoManager $seoManager)
    {
        $this->seoManager = $seoManager;
    }

    public function safeTitleGeneration(string $content, array $options = []): string
    {
        try {
            $analysis = $this->seoManager->analyze($content);
            return $this->seoManager->generateTitle($analysis, $options);
        } catch (Exception $e) {
            $this->logError('title_generation', $e);
            return $this->fallbackTitle($content);
        }
    }

    public function safeDescriptionGeneration(string $content, array $options = []): string
    {
        try {
            $analysis = $this->seoManager->analyze($content);
            return $this->seoManager->generateDescription($analysis, $options);
        } catch (Exception $e) {
            $this->logError('description_generation', $e);
            return $this->fallbackDescription($content);
        }
    }

    private function fallbackTitle(string $content): string
    {
        // Extract first heading or use a generic title
        if (preg_match('/<h[1-6][^>]*>(.*?)<\/h[1-6]>/i', $content, $matches)) {
            return strip_tags($matches[1]);
        }

        return 'Untitled Page';
    }

    private function fallbackDescription(string $content): string
    {
        // Extract first paragraph or create from title
        $text = strip_tags($content);
        $text = preg_replace('/\s+/', ' ', $text);
        
        if (strlen($text) > 160) {
            $text = substr($text, 0, 157) . '...';
        }

        return $text ?: 'Page description not available.';
    }

    private function logError(string $operation, Exception $e): void
    {
        $this->errorLog[] = [
            'operation' => $operation,
            'error' => $e->getMessage(),
            'timestamp' => date('Y-m-d H:i:s'),
            'trace' => $e->getTraceAsString(),
        ];

        // Log to file
        error_log("[SEO Error] {$operation}: {$e->getMessage()}");
    }

    public function getErrors(): array
    {
        return $this->errorLog;
    }

    public function hasErrors(): bool
    {
        return !empty($this->errorLog);
    }
}

// Usage with error handling
$robustSeoManager = new RobustSeoManager($seoManager);

$content = '<h1>Test Article</h1><p>Some content here...</p>';

$title = $robustSeoManager->safeTitleGeneration($content);
$description = $robustSeoManager->safeDescriptionGeneration($content);

if ($robustSeoManager->hasErrors()) {
    echo "Errors occurred during SEO generation:\n";
    foreach ($robustSeoManager->getErrors() as $error) {
        echo "- {$error['operation']}: {$error['error']}\n";
    }
}

echo "Title: {$title}\n";
echo "Description: {$description}\n";

Command Line Tools

CLI SEO Analyzer

#!/usr/bin/env php
<?php

require_once 'vendor/autoload.php';

use Rumenx\PhpSeo\Config\SeoConfig;
use Rumenx\PhpSeo\SeoManager;

class SeoCliTool
{
    private SeoManager $seoManager;

    public function __construct()
    {
        $config = new SeoConfig([
            'ai' => [
                'enabled' => !empty($_ENV['OPENAI_API_KEY']),
                'provider' => 'openai',
            ],
            'providers' => [
                'openai' => [
                    'api_key' => $_ENV['OPENAI_API_KEY'] ?? '',
                ],
            ],
        ]);

        $this->seoManager = new SeoManager($config);
    }

    public function run(array $argv): void
    {
        if (count($argv) < 2) {
            $this->showHelp();
            return;
        }

        $command = $argv[1];

        switch ($command) {
            case 'analyze':
                $this->analyzeCommand($argv);
                break;
            case 'generate':
                $this->generateCommand($argv);
                break;
            case 'bulk':
                $this->bulkCommand($argv);
                break;
            default:
                $this->showHelp();
        }
    }

    private function analyzeCommand(array $argv): void
    {
        if (count($argv) < 3) {
            echo "Usage: php seo-cli.php analyze <file-or-url>\n";
            return;
        }

        $input = $argv[2];
        $content = $this->getContent($input);

        if (!$content) {
            echo "Error: Could not load content from {$input}\n";
            return;
        }

        $analysis = $this->seoManager->analyze($content);

        echo "SEO Analysis Results for: {$input}\n";
        echo str_repeat('=', 50) . "\n";
        echo "Word Count: {$analysis['word_count']}\n";
        echo "Character Count: {$analysis['char_count']}\n";
        echo "Reading Time: {$analysis['reading_time']} minutes\n";
        echo "SEO Score: {$analysis['seo_score']}/100\n";
        echo "\nRecommendations:\n";
        foreach ($analysis['recommendations'] as $recommendation) {
            echo "- {$recommendation}\n";
        }
    }

    private function generateCommand(array $argv): void
    {
        if (count($argv) < 4) {
            echo "Usage: php seo-cli.php generate <type> <file-or-url>\n";
            echo "Types: title, description, keywords, all\n";
            return;
        }

        $type = $argv[2];
        $input = $argv[3];
        $content = $this->getContent($input);

        if (!$content) {
            echo "Error: Could not load content from {$input}\n";
            return;
        }

        $analysis = $this->seoManager->analyze($content);

        switch ($type) {
            case 'title':
                $title = $this->seoManager->generateTitle($analysis);
                echo "Generated Title: {$title}\n";
                break;
            case 'description':
                $description = $this->seoManager->generateDescription($analysis);
                echo "Generated Description: {$description}\n";
                break;
            case 'keywords':
                $keywords = $this->seoManager->generateKeywords($analysis);
                echo "Generated Keywords: " . implode(', ', $keywords) . "\n";
                break;
            case 'all':
                $title = $this->seoManager->generateTitle($analysis);
                $description = $this->seoManager->generateDescription($analysis);
                $keywords = $this->seoManager->generateKeywords($analysis);
                
                echo "Generated SEO Elements:\n";
                echo "Title: {$title}\n";
                echo "Description: {$description}\n";
                echo "Keywords: " . implode(', ', $keywords) . "\n";
                break;
            default:
                echo "Unknown type: {$type}\n";
        }
    }

    private function bulkCommand(array $argv): void
    {
        if (count($argv) < 3) {
            echo "Usage: php seo-cli.php bulk <urls-file>\n";
            return;
        }

        $urlsFile = $argv[2];
        if (!file_exists($urlsFile)) {
            echo "Error: File {$urlsFile} does not exist\n";
            return;
        }

        $urls = array_filter(file($urlsFile, FILE_IGNORE_NEW_LINES));
        $results = [];

        echo "Processing " . count($urls) . " URLs...\n";

        foreach ($urls as $i => $url) {
            echo "Processing " . ($i + 1) . "/" . count($urls) . ": {$url}\n";
            
            $content = $this->getContent(trim($url));
            if ($content) {
                $analysis = $this->seoManager->analyze($content);
                $results[] = [
                    'url' => $url,
                    'title' => $this->seoManager->generateTitle($analysis),
                    'description' => $this->seoManager->generateDescription($analysis),
                    'seo_score' => $analysis['seo_score'],
                ];
            }

            // Rate limiting
            usleep(500000); // 0.5 second delay
        }

        // Save results to CSV
        $csvFile = 'seo-bulk-results-' . date('Y-m-d-H-i-s') . '.csv';
        $csv = fopen($csvFile, 'w');
        fputcsv($csv, ['URL', 'Title', 'Description', 'SEO Score']);

        foreach ($results as $result) {
            fputcsv($csv, [
                $result['url'],
                $result['title'],
                $result['description'],
                $result['seo_score'],
            ]);
        }

        fclose($csv);
        echo "Results saved to: {$csvFile}\n";
    }

    private function getContent(string $input): ?string
    {
        if (filter_var($input, FILTER_VALIDATE_URL)) {
            // It's a URL
            $context = stream_context_create([
                'http' => [
                    'timeout' => 10,
                    'user_agent' => 'SEO-CLI-Tool/1.0',
                ],
            ]);
            return @file_get_contents($input, false, $context);
        } elseif (file_exists($input)) {
            // It's a file
            return file_get_contents($input);
        }

        return null;
    }

    private function showHelp(): void
    {
        echo "SEO CLI Tool\n";
        echo "Usage: php seo-cli.php <command> [options]\n\n";
        echo "Commands:\n";
        echo "  analyze <file-or-url>        Analyze SEO of content\n";
        echo "  generate <type> <file-or-url> Generate SEO elements\n";
        echo "  bulk <urls-file>             Process multiple URLs\n\n";
        echo "Examples:\n";
        echo "  php seo-cli.php analyze https://example.com\n";
        echo "  php seo-cli.php generate title page.html\n";
        echo "  php seo-cli.php bulk urls.txt\n";
    }
}

// Run the CLI tool
$tool = new SeoCliTool();
$tool->run($argv);

Best Practices

Content Quality Guidelines

<?php

class SeoContentValidator
{
    private SeoManager $seoManager;

    public function __construct(SeoManager $seoManager)
    {
        $this->seoManager = $seoManager;
    }

    public function validateContent(string $content): array
    {
        $analysis = $this->seoManager->analyze($content);
        $issues = [];
        $recommendations = [];

        // Check word count
        if ($analysis['word_count'] < 300) {
            $issues[] = 'Content is too short (minimum 300 words recommended)';
        }

        // Check title tags
        if (empty($analysis['title_tags'])) {
            $issues[] = 'No title tags found';
        } elseif (count($analysis['title_tags']) > 1) {
            $issues[] = 'Multiple H1 tags found (should be only one)';
        }

        // Check heading structure
        $headings = $analysis['headings'];
        if (!empty($headings)) {
            $levels = array_column($headings, 'level');
            if (!in_array(1, $levels)) {
                $issues[] = 'No H1 heading found';
            }
            
            // Check for skipped heading levels
            sort($levels);
            for ($i = 1; $i < count($levels); $i++) {
                if ($levels[$i] - $levels[$i-1] > 1) {
                    $issues[] = 'Heading levels are not sequential';
                    break;
                }
            }
        }

        // Check images
        if ($analysis['images']['without_alt'] > 0) {
            $issues[] = "{$analysis['images']['without_alt']} images without alt text";
        }

        // Generate recommendations
        if ($analysis['word_count'] < 1000) {
            $recommendations[] = 'Consider expanding content for better SEO performance';
        }

        if ($analysis['links']['external'] === 0) {
            $recommendations[] = 'Add relevant external links to authoritative sources';
        }

        if ($analysis['links']['internal'] < 2) {
            $recommendations[] = 'Add more internal links to related content';
        }

        return [
            'score' => $analysis['seo_score'],
            'issues' => $issues,
            'recommendations' => $recommendations,
            'analysis' => $analysis,
        ];
    }

    public function generateQualityReport(string $content): string
    {
        $validation = $this->validateContent($content);
        
        $report = "SEO Quality Report\n";
        $report .= str_repeat('=', 30) . "\n";
        $report .= "Overall Score: {$validation['score']}/100\n\n";

        if (!empty($validation['issues'])) {
            $report .= "Issues Found:\n";
            foreach ($validation['issues'] as $issue) {
                $report .= "{$issue}\n";
            }
            $report .= "\n";
        }

        if (!empty($validation['recommendations'])) {
            $report .= "Recommendations:\n";
            foreach ($validation['recommendations'] as $recommendation) {
                $report .= "💡 {$recommendation}\n";
            }
        }

        return $report;
    }
}

// Usage
$validator = new SeoContentValidator($seoManager);
$content = '<h1>My Article</h1><p>Short content here...</p>';

$report = $validator->generateQualityReport($content);
echo $report;

Next Steps

Clone this wiki locally