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); } }