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 @@
Mass Upload
+
+ Blog
+
@@ -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
+
+
+
+
+
+
+
+
+
+ | Image |
+ Title |
+ Status |
+ Date |
+ Actions |
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+ | 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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
![<?php echo htmlspecialchars($post['title']); ?>](/<?php echo $post['image_path']; ?>)
+
+
+
+
+
+
+
+
+
+
+
Share this article:
+
+
+
+
+
+
+
+
+
+
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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+ - Blog
@@ -47,10 +48,18 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -60,4 +69,4 @@