-
-
Notifications
You must be signed in to change notification settings - Fork 1
Plain PHP Examples
Rumen Damyanov edited this page Sep 22, 2025
·
1 revision
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.
Install the package via Composer:
composer require rumenx/php-seoCreate 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";<?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";<?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";
}<?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";
}<?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";
}<?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";
}<?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>© 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');<?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');<?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";<?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";<?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";<?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";<?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";#!/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);<?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;- Configuration Guide - Advanced configuration options
- AI Integration - Setup AI providers for better results
- Laravel Examples - Framework-specific integration
- Symfony Examples - Symfony framework integration
- Performance Optimization - Optimize for production use