sark 1 mese fa
parent
commit
9c5ee72e55

+ 26 - 0
.gitignore

@@ -0,0 +1,26 @@
+# Database
+database/database.db
+
+# Uploads
+uploads/*
+!uploads/.gitkeep
+
+# Logs
+*.log
+
+# Cache
+cache/*
+!cache/.gitkeep
+
+# Environment
+.env
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+
+# OS
+.DS_Store
+Thumbs.db

+ 14 - 0
bin/migrate.php

@@ -9,6 +9,20 @@
 require_once __DIR__ . '/../vendor/autoload.php';
 
 try {
+    // Create database directory and file if they don't exist
+    $dbPath = \Config::PATH['root'] . '/database/database.db';
+    $dbDir = dirname($dbPath);
+    
+    if (!is_dir($dbDir)) {
+        mkdir($dbDir, 0755, true);
+        echo "✓ Created database directory\n";
+    }
+    
+    if (!file_exists($dbPath)) {
+        touch($dbPath);
+        echo "✓ Created database file\n";
+    }
+    
     $db = db();
     
     echo "Starting database migration...\n";

+ 1 - 0
database/.gitignore

@@ -0,0 +1 @@
+*.sqlite*

BIN
database/database.db


+ 16 - 6
resources/view/admin/pages/form.php

@@ -195,12 +195,22 @@ ob_start();
                                     </div>
 
                                     <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
-                                        <div>
-                                            <label for="seo_canonical" class="block text-sm font-medium text-gray-700 mb-2">Canonical URL</label>
-                                            <input type="url" name="seo[canonical]" id="seo_canonical"
-                                                   value="<?= htmlspecialchars($seoMeta['canonical'] ?? '') ?>" 
-                                                   class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
-                                                   placeholder="https://example.com/page">
+                                        <div class="grid grid-cols-1 lg:grid-cols-4 gap-4">
+                                            <div class="lg:col-span-3">
+                                                <label for="seo_canonical" class="block text-sm font-medium text-gray-700 mb-2">Canonical URL</label>
+                                                <input type="url" name="seo[canonical]" id="seo_canonical"
+                                                       value="<?= htmlspecialchars($seoMeta['canonical'] ?? '') ?>" 
+                                                       class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
+                                                       placeholder="https://example.com/page">
+                                            </div>
+
+                                            <div>
+                                                <label for="seo_locale" class="block text-sm font-medium text-gray-700 mb-2">Locale</label>
+                                                <input type="text" name="seo[extra_fields][locale]" id="seo_locale"
+                                                       value="<?= htmlspecialchars($seoMeta['extra_fields']['locale'] ?? 'en') ?>" 
+                                                       class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
+                                                       placeholder="en">
+                                            </div>
                                         </div>
 
                                         <div>

+ 7 - 57
resources/view/admin/pages/layouts/front_page.php

@@ -1,71 +1,21 @@
 <!-- Front Page Layout Form -->
 <div class="space-y-6">
 
-    <!-- Hero Section -->
-    <div class="bg-gray-50 rounded-lg p-4">
-        <h4 class="text-md font-medium text-gray-800 mb-4">Hero Section</h4>
-        <div class="space-y-4">
-            <div>
-                <label for="hero_title" class="block text-sm font-medium text-gray-700 mb-2">Hero Title</label>
-                <input type="text" name="extra_fields[hero_title]" id="hero_title"
-                       value="<?= htmlspecialchars($page['extra_fields']['hero_title'] ?? '') ?>"
-                       class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
-                       placeholder="Welcome to Our Amazing Site">
-            </div>
-
-            <div>
-                <label for="hero_subtitle" class="block text-sm font-medium text-gray-700 mb-2">Hero Subtitle</label>
-                <textarea name="extra_fields[hero_subtitle]" id="hero_subtitle" rows="2"
-                          class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
-                          placeholder="Discover amazing content and experiences..."><?= htmlspecialchars($page['extra_fields']['hero_subtitle'] ?? '') ?></textarea>
-            </div>
-
-            <div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
-                <div>
-                    <label for="hero_button_text" class="block text-sm font-medium text-gray-700 mb-2">Hero Button Text</label>
-                    <input type="text" name="extra_fields[hero_button_text]" id="hero_button_text"
-                           value="<?= htmlspecialchars($page['extra_fields']['hero_button_text'] ?? '') ?>"
-                           class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
-                           placeholder="Get Started">
-                </div>
-
-                <div>
-                    <label for="hero_button_url" class="block text-sm font-medium text-gray-700 mb-2">Hero Button URL</label>
-                    <input type="text" name="extra_fields[hero_button_url]" id="hero_button_url"
-                           value="<?= htmlspecialchars($page['extra_fields']['hero_button_url'] ?? '') ?>"
-                           class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
-                           placeholder="/contact">
-                </div>
-            </div>
-        </div>
+    <!-- Top Content -->
+    <div>
+        <label for="top_content" class="block text-sm font-medium text-gray-700 mb-2">Top Content</label>
+        <textarea name="extra_fields[top_content]" id="top_content" rows="8"
+                  class="secondary-content w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
+                  placeholder="Enter text that will appear at the top of the page..."><?= htmlspecialchars($page['extra_fields']['top_content'] ?? '') ?></textarea>
     </div>
 
-    <!-- Featured Sections -->
-    <div class="bg-gray-50 rounded-lg p-4">
-        <h4 class="text-md font-medium text-gray-800 mb-4">Featured Sections</h4>
-        <div class="space-y-4">
-            <div>
-                <label for="featured_title" class="block text-sm font-medium text-gray-700 mb-2">Featured Section Title</label>
-                <input type="text" name="extra_fields[featured_title]" id="featured_title"
-                       value="<?= htmlspecialchars($page['extra_fields']['featured_title'] ?? '') ?>"
-                       class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
-                       placeholder="Why Choose Us">
-            </div>
 
-            <div>
-                <label for="featured_content" class="block text-sm font-medium text-gray-700 mb-2">Featured Content</label>
-                <textarea name="extra_fields[featured_content]" id="featured_content" rows="6"
-                          class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
-                          placeholder="Describe your featured content..."><?= htmlspecialchars($page['extra_fields']['featured_content'] ?? '') ?></textarea>
-            </div>
-        </div>
-    </div>
 
     <!-- Main Content -->
     <div>
         <label for="content" class="block text-sm font-medium text-gray-700 mb-2">Main Page Content</label>
         <textarea name="content" id="content" rows="8"
-                  class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
+                  class="secondary-content w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
                   placeholder="Enter main content for the homepage..."><?= htmlspecialchars($page['content'] ?? '') ?></textarea>
     </div>
 </div>

+ 26 - 23
resources/view/layouts/main.php

@@ -1,20 +1,22 @@
+<?php
+$settingsContent = settings('content')->getAll();
+?>
 <!DOCTYPE html>
-<html lang="<?= $isHomepage ? ($seo['lang'] ?? 'en') : ($seo['lang-page'] ?? 'en-US') ?>">
+<html lang="<?= $seo['extra_fields']['locale'] ?? 'en' ?>">
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <base href="/">
-    <title><?= $content['title'] ?></title>
+    <title><?= $seo['title'] ?></title>
     <link rel="stylesheet" href="css/styles.css">
     <meta name='robots' content='index, follow' />
-    <?php if (!empty($content['favicon'])): ?>
-        <link rel="icon" href="<?= htmlspecialchars($content['favicon']) ?>" type="image/x-icon">
+    <?php if (!empty($settingsContent['favicon'])): ?>
+        <link rel="icon" href="<?= htmlspecialchars($settingsContent['favicon']) ?>" type="image/x-icon">
     <?php endif; ?>
-    <meta property="og:type" content="<?= $seo['og-type'] ?? '' ?>">
-    <meta property="og:title" content="<?= $seo['og-title'] ?? '' ?>">
-    <meta property="og:description" content="<?= $seo['og-description'] ?? '' ?>">
-    <meta property="og:locale" content="<?= $seo['og-locale'] ?? '' ?>">
-    <meta property="og:image" content="<?= htmlspecialchars($seo['og-image'] ?? '') ?>">
+    <meta property="og:title" content="<?= $seo['title'] ?? '' ?>">
+    <meta property="og:description" content="<?= $seo['description'] ?? '' ?>">
+    <meta property="og:locale" content="<?= $seo['extra_fields']['locale'] ?? '' ?>">
+    <meta property="og:image" content="<?= htmlspecialchars($seo['image'] ?? '') ?>">
     <meta name="description" content="<?= $seo['description'] ?? '' ?>">
 
     <link rel="canonical" href="<?= $seo['canonical'] ?? '' ?>">
@@ -25,22 +27,22 @@
     "@graph" => [
         [
             "@type" => "WebPage",
-            "name" => $content['title'],
-            "description" => $content['description'],
-            "inLanguage" => $content['lang'],
+            "name" => $settingsContent['title'],
+            "description" => $settingsContent['description'],
+            "inLanguage" => $settingsContent['lang'],
             "url" => $currentUrl,
-            "dateModified" => $content['modified-date'] ?? '' , // ISO формат
+            "dateModified" => $settingsContent['modified-date'] ?? '' , // ISO формат
             "author" => [
                 "@type" => "Person",
-                "name" => $content['author-name'] ?? '',
-                "image" => $currentDomain . '/' . htmlspecialchars($content['author-img'] ?? '')
+                "name" => $settingsContent['author-name'] ?? '',
+                "image" => $currentDomain . '/' . htmlspecialchars($settingsContent['author-img'] ?? '')
             ]
         ],
         [
             "@type" => "Organization",
             "name" => $domainName,
             "url" => $currentDomain,
-            "logo" => $currentDomain . '/' . htmlspecialchars($content['uploaded_image'] ?? '')
+            "logo" => $currentDomain . '/' . htmlspecialchars($settingsContent['uploaded_image'] ?? '')
         ],
         [
             "@type" => "BreadcrumbList",
@@ -48,27 +50,28 @@
                 [
                     "@type" => "ListItem",
                     "position" => 1,
-                    "name" => $content['title-h1'],
+                    "name" => $settingsContent['title-h1'],
                     "item" => $currentUrl
                 ]
             ]
         ],
         !empty($casinoItems) ? [
             "@type" => "ItemList",
-            "name" => htmlspecialchars($content['listing']),
+            "name" => htmlspecialchars($settingsContent['listing']),
             "itemListElement" => array_map(function ($item, $index) use ($currentDomain, $currentReviewCount) {
+                $data = json_decode($item['value'], true);
                 return [
                     "@type" => "ListItem",
                     "position" => $index + 1,
                     "item" => [
                         "@type" => "Offer",
-                        "name" => htmlspecialchars($item['heading']),
-                        "description" => htmlspecialchars($item['text']),
-                        "url" => $currentDomain . '/#' . getSlug($item['heading']),
+                        "name" => htmlspecialchars($data['heading']),
+                        "description" => htmlspecialchars($data['text']),
+                        "url" => $currentDomain . '/#' . getSlug($data['heading']),
                         "offeredBy" => [
                             "@type" => "Organization",
-                            "name" => htmlspecialchars($item['heading']),
-                            "logo" => $currentDomain . '/' . htmlspecialchars($item['image']),
+                            "name" => htmlspecialchars($data['heading']),
+                            "logo" => $currentDomain . '/' . htmlspecialchars($data['image']),
                             "aggregateRating" => [
                                 "@type" => "AggregateRating",
                                 "ratingValue" => "5",

+ 32 - 3
src/Models/Page.php

@@ -20,16 +20,39 @@ class Page
     
     public function getById($id)
     {
-        return $this->db->fetchOne("SELECT * FROM pages WHERE id = ?", [$id]);
+        $result = $this->db->fetchOne("SELECT * FROM pages WHERE id = ?", [$id]);
+        
+        // Decode extra_fields JSON
+        if ($result && !empty($result['extra_fields'])) {
+            $result['extra_fields'] = json_decode($result['extra_fields'], true) ?: [];
+        } else if ($result) {
+            $result['extra_fields'] = [];
+        }
+        
+        return $result;
     }
     
     public function getBySlug($slug)
     {
-        return $this->db->fetchOne("SELECT * FROM pages WHERE slug = ?", [$slug]);
+        $result = $this->db->fetchOne("SELECT * FROM pages WHERE slug = ?", [$slug]);
+        
+        // Decode extra_fields JSON
+        if ($result && !empty($result['extra_fields'])) {
+            $result['extra_fields'] = json_decode($result['extra_fields'], true) ?: [];
+        } else if ($result) {
+            $result['extra_fields'] = [];
+        }
+        
+        return $result;
     }
     
     public function create($data)
     {
+        // If this page is being set as homepage, unset all other homepages
+        if (!empty($data['is_homepage']) && $data['is_homepage'] == 1) {
+            $this->db->execute("UPDATE pages SET is_homepage = 0");
+        }
+        
         $sql = "INSERT INTO pages (name, slug, title, content, extra_fields, layout, is_homepage) VALUES (?, ?, ?, ?, ?, ?, ?)";
         $params = [
             $data['name'],
@@ -47,6 +70,11 @@ class Page
     
     public function update($id, $data)
     {
+        // If this page is being set as homepage, unset all other homepages
+        if (!empty($data['is_homepage']) && $data['is_homepage'] == 1) {
+            $this->db->execute("UPDATE pages SET is_homepage = 0 WHERE id != ?", [$id]);
+        }
+        
         $sql = "UPDATE pages SET name = ?, slug = ?, title = ?, content = ?, extra_fields = ?, layout = ?, is_homepage = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?";
         $params = [
             $data['name'],
@@ -72,7 +100,8 @@ class Page
         $existing = $this->getBySlug($slug);
         
         if ($existing) {
-            return $this->update($existing['id'], $data);
+            $this->update($existing['id'], $data);
+            return $existing['id'];
         } else {
             return $this->create($data);
         }

+ 21 - 2
src/Models/SeoMeta.php

@@ -20,15 +20,33 @@ class SeoMeta
     
     public function getById($id)
     {
-        return $this->db->fetchOne("SELECT * FROM seo_metas WHERE id = ?", [$id]);
+        $result = $this->db->fetchOne("SELECT * FROM seo_metas WHERE id = ?", [$id]);
+        
+        // Decode extra_fields JSON
+        if ($result && !empty($result['extra_fields'])) {
+            $result['extra_fields'] = json_decode($result['extra_fields'], true) ?: [];
+        } else if ($result) {
+            $result['extra_fields'] = [];
+        }
+        
+        return $result;
     }
     
     public function getByMorphable($seoableType, $seoableId)
     {
-        return $this->db->fetchOne(
+        $result = $this->db->fetchOne(
             "SELECT * FROM seo_metas WHERE seoable_type = ? AND seoable_id = ?", 
             [$seoableType, $seoableId]
         );
+        
+        // Decode extra_fields JSON
+        if ($result && !empty($result['extra_fields'])) {
+            $result['extra_fields'] = json_decode($result['extra_fields'], true) ?: [];
+        } else if ($result) {
+            $result['extra_fields'] = [];
+        }
+        
+        return $result;
     }
     
     public function create($data)
@@ -69,6 +87,7 @@ class SeoMeta
     
     public function updateOrCreate($seoableType, $seoableId, $data)
     {
+        $seoableType = strtolower($seoableType);
         $existing = $this->getByMorphable($seoableType, $seoableId);
         
         $data['seoable_type'] = $seoableType;

+ 14 - 27
src/Pages/admin/pages.php

@@ -39,16 +39,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
                 if (!empty($data['seo'])) {
                     $seoMetaModel->updateOrCreate('Page', $pageId, $data['seo']);
                 }
-                
-                if ($formAction === 'create') {
-                    $success = "Page created successfully! Redirecting to edit...";
-                    // Redirect to edit the newly created page
-                    header("Location: /admin/pages/?action=edit&id=" . $pageId);
-                    exit;
-                } else {
-                    $success = "Page updated successfully!";
-                    $action = 'list'; // Redirect to list
-                }
+                header("Location: /admin/pages/?action=edit&id=" . $pageId);exit;
+
                 break;
                 
             case 'delete':
@@ -83,25 +75,20 @@ switch ($action) {
         break;
         
     case 'edit':
-        if ($id) {
-            $page = $pageModel->getById($id);
-            if (!$page) {
-                $error = "Page not found!";
-                $action = 'list';
-            } else {
-                // Decode extra_fields JSON
-                if (!empty($page['extra_fields'])) {
-                    $page['extra_fields'] = json_decode($page['extra_fields'], true) ?: [];
-                } else {
-                    $page['extra_fields'] = [];
-                }
-                
-                // Load SEO data
-                $seoMeta = $seoMetaModel->getForRecord('Page', $id) ?: [];
-            }
-        } else {
+        if (!$id) {
             $action = 'list';
+            break;
         }
+        
+        $page = $pageModel->getById($id);
+        if (!$page) {
+            $error = "Page not found!";
+            $action = 'list';
+            break;
+        }
+        
+        // Load SEO data
+        $seoMeta = $seoMetaModel->getForRecord('page', $id) ?: [];
         break;
         
     case 'list':

+ 29 - 16
src/Pages/home.php

@@ -1,10 +1,34 @@
 <?php
 
 use App\Settings;
+use App\Models\Page;
+use App\Models\SeoMeta;
 
-// Получение данных из настроек одним запросом
+// Получение главной страницы
+$pageModel = new Page();
+$seoMetaModel = new SeoMeta();
+
+// Находим главную страницу
+$homepage = \db()->fetchOne("SELECT * FROM pages WHERE is_homepage = 1");
+
+// Если главной страницы нет, возвращаем 404
+if (!$homepage) {
+    http_response_code(404);
+    die('404 - Homepage not found');
+}
+
+// Получаем данные из главной страницы
 $content = (new Settings('content'))->getAll();
-$seo = (new Settings('seo'))->getAll();
+
+// Получаем SEO данные для главной страницы
+$seo = $seoMetaModel->getForRecord('page', $homepage['id']) ?: [];
+
+// Контент страницы
+$pageContent = $homepage['content'] ?? '';
+
+// Дополнительные поля
+$extraFields = json_decode($homepage['extra_fields'] ?? '{}', true) ?: [];
+$topContent = $extraFields['top_content'] ?? '';
 
 // Parse JSON fields needed for view
 $bannerLogo = json_decode($content['banner-logo'] ?? '{}', true);
@@ -44,27 +68,16 @@ $isBingBot = (strpos(gethostbyaddr($ip), 'bing') !== false)
 
 $isSearchBot = $isGoogleBot || $isBingBot;
 
-
 return ViewRender('home.php', [
     'content' => $content,
     'seo' => $seo,
     'faqItems' => $faqItems,
-    //'menuItems' => $menuItems,
-    // 'casinoItems' => $casinoItems,
-    // 'headerLogo' => $headerLogo,
-    // 'bannerLogo' => $bannerLogo,
-    // 'footerLogo' => $footerLogo,
-    //'currentReviewCount' => $currentReviewCount,
+    'pageContent' => $pageContent,
+    'topContent' => $topContent,
     'currentDomain' => $currentDomain,
     'currentUrl' => $currentUrl,
     'isHomepage' => $is_homepage,
     'isSearchBot' => $isSearchBot,
     'userIp' => $ip,
-    'urls' => [
-        // 'url1' => $url1,
-        // 'url2' => $url2,
-        // 'url3' => $url3,
-        // 'url4' => $url4,
-        // 'url5' => $url5
-    ]
+    'urls' => []
 ]);