😍 Dự án Laravel bán hàng martfury dùng Botble quá đỉnh (ok)
<?php
use Botble\Blog\Models\Category;
use Botble\Blog\Models\Post;
use Botble\Page\Models\Page;
use Botble\Slug\Facades\SlugHelper;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Botble\Slug\Models\Slug;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Botble\Contact\Models\Contact;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/
Route::get('/pages', function (Request $request) {
$posts = Page::where('status', 'published')
->orderBy('created_at', 'desc')
->select('id', 'name', 'created_at') // tuỳ chọn field
->paginate(10); // hoặc ->get() nếu không phân trang
return response()->json([
'data' => $posts,
]);
});
Route::get('/posts', function (Request $request) {
// Lấy ID chuyên mục 'human' từ bảng slugs
$excludedCategoryId = Slug::where('key', 'human')
->where('reference_type', Category::class)
->value('reference_id');
// Nếu không có chuyên mục "human", trả về bài viết bình thường
if (!$excludedCategoryId) {
$posts = Post::where('status', 'published')
->orderBy('created_at', 'desc')
->select('id', 'name', 'description', 'content', 'is_featured', 'image', 'created_at')
->paginate(10);
$posts->getCollection()->transform(function ($post) {
$slug = DB::table('slugs')
->where('reference_type', Post::class)
->where('reference_id', $post->id)
->value('key');
$post->slug = $slug;
return $post;
});
return response()->json(['data' => $posts]);
}
// Lấy danh sách post_id thuộc chuyên mục human
$excludedPostIds = DB::table('post_categories')
->where('category_id', $excludedCategoryId)
->pluck('post_id');
// Lấy các bài viết KHÔNG thuộc chuyên mục đó
$posts = Post::where('status', 'published')
->whereNotIn('id', $excludedPostIds)
->orderBy('created_at', 'desc')
->select('id', 'name', 'description', 'content', 'is_featured', 'image', 'created_at')
->paginate(10);
// Gắn slug cho bài viết
$posts->getCollection()->transform(function ($post) {
$slug = DB::table('slugs')
->where('reference_type', Post::class)
->where('reference_id', $post->id)
->value('key');
$post->slug = $slug;
return $post;
});
return response()->json(['data' => $posts]);
});
Route::get('/pages/{slug}', function ($slug) {
// Tìm slug từ bảng `slugs`
$slugRecord = Slug::where('key', $slug)
->where('reference_type', Page::class)
->first();
if (! $slugRecord) {
return response()->json(['message' => 'Page not found'], 404);
}
// Tìm page từ reference_id
$page = Page::where('id', $slugRecord->reference_id)
->where('status', 'published')
->first();
if (! $page) {
return response()->json(['message' => 'Page not found'], 404);
}
return response()->json([
'data' => [
'id' => $page->id,
'name' => $page->name,
'description' => $page->description,
'slug' => $slug,
'content' => $page->content,
'custom_fields' => get_custom_field($page),
]
]);
});
Route::get('/posts/{slug}/related', function ($slug) {
$slugRecord = Slug::where('key', $slug)
->where('reference_type', Post::class)
->first();
if (! $slugRecord) {
return response()->json(['message' => 'Post not found'], 404);
}
// Lấy bài viết hiện tại và chuyên mục của nó
$post = Post::with('categories')
->where('id', $slugRecord->reference_id)
->where('status', 'published')
->first();
if (! $post) {
return response()->json(['message' => 'Post not found'], 404);
}
// Lấy các ID chuyên mục của bài viết
$categoryIds = $post->categories->pluck('id');
// Tìm bài viết liên quan (cùng chuyên mục, không trùng chính nó)
$relatedPosts = Post::where('status', 'published')
->where('id', '!=', $post->id)
->whereHas('categories', function ($query) use ($categoryIds) {
$query->whereIn('categories.id', $categoryIds);
})
->orderBy('created_at', 'desc')
->take(6)
// ->select('id', 'name', 'slug', 'description', 'image', 'created_at')
->get();
$relatedPosts->transform(function ($post) {
$slug = DB::table('slugs')
->where('reference_type', Post::class)
->where('reference_id', $post->id)
->value('key');
$post->slug = $slug;
return $post;
});
return response()->json([
'data' => $relatedPosts,
]);
});
Route::get('/posts/{slug}', function ($slug) {
// Tìm slug từ bảng `slugs`
$slugRecord = Slug::where('key', $slug)
->where('reference_type', Post::class)
->first();
if (! $slugRecord) {
return response()->json(['message' => 'Page not found'], 404);
}
// Tìm page từ reference_id
$post = Post::where('id', $slugRecord->reference_id)
->where('status', 'published')
->first();
if (! $post) {
return response()->json(['message' => 'Page not found'], 404);
}
return response()->json([
'data' => [
'id' => $post->id,
'name' => $post->name,
'slug' => $slug,
'description' => $post->description,
'is_featured' => $post->is_featured,
'image' => $post->image,
'created_at' => $post->created_at,
'content' => $post->content,
'categories' => $post->categories->map(function ($category) {
return [
'id' => $category->id,
'name' => $category->name,
'slug' => $category->slug,
];
}),
]
]);
});
Route::get('/categories/{slug}/posts', function ($slug, Request $request) {
// Tìm chuyên mục theo slug
$category = DB::table('slugs')
->where('key', $slug)
->where('reference_type', Category::class)
->first();
$slugRecord = DB::table('slugs')
->where('key', $slug)
->where('reference_type', Category::class)
->first();
$categorys = Category::select('name', 'description')
->where('id', $slugRecord->reference_id)
->first();
// Lấy bài viết thuộc category
$categoryId = $category->reference_id;
$posts = Post::where('status', 'published')
->whereHas('categories', function ($query) use ($categoryId) {
$query->where('categories.id', $categoryId);
})
->orderBy('created_at', 'desc')
->select('id', 'name', 'description', 'content', 'is_featured', 'image', 'created_at')
->paginate(10);
// Map slug cho từng bài viết
$posts->getCollection()->transform(function ($post) {
$slug = DB::table('slugs')
->where('reference_type', Post::class)
->where('reference_id', $post->id)
->value('key');
$post->slug = $slug;
if (!$post->custom_fields) {
$post->custom_fields = get_custom_field($post);
}
return $post;
});
return response()->json([
'data' => $posts,
'category' => $categorys
]);
});
// Route::post('/contactforconsultation', function (\Illuminate\Http\Request $request) {
// \Botble\Contact\Models\Contact::create([
// 'name' => $request->input('yourName') ?? $request->input('position'),
// 'email' => $request->input('email'),
// 'phone' => $request->input('phone'),
// 'content' => $request->input('content') ?? $request->input('position'),
// 'address' => $request->input('address') ?? $request->input('cvfilename'),
// 'subject' => $request->input('subject') ?? $request->input('taxcode')
// ]);
// return response()->json(['message' => 'Gửi thành công.']);
// });
Route::post('/contactforconsultation', function (Request $request) {
// Validate the request data (highly recommended)
$request->validate([
'yourName' => 'nullable|string|max:255',
'email' => 'required|email|max:255',
'phone' => 'required|string|max:20',
'content' => 'nullable|string',
'taxcode' => 'nullable|string|max:50',
'companyProfile' => 'nullable|file|mimes:pdf,ppt,pptx,doc,docx,zip|max:5120', // Max 5MB (5120 KB)
'cvfilename' => 'nullable|string|max:255', // Để lấy tên file từ frontend
]);
$companyProfilePath = null;
if ($request->hasFile('companyProfile')) {
$file = $request->file('companyProfile');
// Lưu file vào thư mục 'public/company_profiles'
// 'public' là một disk mặc định trong Laravel, mapping tới storage/app/public
// Đảm bảo bạn đã chạy `php artisan storage:link` để tạo symlink public/storage
$companyProfilePath = $file->store('company_profiles', 'public');
// $companyProfilePath sẽ chứa đường dẫn tương đối từ thư mục lưu trữ, ví dụ: 'company_profiles/abcxyz.pdf'
}
Contact::create([
'name' => $request->input('yourName') ?? $request->input('companyName'), // Thêm companyName nếu bạn gửi từ frontend
'email' => $request->input('email'),
'phone' => $request->input('phone'),
'content' => $request->input('content'), // Giữ nguyên 'content' từ frontend
// Lưu đường dẫn file vào trường 'address' hoặc tạo một cột mới nếu muốn rõ ràng hơn
'address' => $companyProfilePath ? Storage::url($companyProfilePath) : null, // Lưu URL công khai
'subject' => $request->input('subject') ?? $request->input('taxcode')
]);
return response()->json(['message' => 'Gửi thành công.']);
});
Route::post('/humanresource', function (Request $request) {
// Validate the request data (highly recommended)
$request->validate([
'yourName' => 'required|string|max:255', // Đổi nullable thành required
'email' => 'required|email|max:255',
'phone' => 'required|string|max:20',
'subject' => 'nullable|string|max:255', // Từ form: "Ứng tuyển vị trí: ..."
'taxcode' => 'nullable|string|max:50', // Từ form: "Ứng tuyển"
'position' => 'required|string|max:255', // Thêm trường position
'companyProfile' => 'required|file|mimes:pdf,doc,docx,zip|max:5120', // Đổi nullable thành required, mimes chuẩn hơn
'cvfilename' => 'nullable|string|max:255', // Tên file gốc từ frontend
]);
$companyProfilePath = null;
$publicFilePath = null; // Để lưu URL công khai
if ($request->hasFile('companyProfile')) {
$file = $request->file('companyProfile');
// Lưu file vào thư mục 'public/cv_applications' (thay đổi thư mục cho rõ ràng hơn)
$companyProfilePath = $file->store('cv_applications', 'public');
$publicFilePath = Storage::url($companyProfilePath); // Lấy URL công khai
}
// Tạo nội dung cho trường 'content' để dễ đọc trong Botble
$content = "Họ và tên: " . $request->input('yourName') . "\n" .
"Số điện thoại: " . $request->input('phone') . "\n" .
"Email: " . $request->input('email') . "\n" .
"Vị trí ứng tuyển: " . $request->input('position') . "\n";
if ($publicFilePath) {
$content .= "Link CV: " . $publicFilePath . "\n";
}
Contact::create([
'name' => $request->input('yourName'),
'email' => $request->input('email'),
'phone' => $request->input('phone'),
'content' => $content, // Sử dụng content đã tạo
'address' => $publicFilePath, // Lưu trực tiếp URL của CV vào trường address
'subject' => $request->input('subject'),
// Nếu bạn muốn lưu tên file gốc vào một trường khác, bạn cần thêm cột vào DB
// 'cv_original_name' => $request->input('cvfilename'),
]);
return response()->json(['message' => 'Gửi hồ sơ ứng tuyển thành công.']);
});
Source code 1



Sử dụng plugin custom-field để thêm nội dung vào bài viết, chuyên mục, trang ...

Cách cài đặt plugin & theme



Bước 1: Để active plugin chúng ra dùng lệnh php artisan plugin:publish nó gợi ý ở dưới

Bước 2: Dùng lệnh php artisan cms:plugin:activate sau đó nó sẽ hỏi plugin cần actate


Bước 3: Sau khi cài xong nó xuất hiện trong back-end như sau.


— Cách lấy get_field
https://github.com/codezin/beeart_shopwise/tree/main
— Viêt thêm hàm get_page_by_id


— Cách Lấy get_sub_field





'get_field' is deprecated.
✅ Kiểm tra cách và bổ sung các đặc điểm đúng
Giải th
🔎 Kiểm tra n
PreviousHướng dẫn tôi chạy Chạy trong Tinker hoặc dump SQL (Full)NextTriển khai dự án Pi bằng Laravel 12
Last updated

