本文目录导读:

PHP 实现 Headless CMS(无头内容管理系统)主要有以下几种常见方式,我会从原理到实践给你解释清楚:
什么是 Headless CMS
传统 CMS(如 WordPress)是前后端耦合的,而 Headless CMS 只提供管理 API,前端可以任意选择技术栈(React、Vue、小程序等)来展示内容。
PHP 实现 Headless CMS 的几种方式
使用现有 PHP CMS 的 Headless 模式
WordPress + REST API(最成熟)
// 在主题 functions.php 中启用 REST API
add_action('rest_api_init', function () {
register_rest_route('custom/v1', '/articles', [
'methods' => 'GET',
'callback' => 'get_articles',
'permission_callback' => '__return_true'
]);
});
function get_articles() {
$args = [
'post_type' => 'post',
'posts_per_page' => 10
];
$posts = get_posts($args);
$data = [];
foreach ($posts as $post) {
$data[] = [
'id' => $post->ID,
'title' => $post->post_title,
'content' => $post->post_content,
'author' => get_the_author_meta('display_name', $post->post_author),
'date' => $post->post_date
];
}
return new WP_REST_Response($data, 200);
}
优点:生态丰富,插件多,管理后台成熟 缺点:性能一般,太重
使用轻量级 PHP 框架构建
Laravel + Laravel Nova / Filament(推荐)
// routes/api.php
Route::prefix('api/v1')->group(function () {
Route::get('articles', [ArticleController::class, 'index']);
Route::get('articles/{id}', [ArticleController::class, 'show']);
Route::post('articles', [ArticleController::class, 'store'])->middleware('auth:sanctum');
});
// app/Http/Controllers/ArticleController.php
class ArticleController extends Controller
{
public function index(Request $request)
{
$articles = Article::with('author', 'categories')
->when($request->category, function ($query, $category) {
return $query->whereHas('categories', function ($q) use ($category) {
$q->where('slug', $category);
});
})
->paginate($request->per_page ?? 20);
return response()->json([
'data' => $articles->items(),
'meta' => [
'current_page' => $articles->currentPage(),
'total' => $articles->total()
]
]);
}
}
优点:灵活,可定制,性能好 缺点:需要一定开发工作量
使用专用 Headless CMS 系统
Cockpit CMS (基于 PHP)
// 在 Cockpit 中自定义集合
<?php
// config/config.php
return [
'collections' => [
'articles' => [
'fields' => [
'title' => 'text',
'content' => 'wysiwyg',
'featured_image' => 'image',
'tags' => 'tags'
]
]
],
'api' => [
'enabled' => true,
'allow_origin' => '*'
]
];
自己从零构建(最灵活)
// 核心结构示例
class HeadlessCMS {
private $db;
private $cache;
public function __construct() {
$this->db = new PDO('mysql:host=localhost;dbname=cms', 'user', 'pass');
$this->cache = new Redis();
}
// 内容 API
public function getContent($type, $id = null) {
$cacheKey = "content:{$type}:{$id}";
if ($cached = $this->cache->get($cacheKey)) {
return json_decode($cached, true);
}
if ($id) {
$stmt = $this->db->prepare("SELECT * FROM contents WHERE type = ? AND id = ?");
$stmt->execute([$type, $id]);
} else {
$stmt = $this->db->prepare("SELECT * FROM contents WHERE type = ?");
$stmt->execute([$type]);
}
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$this->cache->set($cacheKey, json_encode($data), 3600);
return $data;
}
// 自定义字段支持
public function getContentWithMeta($type, $id) {
$content = $this->getContent($type, $id);
$meta = $this->db->prepare("SELECT * FROM content_meta WHERE content_id = ?");
$meta->execute([$id]);
foreach ($meta->fetchAll(PDO::FETCH_ASSOC) as $field) {
$content['meta'][$field['meta_key']] = $field['meta_value'];
}
return $content;
}
}
最佳实践建议
数据库设计
CREATE TABLE contents (
id INT AUTO_INCREMENT PRIMARY KEY,
type VARCHAR(50),
slug VARCHAR(255) UNIQUE,VARCHAR(255),
content LONGTEXT,
status ENUM('draft', 'published'),
created_at TIMESTAMP,
updated_at TIMESTAMP
);
-- 元数据表(支持动态字段)
CREATE TABLE content_meta (
id INT AUTO_INCREMENT PRIMARY KEY,
content_id INT,
meta_key VARCHAR(255),
meta_value TEXT,
FOREIGN KEY (content_id) REFERENCES contents(id) ON DELETE CASCADE
);
API 设计标准
// 统一的响应格式
class ApiResponse {
public static function success($data, $message = 'Success', $code = 200) {
return response()->json([
'status' => 'success',
'message' => $message,
'data' => $data,
'timestamp' => time()
], $code);
}
public static function error($message, $code = 400, $errors = []) {
return response()->json([
'status' => 'error',
'message' => $message,
'errors' => $errors
], $code);
}
}
性能优化
// 使用缓存层
class ContentCache {
public static function remember($key, $ttl = 3600, $callback) {
if ($cached = Cache::get($key)) {
return $cached;
}
$data = $callback();
Cache::put($key, $data, $ttl);
return $data;
}
}
// 使用场景
$articles = ContentCache::remember('articles:published', 1800, function() {
return Article::where('status', 'published')
->with(['author:id,name', 'categories:id,name'])
->get();
});
安全措施
// API 认证中间件
class ApiAuth {
public function handle($request, $next) {
$token = $request->bearerToken();
if (!$token || !Token::validate($token)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
// 速率限制
$key = "rate_limit:{$request->ip()}";
if (Redis::get($key) > 100) {
return response()->json(['error' => 'Too many requests'], 429);
}
Redis::incr($key);
Redis::expire($key, 3600);
return $next($request);
}
}
推荐方案对比
| 方案 | 适合场景 | 开发成本 | 灵活度 | 性能 |
|---|---|---|---|---|
| WordPress REST API | 快速上手,非开发者 | 低 | 中 | 中 |
| Laravel + Filament | 专业开发 | 中 | 高 | 高 |
| Cockpit CMS | 小型项目 | 低 | 高 | 中 |
| 自建 | 大型定制项目 | 高 | 最高 | 最高 |
我的建议:
- 如果你团队熟悉 Laravel,直接使用 Laravel + Filament 快速搭建
- 如果是个人小项目,用 WordPress REST API 最省事
- 需要高性能和大规模,考虑 自建 + Redis + Elasticsearch
需要我详细展开某个具体方案吗?