loadConfiguration();
$this->initDatabase();
}
private function loadConfiguration()
{
$this->config = [
'site_name' => getenv('SITE_NAME') ?: 'Webshop',
'site_description' => getenv('SITE_DESCRIPTION') ?: 'Ihr Online-Shop für hochwertige Produkte',
'site_url' => getenv('SITE_URL') ?: 'https://webshop-system.de',
'default_image' => getenv('DEFAULT_IMAGE') ?: '/img/default-og.jpg',
'twitter_handle' => getenv('TWITTER_HANDLE') ?: '@webshop',
'google_analytics' => getenv('GOOGLE_ANALYTICS') ?: '',
'google_tag_manager' => getenv('GOOGLE_TAG_MANAGER') ?: '',
];
}
private function initDatabase()
{
$connectionParams = [
'dbname' => getenv('DB_DATABASE') ?: 'freeshop',
'user' => getenv('DB_USERNAME') ?: 'freeshop_user',
'password' => getenv('DB_PASSWORD') ?: 'freeshop_password',
'host' => getenv('DB_HOST') ?: 'db',
'driver' => 'pdo_mysql',
'port' => getenv('DB_PORT') ?: 3306,
'charset' => 'utf8mb4',
];
try {
$this->conn = DriverManager::getConnection($connectionParams);
} catch (Exception $e) {
// Database connection failed, continue without DB features
}
}
/**
* Generiert Meta-Tags für eine Seite
*/
public function generateMetaTags($data = [])
{
$defaults = [
'title' => $this->config['site_name'],
'description' => $this->config['site_description'],
'keywords' => '',
'image' => $this->config['default_image'],
'url' => $this->getCurrentUrl(),
'type' => 'website',
'author' => $this->config['site_name'],
'robots' => 'index, follow',
'canonical' => $this->getCurrentUrl(),
];
$meta = array_merge($defaults, $data);
return $this->renderMetaTags($meta);
}
/**
* Generiert Meta-Tags für ein Produkt
*/
public function generateProductMetaTags($product)
{
$meta = [
'title' => $product['name'] . ' - ' . $this->config['site_name'],
'description' => $this->truncateDescription($product['description'], 160),
'keywords' => $product['name'] . ', ' . $product['category_name'] . ', online kaufen',
'image' => $product['image'] ?: $this->config['default_image'],
'url' => $this->config['site_url'] . '/product/' . $product['id'],
'type' => 'product',
'price' => $product['price'],
'currency' => 'EUR',
'availability' => $product['stock'] > 0 ? 'in stock' : 'out of stock',
];
return $this->renderMetaTags($meta);
}
/**
* Generiert Meta-Tags für eine Kategorie
*/
public function generateCategoryMetaTags($category)
{
$meta = [
'title' => $category['name'] . ' - ' . $this->config['site_name'],
'description' => $this->truncateDescription($category['description'], 160),
'keywords' => $category['name'] . ', ' . $category['description'],
'url' => $this->config['site_url'] . '/category/' . $category['id'],
'type' => 'website',
];
return $this->renderMetaTags($meta);
}
/**
* Rendert die Meta-Tags als HTML
*/
private function renderMetaTags($meta)
{
$tags = [];
// Basic Meta Tags
$tags[] = '';
$tags[] = '';
$tags[] = '
' . htmlspecialchars($meta['title']) . '';
$tags[] = '';
if (!empty($meta['keywords'])) {
$tags[] = '';
}
$tags[] = '';
$tags[] = '';
// Canonical URL
$tags[] = '';
// Open Graph Tags
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
// Twitter Card Tags
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
// Product specific tags
if ($meta['type'] === 'product') {
$tags[] = '';
$tags[] = '';
$tags[] = '';
}
return implode("\n ", $tags);
}
/**
* Generiert eine XML-Sitemap
*/
public function generateSitemap()
{
if (!$this->conn) {
return false;
}
try {
$xml = '' . "\n";
$xml .= '' . "\n";
// Homepage
$xml .= $this->generateSitemapUrl($this->config['site_url'], '1.0', 'daily');
// Kategorien
$stmt = $this->conn->prepare('SELECT id, name, updated_at FROM ws_category WHERE active = 1');
$stmt->execute();
$categories = $stmt->fetchAllAssociative();
foreach ($categories as $category) {
$url = $this->config['site_url'] . '/category/' . $category['id'];
$lastmod = $category['updated_at'] ?: date('Y-m-d');
$xml .= $this->generateSitemapUrl($url, '0.8', 'weekly', $lastmod);
}
// Produkte
$stmt = $this->conn->prepare('SELECT id, name, updated_at FROM ws_product WHERE active = 1');
$stmt->execute();
$products = $stmt->fetchAllAssociative();
foreach ($products as $product) {
$url = $this->config['site_url'] . '/product/' . $product['id'];
$lastmod = $product['updated_at'] ?: date('Y-m-d');
$xml .= $this->generateSitemapUrl($url, '0.9', 'weekly', $lastmod);
}
$xml .= '';
return $xml;
} catch (Exception $e) {
return false;
}
}
/**
* Generiert eine einzelne Sitemap-URL
*/
private function generateSitemapUrl($url, $priority, $changefreq, $lastmod = null)
{
$xml = ' ' . "\n";
$xml .= ' ' . htmlspecialchars($url) . '' . "\n";
if ($lastmod) {
$xml .= ' ' . htmlspecialchars($lastmod) . '' . "\n";
}
$xml .= ' ' . htmlspecialchars($changefreq) . '' . "\n";
$xml .= ' ' . htmlspecialchars($priority) . '' . "\n";
$xml .= ' ' . "\n";
return $xml;
}
/**
* Generiert robots.txt Inhalt
*/
public function generateRobotsTxt()
{
$robots = "User-agent: *\n";
$robots .= "Allow: /\n";
$robots .= "Disallow: /admin/\n";
$robots .= "Disallow: /api/\n";
$robots .= "Disallow: /cart/\n";
$robots .= "Disallow: /checkout/\n";
$robots .= "Disallow: /account/\n";
$robots .= "Disallow: /login/\n";
$robots .= "Disallow: /register/\n";
$robots .= "Disallow: /search?\n";
$robots .= "Disallow: /*?*\n";
$robots .= "\n";
$robots .= "Sitemap: " . $this->config['site_url'] . "/sitemap.xml\n";
return $robots;
}
/**
* Generiert JSON-LD Structured Data
*/
public function generateStructuredData($type, $data)
{
switch ($type) {
case 'product':
return $this->generateProductStructuredData($data);
case 'organization':
return $this->generateOrganizationStructuredData();
case 'breadcrumb':
return $this->generateBreadcrumbStructuredData($data);
default:
return '';
}
}
/**
* Generiert Produkt-Structured Data
*/
private function generateProductStructuredData($product)
{
$structuredData = [
'@context' => 'https://schema.org/',
'@type' => 'Product',
'name' => $product['name'],
'description' => $product['description'],
'image' => $product['image'],
'offers' => [
'@type' => 'Offer',
'price' => $product['price'],
'priceCurrency' => 'EUR',
'availability' => $product['stock'] > 0 ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock',
'url' => $this->config['site_url'] . '/product/' . $product['id']
]
];
if (!empty($product['category_name'])) {
$structuredData['category'] = $product['category_name'];
}
return '';
}
/**
* Generiert Organization-Structured Data
*/
private function generateOrganizationStructuredData()
{
$structuredData = [
'@context' => 'https://schema.org/',
'@type' => 'Organization',
'name' => $this->config['site_name'],
'url' => $this->config['site_url'],
'logo' => $this->config['site_url'] . '/img/logo.png',
'contactPoint' => [
'@type' => 'ContactPoint',
'telephone' => getenv('CONTACT_PHONE') ?: '+49-123-456789',
'contactType' => 'customer service'
]
];
return '';
}
/**
* Generiert Breadcrumb-Structured Data
*/
private function generateBreadcrumbStructuredData($breadcrumbs)
{
$structuredData = [
'@context' => 'https://schema.org/',
'@type' => 'BreadcrumbList',
'itemListElement' => []
];
foreach ($breadcrumbs as $index => $breadcrumb) {
$structuredData['itemListElement'][] = [
'@type' => 'ListItem',
'position' => $index + 1,
'name' => $breadcrumb['name'],
'item' => $breadcrumb['url']
];
}
return '';
}
/**
* Generiert Google Analytics Code
*/
public function generateGoogleAnalytics()
{
if (empty($this->config['google_analytics'])) {
return '';
}
return "
";
}
/**
* Generiert Google Tag Manager Code
*/
public function generateGoogleTagManager()
{
if (empty($this->config['google_tag_manager'])) {
return '';
}
return "
";
}
/**
* Kürzt eine Beschreibung auf die gewünschte Länge
*/
private function truncateDescription($description, $length = 160)
{
$description = strip_tags($description);
if (strlen($description) <= $length) {
return $description;
}
return substr($description, 0, $length - 3) . '...';
}
/**
* Ermittelt die aktuelle URL
*/
private function getCurrentUrl()
{
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$uri = $_SERVER['REQUEST_URI'] ?? '/';
return $protocol . '://' . $host . $uri;
}
/**
* Optimiert URLs für SEO
*/
public function generateSlug($text)
{
// Umlaute ersetzen
$text = str_replace(
['ä', 'ö', 'ü', 'ß', 'Ä', 'Ö', 'Ü'],
['ae', 'oe', 'ue', 'ss', 'Ae', 'Oe', 'Ue'],
$text
);
// Nur Buchstaben, Zahlen und Bindestriche erlauben
$text = preg_replace('/[^a-zA-Z0-9\s-]/', '', $text);
// Mehrere Leerzeichen/Bindestriche zu einem Bindestrich
$text = preg_replace('/[\s-]+/', '-', $text);
// Am Anfang und Ende Bindestriche entfernen
$text = trim($text, '-');
// Kleinbuchstaben
$text = strtolower($text);
return $text;
}
/**
* Generiert Meta-Tags für Social Media
*/
public function generateSocialMetaTags($data = [])
{
$defaults = [
'title' => $this->config['site_name'],
'description' => $this->config['site_description'],
'image' => $this->config['default_image'],
'url' => $this->getCurrentUrl(),
];
$meta = array_merge($defaults, $data);
$tags = [];
// Facebook Open Graph
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
// Twitter Card
$tags[] = '';
$tags[] = '';
$tags[] = '';
$tags[] = '';
return implode("\n ", $tags);
}
}