diff --git a/app/Controllers/AdminController.php b/app/Controllers/AdminController.php index d21b5ba..8619d3e 100644 --- a/app/Controllers/AdminController.php +++ b/app/Controllers/AdminController.php @@ -108,7 +108,7 @@ class AdminController extends Controller { $status = $_POST['status'] ?? 'published'; $is_vip = isset($_POST['is_vip']) ? 1 : 0; - $icon_path = $this->handleUpload('icon_file', true); + $icon_path = $this->handleUpload('icon_file', 'icons'); $db = db_pdo(); $stmt = $db->prepare("INSERT INTO apks (title, slug, description, version, image_url, icon_path, download_url, category_id, status, is_vip, display_order) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)"); @@ -142,7 +142,7 @@ class AdminController extends Controller { $download_url = $download_urls[$index] ?? ''; $description = $title; // Default description to title for mass upload - $icon_path = $this->handleMassUploadFile('icon_files', $index, true); + $icon_path = $this->handleMassUploadFile('icon_files', $index, 'icons'); $stmt->execute([$title, $slug, $description, $version, $icon_path, $download_url, $category_id, $status]); } @@ -150,12 +150,12 @@ class AdminController extends Controller { $this->redirect('/admin/apks'); } - private function handleMassUploadFile($field, $index, $compress = false) { + private function handleMassUploadFile($field, $index, $dir = 'icons') { if (!isset($_FILES[$field]['name'][$index]) || $_FILES[$field]['error'][$index] !== UPLOAD_ERR_OK) { return null; } - $uploadDir = 'assets/uploads/icons/'; + $uploadDir = 'assets/uploads/' . $dir . '/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0775, true); } @@ -164,14 +164,8 @@ class AdminController extends Controller { $fileName = uniqid() . '.' . $ext; $targetPath = $uploadDir . $fileName; - if ($compress) { - if (compress_image($_FILES[$field]['tmp_name'][$index], $targetPath, 75)) { - return $targetPath; - } - } else { - if (move_uploaded_file($_FILES[$field]['tmp_name'][$index], $targetPath)) { - return $targetPath; - } + if (compress_image($_FILES[$field]['tmp_name'][$index], $targetPath, 75)) { + return $targetPath; } return null; @@ -199,7 +193,7 @@ class AdminController extends Controller { $db = db_pdo(); $apk = $db->query("SELECT * FROM apks WHERE id = " . $params['id'])->fetch(); - $icon_path = $this->handleUpload('icon_file', true) ?: $apk['icon_path']; + $icon_path = $this->handleUpload('icon_file', 'icons') ?: $apk['icon_path']; $stmt = $db->prepare("UPDATE apks SET title = ?, description = ?, version = ?, image_url = ?, icon_path = ?, download_url = ?, category_id = ?, status = ?, is_vip = ? WHERE id = ?"); $stmt->execute([$title, $description, $version, $image_url, $icon_path, $download_url, $category_id, $status, $is_vip, $params['id']]); @@ -219,12 +213,12 @@ class AdminController extends Controller { echo json_encode(['success' => true]); } - private function handleUpload($field, $compress = false) { + private function handleUpload($field, $dir = 'icons') { if (!isset($_FILES[$field]) || $_FILES[$field]['error'] !== UPLOAD_ERR_OK) { return null; } - $uploadDir = 'assets/uploads/icons/'; + $uploadDir = 'assets/uploads/' . $dir . '/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0775, true); } @@ -233,14 +227,8 @@ class AdminController extends Controller { $fileName = uniqid() . '.' . $ext; $targetPath = $uploadDir . $fileName; - if ($compress) { - if (compress_image($_FILES[$field]['tmp_name'], $targetPath, 75)) { - return $targetPath; - } - } else { - if (move_uploaded_file($_FILES[$field]['tmp_name'], $targetPath)) { - return $targetPath; - } + if (compress_image($_FILES[$field]['tmp_name'], $targetPath, 75)) { + return $targetPath; } return null; @@ -257,6 +245,10 @@ class AdminController extends Controller { 'meta_keywords' => get_setting('meta_keywords'), 'head_js' => get_setting('head_js'), 'body_js' => get_setting('body_js'), + 'facebook_url' => get_setting('facebook_url'), + 'twitter_url' => get_setting('twitter_url'), + 'instagram_url' => get_setting('instagram_url'), + 'github_url' => get_setting('github_url'), ]; $this->view('admin/settings', ['settings' => $settings]); } @@ -265,7 +257,10 @@ class AdminController extends Controller { $this->checkAuth(); $db = db_pdo(); - $fields = ['site_name', 'meta_description', 'meta_keywords', 'head_js', 'body_js']; + $fields = [ + 'site_name', 'meta_description', 'meta_keywords', 'head_js', 'body_js', + 'facebook_url', 'twitter_url', 'instagram_url', 'github_url' + ]; foreach ($fields as $field) { if (isset($_POST[$field])) { $stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = ?"); @@ -273,13 +268,13 @@ class AdminController extends Controller { } } - $site_icon = $this->handleUpload('site_icon_file'); + $site_icon = $this->handleUpload('site_icon_file', 'settings'); if ($site_icon) { $stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'site_icon'"); $stmt->execute([$site_icon]); } - $site_favicon = $this->handleUpload('site_favicon_file'); + $site_favicon = $this->handleUpload('site_favicon_file', 'settings'); if ($site_favicon) { $stmt = $db->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'site_favicon'"); $stmt->execute([$site_favicon]); @@ -288,6 +283,66 @@ class AdminController extends Controller { $this->redirect('/admin/settings'); } + // Blog Management + public function posts() { + $this->checkAuth(); + $db = db_pdo(); + $posts = $db->query("SELECT * FROM posts ORDER BY created_at DESC")->fetchAll(); + $this->view('admin/posts/index', ['posts' => $posts]); + } + + public function addPostForm() { + $this->checkAuth(); + $this->view('admin/posts/form', ['action' => 'add']); + } + + public function addPost() { + $this->checkAuth(); + $title = $_POST['title']; + $slug = $this->slugify($title); + $content = $_POST['content']; + $status = $_POST['status'] ?? 'published'; + + $image_path = $this->handleUpload('image_file', 'blog'); + + $db = db_pdo(); + $stmt = $db->prepare("INSERT INTO posts (title, slug, content, image_path, status) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$title, $slug, $content, $image_path, $status]); + + $this->redirect('/admin/posts'); + } + + public function editPostForm($params) { + $this->checkAuth(); + $db = db_pdo(); + $post = $db->query("SELECT * FROM posts WHERE id = " . $params['id'])->fetch(); + $this->view('admin/posts/form', ['action' => 'edit', 'post' => $post]); + } + + public function editPost($params) { + $this->checkAuth(); + $title = $_POST['title']; + $content = $_POST['content']; + $status = $_POST['status']; + + $db = db_pdo(); + $post = $db->query("SELECT * FROM posts WHERE id = " . $params['id'])->fetch(); + $image_path = $this->handleUpload('image_file', 'blog') ?: $post['image_path']; + + $stmt = $db->prepare("UPDATE posts SET title = ?, content = ?, image_path = ?, status = ? WHERE id = ?"); + $stmt->execute([$title, $content, $image_path, $status, $params['id']]); + + $this->redirect('/admin/posts'); + } + + public function deletePost($params) { + $this->checkAuth(); + $db = db_pdo(); + $stmt = $db->prepare("DELETE FROM posts WHERE id = ?"); + $stmt->execute([$params['id']]); + $this->redirect('/admin/posts'); + } + // Category Management public function categories() { $this->checkAuth(); @@ -361,4 +416,4 @@ class AdminController extends Controller { $text = strtolower($text); return empty($text) ? 'n-a' : $text; } -} +} \ No newline at end of file diff --git a/app/Controllers/BlogController.php b/app/Controllers/BlogController.php new file mode 100644 index 0000000..2e47ed0 --- /dev/null +++ b/app/Controllers/BlogController.php @@ -0,0 +1,29 @@ +query("SELECT * FROM posts WHERE status = 'published' ORDER BY created_at DESC")->fetchAll(); + $this->view('blog/index', ['posts' => $posts]); + } + + public function detail($params) { + $slug = $params['slug']; + $db = db_pdo(); + $stmt = $db->prepare("SELECT * FROM posts WHERE slug = ? AND status = 'published'"); + $stmt->execute([$slug]); + $post = $stmt->fetch(); + + if (!$post) { + $this->view('404'); + return; + } + + $this->view('blog/detail', ['post' => $post]); + } +} diff --git a/db/migrations/20260225_add_blog_and_social_settings.sql b/db/migrations/20260225_add_blog_and_social_settings.sql new file mode 100644 index 0000000..44a4214 --- /dev/null +++ b/db/migrations/20260225_add_blog_and_social_settings.sql @@ -0,0 +1,18 @@ +-- Create posts table for Blog +CREATE TABLE IF NOT EXISTS `posts` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `title` VARCHAR(255) NOT NULL, + `slug` VARCHAR(255) NOT NULL UNIQUE, + `content` TEXT NOT NULL, + `image_path` VARCHAR(255) DEFAULT NULL, + `status` ENUM('published', 'draft') DEFAULT 'published', + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Add Social Media Settings +INSERT IGNORE INTO `settings` (`setting_key`, `setting_value`) VALUES +('facebook_url', ''), +('twitter_url', ''), +('instagram_url', ''), +('github_url', ''); diff --git a/index.php b/index.php index 56a200d..661259a 100644 --- a/index.php +++ b/index.php @@ -46,6 +46,10 @@ $router->get('/', 'HomeController@index'); $router->get('/apk/:slug', 'HomeController@apkDetail'); $router->get('/download/:slug', 'HomeController@download'); +// Blog +$router->get('/blog', 'BlogController@index'); +$router->get('/blog/:slug', 'BlogController@detail'); + // Static Pages $router->get('/help-center', 'HomeController@helpCenter'); $router->get('/privacy-policy', 'HomeController@privacyPolicy'); @@ -87,6 +91,14 @@ $router->post('/admin/apks/edit/:id', 'AdminController@editApk'); $router->get('/admin/apks/delete/:id', 'AdminController@deleteApk'); $router->post('/admin/apks/reorder', 'AdminController@updateOrder'); +// Admin Posts (Blog) +$router->get('/admin/posts', 'AdminController@posts'); +$router->get('/admin/posts/add', 'AdminController@addPostForm'); +$router->post('/admin/posts/add', 'AdminController@addPost'); +$router->get('/admin/posts/edit/:id', 'AdminController@editPostForm'); +$router->post('/admin/posts/edit/:id', 'AdminController@editPost'); +$router->get('/admin/posts/delete/:id', 'AdminController@deletePost'); + // Admin Categories $router->get('/admin/categories', 'AdminController@categories'); $router->post('/admin/categories/add', 'AdminController@addCategory'); @@ -97,4 +109,4 @@ $router->get('/admin/withdrawals', 'AdminController@withdrawals'); $router->get('/admin/withdrawals/approve/:id', 'AdminController@approveWithdrawal'); $router->get('/admin/withdrawals/reject/:id', 'AdminController@rejectWithdrawal'); -$router->dispatch(); +$router->dispatch(); \ No newline at end of file diff --git a/views/admin/header.php b/views/admin/header.php index 14696b4..a530bf6 100644 --- a/views/admin/header.php +++ b/views/admin/header.php @@ -191,6 +191,9 @@ + @@ -250,4 +253,5 @@ - \ No newline at end of file + +
diff --git a/views/admin/posts/form.php b/views/admin/posts/form.php new file mode 100644 index 0000000..fa6efc3 --- /dev/null +++ b/views/admin/posts/form.php @@ -0,0 +1,52 @@ + + +
+ + +
+
+
+
+ + +
+ +
+ + + +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+
+ + diff --git a/views/admin/posts/index.php b/views/admin/posts/index.php new file mode 100644 index 0000000..034f994 --- /dev/null +++ b/views/admin/posts/index.php @@ -0,0 +1,68 @@ + + +
+
+

Blog Posts

+ + Add New Post + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
ImageTitleStatusDateActions
+ + + +
+ +
+ +
+
+ +
+ + + + + + + + + + +
No posts found.
+
+
+
+
+ + diff --git a/views/admin/settings.php b/views/admin/settings.php index 0111e09..dff21d9 100644 --- a/views/admin/settings.php +++ b/views/admin/settings.php @@ -35,6 +35,31 @@ +
+
Social Media Settings
+ +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+
SEO Settings
@@ -93,4 +118,4 @@ - \ No newline at end of file + diff --git a/views/blog/detail.php b/views/blog/detail.php new file mode 100644 index 0000000..da1d4e2 --- /dev/null +++ b/views/blog/detail.php @@ -0,0 +1,67 @@ + + +
+ +
+ + + + diff --git a/views/blog/index.php b/views/blog/index.php new file mode 100644 index 0000000..af548ad --- /dev/null +++ b/views/blog/index.php @@ -0,0 +1,56 @@ + + +
+
+
+
+

Blog & Articles

+

Dapatkan informasi terbaru seputar aplikasi, game, dan tips teknologi di sini.

+
+
+ +
+ +
+
+ + <?php echo htmlspecialchars($post['title']); ?> + +
+ +
+ +
+
+ +
+

+ + + +

+

+ +

+
+
+
+ + + +
+
+ +
+

Belum ada artikel yang diterbitkan.

+ Kembali ke Beranda +
+ +
+
+
+ + diff --git a/views/footer.php b/views/footer.php index cd370d2..04a57fb 100644 --- a/views/footer.php +++ b/views/footer.php @@ -26,6 +26,7 @@
- - - - + + + + + + + + + + + +
@@ -60,4 +69,4 @@ - \ No newline at end of file + diff --git a/views/header.php b/views/header.php index 409a113..5987653 100644 --- a/views/header.php +++ b/views/header.php @@ -98,6 +98,10 @@ $currentLang = \App\Services\LanguageService::getLang(); + +