内容管理系统

June 24, 2026 · View on GitHub

本文档整合了以下源文件:cms.md, headless.md, flat.md, grav.md, pagekit.md, statamic.md, strapi.md, keystone.md


来源:cms.md

简介

Cockpit 是一款自托管的无头内容管理系统 (CMS),专注于结构化内容管理。与传统 CMS 平台不同,Cockpit 仅提供后端 API,允许开发者使用任何技术栈构建自定义前端。

Cockpit 轻量、灵活,专为希望完全控制内容分发而无需传统 CMS 开销的开发者设计。

为什么使用无头 CMS?

方式传统 CMS无头 CMS
前端内置模板任何框架
内容分发HTML 页面API (JSON)
灵活性有限完全控制
多平台困难容易
性能服务器渲染优化分发
开发耦合解耦

为什么选择 Cockpit?

特性CockpitStrapiContentfulSanity
费用免费免费/OSS付费免费增值
自托管
开源
轻量非常中等不适用不适用
学习曲线
API 优先

核心功能

功能描述
集合结构化内容类型
内容树层次化内容
表单表单构建器
资源媒体管理
APIRESTful 和 GraphQL
Webhooks事件通知
用户和角色访问控制
本地化多语言内容
自定义插件可扩展性

安装

Docker 部署

# 创建目录
mkdir -p /opt/cockpit/storage

# 运行 Cockpit
docker run -d \
  --name cockpit \
  -p 8080:80 \
  -v /opt/cockpit/storage:/var/www/html/storage \
  agentejo/cockpit

Docker Compose

version: '3'
services:
  cockpit:
    image: agentejo/cockpit
    container_name: cockpit
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./storage:/var/www/html/storage

手动安装

# 下载最新版本
wget https://github.com/agentejo/cockpit/releases/latest/download/cockpit.zip

# 解压到 Web 目录
unzip cockpit.zip -d /var/www/html/cockpit

# 设置权限
chmod -R 777 /var/www/html/cockpit/storage

系统要求

要求最低推荐
PHP7.4+8.0+
扩展json, gd, mbstring+curl, +zip
Web 服务器Apache/NginxNginx
存储50MB500MB

快速上手

初始设置

步骤操作
1访问 Web 界面
2创建管理员账户
3设置站点名称
4创建第一个集合
5添加内容
6通过 API 访问

仪表板概述

区域用途
集合管理内容类型
内容树层次化内容
资源媒体库
表单表单提交
账户用户管理
设置系统配置

集合

集合是 Cockpit 的核心内容类型。

字段类型

类型描述使用场景
文本单行文本标题、名称
文本区域多行文本描述
WYSIWYG富文本编辑器正文内容
布尔真/假切换发布状态
选择下拉选择分类
标签多标签关键词
图片图片上传特色图片
画廊多图片图片画廊
文件文件上传文档
日期日期选择器发布日期
时间时间选择器活动时间
颜色颜色选择器主题颜色
对象JSON 对象自定义数据
数组项目列表重复字段

创建集合

步骤操作
1导航到集合
2点击"创建集合"
3输入集合名称
4添加字段
5配置字段设置
6保存集合

集合设置

设置描述
名称集合标识符
可排序启用拖拽排序
排序字段默认排序列
在 API 中包含在 API 输出中
预览 URL内容预览链接

内容树

内容树提供层次化内容组织。

功能描述
嵌套结构父子关系
拖拽重新排序内容
多根独立层级
基于路径URL 友好路径

使用场景

使用场景示例
导航菜单主菜单、页脚菜单
页面层级关于 > 团队 > 成员
分类产品 > 电子产品 > 手机
站点地图网站结构

资源管理

支持的文件类型

类别格式
图片JPG, PNG, GIF, WebP, SVG
文档PDF, DOC, XLS
视频MP4, WebM
音频MP3, OGG
归档ZIP, RAR

图片功能

功能描述
缩略图自动生成预览
图片信息尺寸、文件大小
替代文本无障碍元数据
焦点裁剪锚点

资源组织

方式描述
文件夹目录结构
标签分类
搜索全文搜索
过滤类型、日期、大小

API

REST API 端点

端点方法描述
/api/content/get/{collection}POST获取内容项
/api/content/item/{collection}POST获取单个项
/api/content/items/{collection}POST获取多个项
/api/assetsPOST获取资源
/api/forms/submit/{form}POST提交表单

API 认证

# 获取 API 令牌
curl -X POST https://your-cockpit.com/api/auth/token \
  -H "Content-Type: application/json" \
  -d '{"user":"admin","password":"password"}'

# 使用 API 令牌
curl -H "Cockpit-Token: YOUR_API_TOKEN" \
  https://your-cockpit.com/api/content/get/articles

GraphQL API

# 查询内容
query {
  articles(limit: 10, sort: {_created: -1}) {
    title
    content
    image {
      path
    }
  }
}

过滤和排序

{
  "filter": {
    "published": true,
    "category": "news"
  },
  "sort": {
    "_created": -1
  },
  "limit": 10,
  "skip": 0
}

Webhooks

Webhook 事件

事件触发
collection.save.before保存项之前
collection.save.after保存项之后
collection.remove.before移除项之前
collection.remove.after移除项之后
assets.save.before保存资源之前
assets.save.after保存资源之后

Webhook 配置

设置描述
名称Webhook 标识符
URL回调 URL
头部自定义头部
内容类型JSON 或表单数据
触发器监听的事件

用户和角色

用户角色

角色权限
管理员完全访问
编辑内容管理
作者创建/编辑自己的内容
查看者只读访问

权限级别

级别描述
集合每集合访问
内容树每树访问
资源媒体库访问
表单表单管理
设置系统配置

本地化

多语言内容

功能描述
语言定义支持的语言
字段每语言字段值
回退默认语言回退
API按语言查询

语言配置

设置描述
默认主要语言
语言支持的语言列表
可本地化字段带翻译的字段

自定义插件

插件类型

类型描述
集合自定义字段类型
控制器API 端点
命令CLI 命令
管理仪表板组件

创建插件

步骤操作
1创建插件目录
2定义 bootstrap.php
3实现功能
4注册到 Cockpit
5测试插件

集成示例

JavaScript (Fetch)

// 从 Cockpit 获取内容
const response = await fetch('https://your-cockpit.com/api/content/get/articles', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Cockpit-Token': 'YOUR_API_TOKEN'
  },
  body: JSON.stringify({
    filter: { published: true },
    limit: 10
  })
});

const articles = await response.json();

PHP

// 从 Cockpit 获取内容
$ch = curl_init('https://your-cockpit.com/api/content/get/articles');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Cockpit-Token: YOUR_API_TOKEN'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'filter' => ['published' => true],
    'limit' => 10
]));
$response = curl_exec($ch);

Python

import requests

response = requests.post(
    'https://your-cockpit.com/api/content/get/articles',
    headers={
        'Content-Type': 'application/json',
        'Cockpit-Token': 'YOUR_API_TOKEN'
    },
    json={
        'filter': {'published': True},
        'limit': 10
    }
)

articles = response.json()

故障排除

问题原因解决方案
无法安装PHP 版本升级 PHP
API 错误令牌错误验证 API 令牌
上传失败文件权限检查存储权限
API 缓慢无缓存启用 API 缓存

更多资源

资源URL
官方网站cockpitcms.com
GitHubgithub.com/agentejo/cockpit
文档cockpitcms.com/documentation
社区cockpitcms.com/community

来源:headless.md

简介

Directus 是一个开源的无头 CMS,为任何 SQL 数据库提供实时 REST 和 GraphQL API 包装。它提供无代码管理应用来管理内容,同时让开发者完全控制数据层。本教程涵盖设置、数据建模、API 使用和自定义。

架构

组件技术用途
APINode.js (Express)REST 和 GraphQL 端点
Admin AppVue.js无代码管理 UI
数据库PostgreSQL/MySQL/SQLite/MS SQL数据存储
实时WebSocket实时更新
存储本地/S3/Azure/GCS文件管理

安装

Docker Compose

version: "3"
services:
  directus:
    image: directus/directus:latest
    ports:
      - "8055:8055"
    volumes:
      - directus_uploads:/directus/uploads
      - directus_extensions:/directus/extensions
    environment:
      KEY: "random-key-here"
      SECRET: "random-secret-here"
      DB_CLIENT: "pg"
      DB_HOST: "database"
      DB_PORT: "5432"
      DB_DATABASE: "directus"
      DB_USER: "directus"
      DB_PASSWORD: "secure_password"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin_password"
    depends_on:
      - database
  database:
    image: postgres:15
    environment:
      POSTGRES_DB: directus
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: secure_password
    volumes:
      - db_data:/var/lib/postgresql/data
volumes:
  directus_uploads:
  directus_extensions:
  db_data:

NPX

npx directus bootstrap
npx directus start

核心概念

数据模型

概念描述SQL 等价物
Collection数据实体
Field集合的属性
Item单条记录
Relation集合间的连接外键

系统集合

集合用途
directus_users用户账户
directus_roles用户角色
directus_permissions访问控制规则
directus_files上传的文件
directus_folders文件组织
directus_presets保存的筛选/视图预设
directus_activity审计日志
directus_revisions项目版本历史
directus_settings系统配置

数据建模

创建集合

  1. 导航到 Settings > Data Model。
  2. 点击"Create Collection"。
  3. 输入集合名称(例如 articles)。
  4. 配置可选字段(status、sort 等)。
  5. 保存。

字段类型

类型描述示例
Input单行文本标题、名称
Textarea多行文本描述
WYSIWYG富文本编辑器正文内容
MarkdownMarkdown 编辑器技术内容
Boolean真/假开关已发布、精选
Integer整数计数、排序
Decimal小数价格、评分
DateTime日期和时间创建日期
Date仅日期生日
Time仅时间预约时间
Dropdown单选类别、状态
Tags多标签标签、关键词
Image图片文件引用特色图片
File文件引用附件
JSON任意 JSON 数据配置
UUID自动生成 UUID外部引用
Auto Increment顺序编号订单号

创建字段

  1. 导航到集合。
  2. 点击"Create Field"。
  3. 选择字段类型。
  4. 配置名称、界面和验证。
  5. 设置关系(如适用)。
  6. 保存。

关系

类型描述示例
Many-to-One多个项目引用一个文章有一个作者
One-to-Many一个项目有多个作者有多篇文章
Many-to-Many多个项目链接多个文章有多个标签
One-to-One一个项目链接一个用户有一个个人资料

创建关系

  1. 添加类型为"Related to Collection"的新字段。
  2. 选择目标集合。
  3. 选择关系类型。
  4. 配置外键字段。
  5. 保存。

API 访问

REST API

端点方法描述
/items/{collection}GET列出项目
/items/{collection}/{id}GET获取单个项目
/items/{collection}POST创建项目
/items/{collection}/{id}PATCH更新项目
/items/{collection}/{id}DELETE删除项目

认证

# 登录
curl -X POST https://directus.example.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "password"}'

# 使用 token
curl -H "Authorization: Bearer ACCESS_TOKEN" \
  https://directus.example.com/items/articles

筛选

# 按状态筛选
GET /items/articles?filter[status][_eq]=published

# 按日期范围筛选
GET /items/articles?filter[date_published][_gte]=2024-01-01

# 多个条件
GET /items/articles?filter[status][_eq]=published&filter[author][_eq]=5

筛选操作符

操作符描述示例
_eq等于?filter[status][_eq]=published
_neq不等于?filter[status][_neq]=draft
_gt大于?filter[price][_gt]=100
_gte大于等于?filter[price][_gte]=50
_lt小于?filter[price][_lt]=200
_lte小于等于?filter[price][_lte]=150
_in在列表中?filter[status][_in]=published,featured
_contains包含文本?filter[title][_contains]=tutorial
_between在值之间?filter[price][_between]=50,100
_null为空?filter[deleted_at][_null]=true

排序和分页

# 按日期降序排序
GET /items/articles?sort=-date_created

# 分页
GET /items/articles?page=1&limit=20

# 字段选择
GET /items/articles?fields=id,title,author.name

GraphQL

query {
  articles(
    filter: { status: { _eq: "published" } }
    sort: ["-date_created"]
    limit: 10
  ) {
    id
    title
    body
    author {
      name
      avatar {
        id
      }
    }
    tags {
      tags_id {
        name
      }
    }
  }
}

权限

基于角色的访问控制

级别描述
System Access可以访问管理应用
Admin完全访问一切
Public未认证的 API 访问
Custom Roles细粒度的每集合权限

权限配置

权限选项
CreateNone、Full、Custom
ReadNone、Full、Custom
UpdateNone、Full、Custom
DeleteNone、Full、Custom

自定义权限

使用自定义权限限制对特定项目的访问。

{
  "id": {
    "_eq": "$CURRENT_USER"
  }
}

此筛选器允许用户仅读取自己的项目。

Flows(自动化)

Flow 组件

组件描述
Trigger启动 flow 的事件
Operation要执行的操作
Conditionif/then 逻辑

触发器类型

类型描述
Event Hook在 CRUD 操作时触发
Schedule基于 cron 的调度
Webhook外部 HTTP 触发
Manual用户发起

操作类型

类型描述
Create Item添加新记录
Read Item获取记录
Update Item修改记录
Delete Item删除记录
Send Email发送通知
Webhook Request调用外部 API
Run Script执行自定义代码
Transform Data映射/转换数据

示例 Flow:自动发布

触发器:文章创建(status = "review")
  |
  v
条件:作者是否受信任?
  |
  是 -> 更新项目:设置 status = "published"
  否 -> 发送邮件:通知编辑审查

文件和媒体

文件上传

方法描述
Admin UI在 Files 模块中拖拽
APIPOST 到 /files 使用 multipart 表单
Relation附加到项目字段

文件配置

设置描述
Storage adapter本地、S3、Azure、GCS
Max file size上传限制
Allowed typesMIME 类型限制
Transform上传时自动调整大小

图片转换

# 调整图片大小
GET /assets/{id}?width=300&height=200&fit=cover

# 格式转换
GET /assets/{id}?format=webp

# 质量调整
GET /assets/{id}?quality=80

扩展

扩展类型

类型描述语言
Interface自定义字段 UIVue.js
Display自定义字段显示Vue.js
Layout自定义集合视图Vue.js
Module自定义管理部分Vue.js
HookAPI 事件处理器JavaScript
Endpoint自定义 API 路由JavaScript
Theme管理应用主题CSS

创建 Hook 扩展

// extensions/hooks/auto-slug/index.js
module.exports = function registerHook({ action }) {
  action('items.create', async ({ payload, collection }) => {
    if (collection === 'articles' && payload.title && !payload.slug) {
      payload.slug = payload.title
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/(^-|-$)/g, '');
    }
  });
};

创建 Endpoint 扩展

// extensions/endpoints/custom-api/index.js
module.exports = function registerEndpoint({ router }) {
  router.get('/stats', async (req, res) => {
    const articles = await req.database('articles').count('* as total');
    const users = await req.database('directus_users').count('* as total');
    res.json({
      articles: articles[0].total,
      users: users[0].total
    });
  });
};

Webhooks 和实时

Webhooks

在 Settings > Webhooks 中配置 webhooks。

设置描述
URL要通知的端点
MethodHTTP 方法
Headers自定义头
Trigger监听哪些事件
Collection哪个集合

实时订阅

import { createDirectus, realtime } from '@directus/sdk';

const client = createDirectus('https://directus.example.com')
  .with(realtime());

// 订阅变更
const subscription = client.subscribe('articles', {
  event: 'create',
  query: { fields: ['id', 'title', 'status'] }
});

for await (const item of subscription) {
  console.log('New article:', item.data[0]);
}

快照和迁移

架构快照

# 导出架构
npx directus schema snapshot ./snapshot.yaml

# 应用架构
npx directus schema apply ./snapshot.yaml

备份

备份组件

组件方法
数据库pg_dump、mysqldump
上传文件rsync 或 rclone
扩展文件复制
.env文件复制

总结

Directus 提供了一个灵活的无头 CMS,为任何 SQL 数据库提供 REST 和 GraphQL API 包装。通过集合和字段建模数据,配置细粒度权限,使用 Flows 构建自动化工作流程。管理应用提供无代码界面用于内容管理,而开发者获得完全的 API 访问来构建应用程序。


来源:flat.md

简介

Bolt CMS(也称为 Bolt)是一个轻量级的开源内容管理系统,专为开发者和内容编辑者设计。它使用扁平文件方式进行配置,同时将内容存储在数据库中。本教程涵盖安装、内容建模、主题和日常使用。

架构

组件技术用途
后端Symfony (PHP)应用框架
存储SQLite/MySQL/PostgreSQL内容存储
模板TwigHTML 渲染
管理内置面板内容管理
APIREST 端点无头访问

安装

Composer

composer create-project bolt/project mysite
cd mysite
php bin/console bolt:setup

Docker

version: "3"
services:
  bolt:
    image: bolt/core:latest
    ports:
      - "80:80"
    volumes:
      - ./bolt-data:/var/www/html
    depends_on:
      - database
  database:
    image: mariadb:10
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: bolt
      MYSQL_USER: bolt
      MYSQL_PASSWORD: bolt

Web 服务器配置

server {
    listen 80;
    server_name mysite.example.com;
    root /var/www/html/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

内容类型

内容类型定义内容的结构。它们在 YAML 配置文件中定义。

定义内容类型

# config/bolt/contenttypes.yaml
pages:
    name: Pages
    singular_name: Page
    fields:
        title:
            type: text
            class: large
            group: content
        slug:
            type: slug
            uses: title
        body:
            type: html
            height: 300px
        image:
            type: image
    taxonomy: [ groups ]
    listing_records: 10
    default_status: published
    sort: -datepublish

字段类型

类型描述使用场景
text单行文本标题、名称
html富文本编辑器正文内容
markdownMarkdown 编辑器技术内容
image图片上传特色图片
file文件上传文档、下载
video视频嵌入YouTube、Vimeo
textarea纯文本多行描述
date日期选择器活动、截止日期
datetime日期和时间选择器日程安排
select下拉选择类别、状态
checkbox布尔开关精选、已发布
number数值价格、数量
email邮箱地址联系信息
embedOEmbed社交媒体嵌入
geolocation地图坐标位置数据
repeater可重复字段多个条目
block内容块灵活布局

多个内容类型

blogposts:
    name: Blog Posts
    singular_name: Blog Post
    fields:
        title:
            type: text
            class: large
        slug:
            type: slug
            uses: title
        image:
            type: image
        body:
            type: html
        tags:
            type: taxonomy
            taxonomy: tags
    relations:
        pages:
            multiple: false
    taxonomy: [ categories, tags ]
    record_template: blogpost.twig

entries:
    name: Entries
    singular_name: Entry
    fields:
        title:
            type: text
        body:
            type: markdown
    listing_records: 20

模板(主题)

主题结构

mytheme/
  index.twig
  record.twig
  listing.twig
  _header.twig
  _footer.twig
  _aside.twig
  css/
    style.css
  js/
    main.js

基础模板

{# index.twig #}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ config.get('general/sitename') }}</title>
    <link rel="stylesheet" href="{{ asset('css/style.css', 'theme') }}">
</head>
<body>
    {% include '_header.twig' %}

    <main>
        {% block content %}
            {% for record in records %}
                <article>
                    <h2><a href="{{ record|link }}">{{ record.title }}</a></h2>
                    {{ record|excerpt(300) }}
                </article>
            {% endfor %}
        {% endblock %}
    </main>

    {% include '_footer.twig' %}
</body>
</html>

记录模板

{# record.twig #}
{% extends 'index.twig' %}

{% block content %}
<article class="record">
    <h1>{{ record.title }}</h1>
    <time>{{ record.datepublish|date('F j, Y') }}</time>

    {% if record.image %}
        <img src="{{ record.image|thumbnail(800, 600) }}"
             alt="{{ record.title }}">
    {% endif %}

    <div class="body">
        {{ record.body }}
    </div>

    {% if record.taxonomy.tags is defined %}
        <div class="tags">
            {% for tag in record.taxonomy.tags %}
                <span class="tag">{{ tag }}</span>
            {% endfor %}
        </div>
    {% endif %}
</article>
{% endblock %}

列表模板

{# listing.twig #}
{% extends 'index.twig' %}

{% block content %}
{% for record in records %}
    <div class="card">
        <h2><a href="{{ record|link }}">{{ record.title }}</a></h2>
        <p>{{ record|excerpt(200) }}</p>
    </div>
{% endfor %}

{{ pager(records, template='helpers/_pager.html') }}
{% endblock %}

Twig 函数和过滤器

常用过滤器

过滤器描述示例
|link获取记录 URL{{ record|link }}
|excerpt截断文本{{ record|excerpt(300) }}
|date格式化日期{{ record.datepublish|date('Y-m-d') }}
|raw输出未转义的 HTML{{ record.body|raw }}
|thumbnail调整图片大小{{ image|thumbnail(400, 300) }}
|markdown解析 markdown{{ text|markdown }}
|json_decode解析 JSON 字符串{{ data|json_decode }}

常用函数

函数描述示例
path()生成 URL{{ path('homepage') }}
url()绝对 URL{{ url('page', {'slug': 'about'}) }}
asset()主题资源路径{{ asset('css/style.css', 'theme') }}
menu()渲染导航{{ menu('main') }}
pager()分页控件{{ pager(records) }}
dump()调试变量{{ dump(record) }}

分类法

定义分类法

# config/bolt/taxonomy.yaml
categories:
    name: Categories
    slug: categories
    singular_name: Category
    behaves_like: categories
    options: [ news, tutorials, reviews ]

tags:
    name: Tags
    slug: tags
    singular_name: Tag
    behaves_like: tags
    allow_spaces: true

groups:
    name: Groups
    slug: groups
    singular_name: Group
    behaves_like: grouping
    options: [ content, meta ]

在模板中使用分类法

{# 显示记录的标签 #}
{% if record.taxonomy.tags is defined %}
    <div class="tags">
        {% for tag in record.taxonomy.tags %}
            <a href="{{ path('taxonomy', {'taxonomytype': 'tags', 'slug': tag}) }}">
                {{ tag }}
            </a>
        {% endfor %}
    </div>
{% endif %}

菜单

定义菜单

# config/bolt/menu.yaml
main:
    - label: Home
      title: Welcome
      path: homepage
      class: first
    - label: Blog
      path: listing/blogposts
    - label: About
      link: /page/about
    - label: Contact
      path: page/contact

渲染菜单

<nav>
    {{ menu('main', 'helpers/_menu.twig') }}
</nav>

菜单模板

{# helpers/_menu.twig #}
<ul class="nav">
    {% for item in menu %}
        <li class="{{ item.class|default('') }}">
            <a href="{{ item.link }}" title="{{ item.title }}">
                {{ item.label }}
            </a>
        </li>
    {% endfor %}
</ul>

配置

常规设置

# config/bolt/config.yaml
sitename: My Site
payoff: A great website
description: This is my website
locale: en_US
timezone: America/New_York
theme: mytheme
record_template: record.twig
listing_template: listing.twig

数据库配置

# .env
DATABASE_DRIVER=mysql
DATABASE_HOST=localhost
DATABASE_NAME=bolt
DATABASE_USER=bolt
DATABASE_PASSWORD=bolt

用户角色和权限

角色描述
Developer完全访问所有设置
Chief Editor管理所有内容和用户
Editor编辑和发布内容
Author创建和编辑自己的内容
Guest对管理面板的只读访问
Anonymous公共前端访问

扩展

安装扩展

composer require bolt/thumbs

常用扩展

扩展用途
bolt/thumbs图片缩略图生成
bolt/sitemapXML 站点地图生成
bolt/seoSEO 元数据管理
bolt/comments评论系统
bolt/redactor增强的富文本编辑器

API 访问

REST API 端点

端点方法描述
/api/contentsGET列出所有内容
/api/content/{type}GET按内容类型列出
/api/content/{type}/{id}GET获取单条记录
/api/content/{type}POST创建新记录
/api/content/{type}/{id}PUT更新记录

总结

Bolt CMS 提供了一个对开发者友好的扁平文件 CMS,具有灵活的内容建模系统。在 YAML 中定义内容类型,使用 Twig 构建模板,通过内置管理面板管理内容。它在编辑者的简洁性和开发者的能力之间取得了平衡。


来源:grav.md

简介

Grav 是一个现代的扁平文件内容管理系统,将内容存储在 Markdown 文件中,而不是数据库中。它提供快速的性能、简便的部署和灵活的 Twig 模板系统,无需数据库开销即可构建网站。

系统要求

组件最低配置推荐配置
PHP 版本7.3.68.1+
Web 服务器Apache 2.4Nginx 1.18+
内存64 MB256 MB
磁盘空间30 MB500 MB
扩展mbstring, xml, curl, zip+gd, +intl, +json

安装

手动安装

cd /var/www/html
wget https://getgrav.org/download/core/grav/latest
unzip latest -d grav
mv grav grav-site
chown -R www-data:www-data /var/www/html/grav-site

安装 Admin 插件

cd /var/www/html/grav-site
bin/gpm install admin

Docker 安装

docker run -d \
  --name grav \
  -p 8080:80 \
  -v /path/to/grav:/var/www/html \
  ricardoamaro/gravcms:latest

目录结构

目录用途
pages/所有内容(Markdown 文件)
themes/已安装的主题
plugins/已安装的插件
config/系统和插件配置
assets/编译后的 CSS、JS、图片
images/上传的图片
accounts/用户账户数据
backup/站点备份
cache/编译后的 Twig 缓存
logs/系统日志
user/用户自定义

内容结构

页面组织

pages/
  01.home/
    default.md
  02.about/
    default.md
  03.blog/
    item1/
      item.md
    item2/
      item.md
    blog.md
  04.contact/
    form.md

页面排序

前缀排序顺序导航
01.第一第一项
02.第二第二项
01. vs 02.数字排序控制菜单顺序
无前缀默认列表末尾

Frontmatter

Frontmatter 是每个 Markdown 文件顶部的 YAML 元数据。

基本 Frontmatter

---
title: About Us
menu: About
slug: about
template: default
visible: true
published: true
date: 2024-01-15
---

Frontmatter 字段

字段说明示例
title页面标题"About Us"
menu导航标签"About"
slugURL slug"about"
templateTwig 模板"default"
visible在导航中显示true
published页面已发布true
date发布日期2024-01-15
taxonomy分类和标签category: blog
metadataSEO 元数据description, og tags
order自定义排序alphabetical, date
redirectURL 重定向"/new-page"

分类配置

---
taxonomy:
  category: blog
  tag: [php, grav, tutorial]
---

Markdown 内容

标准 Markdown

# 标题 1
## 标题 2
### 标题 3

**粗体文本***斜体文本*

- 无序列表项
- 另一项

1. 有序列表项
2. 另一项

[链接文本](https://example.com)

![图片替代文字](image.jpg)

代码块

```php
<?php echo "Hello World"; ?>
```

表格

| 表头 1 | 表头 2 | 表头 3 |
|--------|--------|--------|
| 单元格 1 | 单元格 2 | 单元格 3 |
| 单元格 4 | 单元格 5 | 单元格 6 |

主题

热门主题

主题风格功能
Quark简洁、现代默认主题,响应式
Learn2文档侧边栏导航,搜索
Helium博客多作者,分类
Flavor作品集网格布局,画廊
Bookworm文档章节导航

安装主题

# 通过 CLI
bin/gpm install quark

# 通过管理面板
# 导航到 Themes > Add

主题结构

themes/
  my-theme/
    blueprints.yaml     # 主题元数据
    my-theme.yaml       # 主题配置
    css/                # 样式表
    js/                 # JavaScript
    images/             # 主题图片
    templates/          # Twig 模板
      default.html.twig
      blog.html.twig
      partials/
        base.html.twig
        navigation.html.twig

自定义主题模板

{# templates/default.html.twig #}
{% extends 'partials/base.html.twig' %}

{% block content %}
  <h1>{{ page.title }}</h1>
  {{ page.content|raw }}
{% endblock %}

插件

基础插件

插件用途分类
AdminWeb 管理界面管理
Form表单构建器内容
Email邮件发送通信
Markdown Notices样式化通知内容
Error自定义错误页面导航
Problems站点诊断管理
Login用户认证安全
Flex Objects自定义内容类型内容

安装插件

# 通过 CLI
bin/gpm install form

# 通过管理面板
# 导航到 Plugins > Add

表单插件

表单定义(在页面 frontmatter 中)

---
title: Contact
form:
  name: contact
  fields:
    - name: name
      label: Name
      type: text
      validate:
        required: true

    - name: email
      label: Email
      type: email
      validate:
        required: true

    - name: message
      label: Message
      type: textarea
      validate:
        required: true

  buttons:
    - type: submit
      value: Send
      classes: btn btn-primary

  process:
    - email:
        from: "{{ form.value.email }}"
        to: admin@example.com
        subject: "Contact Form"
    - message: Thank you for contacting us!
    - display: thankyou
---

表单字段类型

字段类型说明验证选项
text单行文本required, pattern
email邮箱输入required, 邮箱格式
textarea多行文本required, minlength
select下拉菜单required, options
checkbox复选框required
radio单选按钮required
file文件上传accept, maxsize
hidden隐藏值-
date日期选择器required

配置

系统配置(config/system.yaml)

pages:
  theme: quark
  markdown:
    extra: true
  process:
    markdown: true
    twig: false

cache:
  enabled: true
  driver: auto
  prefix: g

session:
  enabled: true
  timeout: 1800

站点配置(config/site.yaml)

title: My Grav Site
default_lang: en
author:
  name: Site Owner
  email: owner@example.com
metadata:
  description: "Site description for SEO"
taxonomies:
  - category
  - tag

性能

优化配置影响
Twig 缓存cache.enabled: true更快渲染
GzipWeb 服务器配置更小传输
OPcachephp.ini更快 PHP 执行
CDN外部 CDN全球分发
图片优化Grav 图片处理更小图片
资源管道CSS/JS 压缩更少请求

资源管道

{# 在基础模板中 #}
{% do assets.addCss('theme://css/custom.css') %}
{% do assets.addJs('theme://js/app.js', {group: 'bottom'}) %}
{{ assets.css() }}
{{ assets.js() }}

CLI 命令

命令用途
bin/grav install安装依赖
bin/gpm install <package>安装主题或插件
bin/gpm update更新所有包
bin/gpm selfupgrade升级 Grav 核心
bin/grav clear-cache清除所有缓存
bin/grav sandbox检查系统要求

备份与迁移

组件方法说明
页面文件复制整个 pages/ 目录
配置文件复制config/ 目录
主题bin/gpm 或文件复制可重新安装
插件bin/gpm 或文件复制可重新安装
用户数据文件复制user/ 目录
完整备份zip 整个目录完整站点备份

迁移步骤

  1. 复制整个 Grav 目录到新服务器
  2. 设置 Web 服务器文档根目录
  3. 配置 PHP 版本
  4. 设置文件权限
  5. 清除缓存:bin/grav clear-cache

安全

措施实现方式
HTTPSWeb 服务器 SSL 配置
Admin 插件强管理员密码
文件权限限制写入访问
PHP 版本保持 PHP 更新
插件更新定期 bin/gpm update
备份定期备份
登录保护管理端速率限制

故障排除

问题原因解决方案
500 错误PHP 版本检查 PHP 兼容性
空白页Twig 错误启用调试模式
样式缺失资源管道清除缓存
页面 404URL 重写检查 .htaccess 或 nginx 配置
加载缓慢缓存禁用在配置中启用缓存

总结

Grav 提供了一个快速、灵活的扁平文件 CMS,消除了数据库开销,同时保持强大的内容管理能力。其基于 Markdown 的内容、Twig 模板和丰富的插件生态系统,使其成为寻求轻量但功能丰富的 CMS 的开发者的理想选择。


来源:pagekit.md

使用 Pagekit 构建和管理网站的完整指南,这是一个基于现代 PHP 和 Vue.js 的模块化 CMS。

目录


安装

要求

要求最低版本推荐
PHP7.2+8.1+
数据库MySQL 5.7+ / SQLite 3.8+ / PostgreSQL 9.4+MySQL 8.0
Web 服务器Apache 2.4+ / Nginx 1.14+Nginx
Composer2.0+最新
PHP 扩展PDO, Mbstring, Tokenizer, XML, JSON所有列出

通过 Composer 安装

composer create-project pagekit/pagekit mysite
cd mysite

手动安装

  1. https://pagekit.com 下载最新版本。
  2. 解压到 Web 服务器的文档根目录。
  3. 确保 Web 服务器可以写入 storagetmp 目录。
chmod -R 775 storage tmp
chown -R www-data:www-data storage tmp

Web 安装器

  1. 在浏览器中访问你的站点 URL。
  2. 安装器检查系统要求。
  3. 配置数据库连接:
字段示例
Database TypeMySQL
Hostlocalhost
Database Namepagekit
Usernamepagekit_user
Passwordsecure_password
  1. 创建管理员账号:
字段描述
Site Title你的网站名称
Username管理员用户名
Password管理员密码
Email管理员邮箱
  1. 点击 Install 完成设置。

Web 服务器配置

Apache(已包含 .htaccess):

<VirtualHost *:80>
    ServerName mysite.com
    DocumentRoot /var/www/mysite
    <Directory /var/www/mysite>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Nginx:

server {
    listen 80;
    server_name mysite.com;
    root /var/www/mysite;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

安装后

任务方法
移除安装器删除 install 目录
设置权限限制 storagetmp 访问
配置缓存在 System 设置中启用缓存
设置时区Settings > System > Timezone

仪表板

仪表板是管理 Pagekit 站点的中心枢纽。

仪表板概述

区域用途
Site Info显示站点名称、版本和状态
Recent Activity显示最新内容变更
Quick Actions常用任务快捷方式
System Updates可用更新通知

导航

主管理侧边栏包含:

菜单项描述
Dashboard概览和快捷操作
Site页面、博客、菜单、组件
Extensions管理已安装扩展
System用户、设置、存储、信息

系统设置

设置描述
Site Title浏览器标签和标题中显示的名称
Site Description默认 meta 描述
Application调试模式、维护模式
Cache启用/禁用页面缓存
Timezone日期显示的服务器时区
Locale默认语言

维护模式

在更新期间启用维护模式以限制访问:

  1. 前往 System > Settings > Application
  2. 切换 Maintenance Mode
  3. 管理员仍可访问仪表板。
  4. 访客看到维护页面。

页面

页面是构成网站结构的静态内容。

创建页面

  1. 前往 Site > Pages
  2. 点击 Add Page
  3. 输入页面标题。
  4. 配置页面设置。
  5. 使用编辑器添加内容。
  6. 点击 SaveSave and Close

页面设置

设置描述
Title页面标题和浏览器标签标题
SlugURL 友好的标识符
Status草稿、已发布或未发布
Access谁可以查看页面
Redirect重定向 URL(可选)
Layout使用的模板布局

内容编辑器

Pagekit 提供支持 Markdown 的富文本编辑器。

功能描述
Rich Text所见即所得编辑工具栏
Markdown直接 Markdown 输入
HTML原始 HTML 编辑
Media插入图片和文件
Widgets嵌入组件内容

页面模板

模板描述
Default标准页面布局
Full Width无侧边栏
Sidebar带侧边栏的内容
Landing自定义着陆页布局

管理页面

操作方法
编辑点击列表中的页面标题
复制选择页面 > Actions > Duplicate
删除选择页面 > Actions > Delete
重排序在页面列表中拖放
批量操作选择多个页面 > 选择操作

页面路由

为页面配置 URL 模式:

设置示例
Default/about
Custom slug/about-us
Nested/company/about
Redirect/old-page 重定向到 /new-page

博客

博客模块提供完整的博客平台。

创建博客文章

  1. 前往 Site > Blog
  2. 点击 Add Post
  3. 输入文章标题和内容。
  4. 配置文章设置。
  5. 点击 PublishSave as Draft

文章设置

设置描述
Title文章标题
SlugURL 友好的标识符
Content文章正文(富文本或 Markdown)
Excerpt列表视图的简短摘要
Status草稿、已发布、已排期
Publish Date发布日期和时间
Categories分配到分类
Tags添加标签用于筛选
Access谁可以查看文章

分类

将文章组织到分类:

操作方法
创建分类Blog > Categories > Add
分配分类在文章设置中选择分类
编辑分类分类列表 > Edit
删除分类分类列表 > Delete

标签

标签为文章提供灵活的标记:

功能描述
自动创建首次使用时创建标签
多标签每篇文章可分配多个标签
标签云在前端显示热门标签
筛选按标签筛选文章

博客设置

设置描述
Posts per page列表页每页文章数
Date format日期显示格式
Comments启用/禁用评论
RSS feed启用 RSS 输出
Share buttons社交分享选项

博客显示

配置博客在前端的显示方式:

选项描述
List view以列表显示文章摘要
Grid view以卡片网格显示文章
Full posts显示完整文章内容
Excerpts显示摘要加阅读更多链接

菜单

菜单定义网站的导航结构。

创建菜单

  1. 前往 Site > Menus
  2. 点击 Add Menu
  3. 输入菜单名称。
  4. 添加菜单项。
  5. 将菜单分配到主题位置。

菜单项

类型描述示例
URL链接到任意 URLhttps://example.com
Page链接到现有页面About, Contact
Blog链接到博客列表博客首页
Category链接到博客分类News, Updates
Separator菜单中的视觉分隔线---

添加菜单项

  1. 在菜单编辑器中点击 Add Item
  2. 选择项目类型。
  3. 配置项目:
设置描述
Title菜单中显示的文字
URL目标 URL 或页面
Icon可选图标类
Target同一窗口或新标签
Access谁可以看到此项

菜单结构

通过拖放组织项目:

Home
About
  Our Team
  History
Services
  Consulting
  Development
Blog
Contact

菜单位置

将菜单分配到主题位置:

位置典型位置
logo站点头部 logo 区域
menu主导航栏
offcanvas移动端滑出菜单
footer页脚导航

菜单设置

设置描述
Dropdown为子项启用下拉
Dropdown style悬停或点击打开
Active trail高亮活动页面的父项
Max depth限制嵌套层级

组件

组件是放置在主题位置的可复用内容块。

创建组件

  1. 前往 Site > Widgets
  2. 点击 Add Widget
  3. 选择组件类型。
  4. 配置组件。
  5. 分配到主题位置。
  6. 点击 Save

组件类型

类型描述用途
Text自定义文本和 HTML页脚内容、通知
Menu显示导航菜单侧边栏导航
System系统生成内容登录、搜索
CustomHTML/JS 代码块嵌入、脚本

组件设置

设置描述
Title组件标题
Type组件内容类型
Position显示的主题位置
Access谁可以看到组件
Pages仅在特定页面显示

组件位置

可用位置取决于活动主题:

位置典型用途
sidebar右或左侧边栏
footer页面页脚区域
header主内容上方
content_top主内容之前
content_bottom主内容之后

页面特定组件

控制哪些页面显示组件:

设置描述
All pages组件在所有地方显示
Selected pages选择特定页面
Exclude pages除选定外都显示

主题

主题控制网站的视觉外观和布局。

安装主题

  1. 前往 System > Extensions
  2. 点击 Add Extensions
  3. 浏览或搜索主题。
  4. 点击 Install
  5. 前往 System > Settings > Site
  6. 选择新主题。

主题设置

设置描述
Logo上传站点 logo
Favicon浏览器标签图标
Primary Color主强调色
Font默认正文字体
Layout页面布局样式
Custom CSS附加 CSS 样式

主题位置

主题定义可放置组件和菜单位置:

位置名称位置
logo站点头部
menu导航栏
heroHero/Banner 区域
sidebar左或右侧边栏
content主内容区域
footer页面页脚
copyright版权栏

创建子主题

自定义主题而不修改原始主题:

themes/
  my-child/
    index.php          # Theme registration
    theme.json         # Theme configuration
    templates/         # Override templates
    styles/            # Custom styles

主题配置 (theme.json)

{
  "name": "my-child",
  "version": "1.0.0",
  "parent": "theme-flavor",
  "positions": {
    "sidebar": "Sidebar",
    "footer": "Footer"
  }
}

扩展

扩展为 Pagekit 安装添加功能。

安装扩展

方式方法
MarketplaceSystem > Extensions > Add Extensions
UploadSystem > Extensions > Upload ZIP
Composercomposer require vendor/package

管理扩展

操作方法
启用Extensions > Toggle on
禁用Extensions > Toggle off
更新Extensions > Update(如有)
卸载Extensions > Remove

热门扩展类别

类别示例
SEOSitemap 生成器、meta 标签管理器
Forms联系表单、调查
E-commerce购物车、产品目录
Social社交媒体 feed、分享按钮
AnalyticsGoogle Analytics、访客追踪
Security双因素认证、防火墙

扩展设置

每个扩展有自己的配置:

  1. 前往 System > Extensions
  2. 点击扩展旁的齿轮图标。
  3. 根据需要配置设置。
  4. 点击 Save

开发自定义扩展

扩展结构:

packages/
  vendor/
    extension-name/
      index.php           # Extension entry point
      src/                # PHP source files
      views/              # Templates
      assets/             # CSS, JS, images
      extension.json      # Extension metadata

用户

管理用户账号和角色。

用户管理

操作方法
查看用户System > Users
添加用户Users > Add User
编辑用户点击用户名 > Edit
删除用户选择用户 > Actions > Delete
封禁用户选择用户 > Actions > Block

用户字段

字段描述
Username唯一登录名
Email用户邮箱
Password账号密码
Display Name公开显示名称
Avatar头像
Roles分配的角色
Status活动或封禁

用户角色

角色默认权限
Administrator所有功能完全访问
Editor创建、编辑、发布内容
Author创建和编辑自己的内容
Subscriber只读前端访问

创建自定义角色

  1. 前往 System > Users > Roles
  2. 点击 Add Role
  3. 输入角色名称。
  4. 选择权限。
  5. 点击 Save

用户注册

设置描述
Allow registration启用公开注册
Email verification需要邮箱确认
Default role分配给新注册的角色
Approval需要管理员批准

权限

控制对内容和功能的访问。

权限系统

级别描述
Global系统范围权限
Component每模块权限
Content每项访问控制

全局权限

权限描述
system: access admin area访问管理仪表板
system: manage settings更改系统设置
system: manage extensions安装/移除扩展
system: manage storage管理文件存储

内容权限

设置选项
Public任何人都可查看
Registered仅登录用户
Author仅内容作者
Custom特定角色或用户

分配权限

  1. 前往 System > Users > Permissions
  2. 选择角色。
  3. 勾选/取消每个组件的权限。
  4. 点击 Save

权限矩阵示例

权限AdminEditorAuthorSubscriber
访问管理
管理页面
编辑自己的内容
发布内容
管理用户
管理设置

SEO

为搜索引擎优化你的 Pagekit 站点。

基本 SEO 设置

设置位置描述
Site TitleSystem > Settings出现在搜索结果中
Meta DescriptionSystem > Settings默认页面描述
Permalink StructureSystem > Settings内容 URL 格式
SitemapExtensions自动生成的 XML sitemap

URL 结构

配置简洁 URL:

格式示例
Default/index.php?id=123
Clean/about
Blog/blog/post-title
Category/blog/category/news

页面级 SEO

每页和文章都有 SEO 字段:

字段描述
Title Tag浏览器标签和搜索结果标题
Meta Description搜索结果中显示的摘要
SlugURL 路径组件
Canonical URL重复内容的首选 URL
RobotsIndex/noindex, follow/nofollow

SEO 最佳实践

实践实施方式
独特标题每页有不同标题
Meta 描述150-160 字符摘要
简洁 URL描述性、关键词丰富的 slug
标题层级正确的 H1, H2, H3 结构
图片 alt 文本描述性 alt 属性
内部链接相关内容之间链接
Sitemap向搜索引擎提交 XML sitemap

SEO 扩展

扩展功能
SEO PackMeta 标签、sitemap、robots.txt
Google Analytics访客追踪集成
Schema Markup富摘要的结构化数据
Redirect Manager301/302 重定向管理

备份

通过定期备份保护站点数据。

备份内容

组件位置方法
DatabaseMySQL/PostgreSQL/SQLite数据库导出
Files/storage 目录文件复制
Configuration/config 目录文件复制
Extensions/packages 目录文件复制
Themes/themes 目录文件复制

数据库备份

MySQL:

mysqldump -u username -p pagekit_db > backup_$(date +%Y%m%d).sql

PostgreSQL:

pg_dump -U username pagekit_db > backup_$(date +%Y%m%d).sql

SQLite:

cp storage/database.sqlite backup_$(date +%Y%m%d).sqlite

文件备份

tar -czf pagekit_files_$(date +%Y%m%d).tar.gz \
  storage/ \
  config/ \
  packages/ \
  themes/

自动备份脚本

#!/bin/bash
BACKUP_DIR="/backups/pagekit"
DATE=$(date +%Y%m%d_%H%M%S)

# Database backup
mysqldump -u root -p pagekit_db | gzip > $BACKUP_DIR/db_$DATE.sql.gz

# File backup
tar -czf $BACKUP_DIR/files_$DATE.tar.gz /var/www/pagekit/storage

# Cleanup old backups (keep 30 days)
find $BACKUP_DIR -type f -mtime +30 -delete

恢复流程

步骤命令
1. 恢复数据库mysql -u root -p pagekit_db < backup.sql
2. 恢复文件tar -xzf files_backup.tar.gz -C /var/www/pagekit
3. 清除缓存删除 storage/cache 内容
4. 验证浏览站点并检查功能

备份计划

频率保留用途
每天7 天经常变更的活跃站点
每周30 天标准站点
每月12 个月归档
更新前永久更新前安全网

备份验证

定期通过恢复到暂存环境测试备份:

  1. 设置暂存服务器。
  2. 恢复最新备份。
  3. 验证所有内容正确加载。
  4. 测试关键功能(登录、表单、导航)。
  5. 记录发现的任何问题。

来源:statamic.md

简介

Statamic 是一个基于 Laravel 构建的现代扁平文件内容管理系统。它使用 Markdown 和 YAML 文件存储内容,而非数据库。本教程涵盖安装、内容建模以及使用 Statamic 构建完整网站。

为什么选择扁平文件 CMS

特性扁平文件(Statamic)数据库 CMS
存储YAML/Markdown 文件MySQL/PostgreSQL
设置无需数据库需要数据库配置
版本控制Git 友好的内容需要导出工具
性能文件读取,可选缓存基于查询
托管任何 PHP 主机需要数据库主机
备份复制文件导出数据库

系统要求

组件最低要求推荐配置
PHP8.18.2 或 8.3
Composer2.x最新版
Node.js16+18+ LTS
Web 服务器Apache/NginxNginx + PHP-FPM
扩展mbstring、xml、curl、zip所有 PHP 扩展

安装

全新安装

composer create-project statamic/statamic my-site
cd my-site
php artisan statamic:install

添加到现有 Laravel 项目

composer require statamic/cms
php artisan statamic:install

目录结构

目录用途
content/所有页面、条目、分类法
resources/视图(Antlers 模板)、CSS、JS
public/网站根目录、资源文件
config/站点和插件配置
users/用户账户(YAML 文件)
storage/日志、缓存、临时文件
app/自定义 PHP 代码、控制器

内容架构

集合(Collections)

集合将相关内容条目分组。

集合类型用例示例
Blog(博客)基于时间的文章文章、新闻
Pages(页面)静态页面关于、联系
Products(产品)电商商品目录条目
Events(活动)基于日期的内容会议、聚会

创建集合

  1. 运行 php please make:collection blog
  2. 编辑 content/collections/blog.yaml
  3. 定义蓝图字段
  4. 以 Markdown 文件形式添加条目

条目结构

字段格式用途
titleString条目标题
slugStringURL 安全标识符
dateDate发布日期
authorString内容作者
templateStringAntlers 模板名称
bodyMarkdown主要内容

蓝图(Blueprints)

蓝图定义内容条目的结构。

字段类型用例
text标题、名称、短字符串
textarea描述、摘要
markdown富文本内容
select下拉选项
assets图片和文件上传
entries与其他条目的关联
date日期和时间选择器
toggle布尔标志
bard基于块的富文本编辑器
repeater可重复的字段组

使用 Antlers 模板

Antlers 是 Statamic 的原生模板引擎。

基本语法

语法用途
{{ title }}输出变量
{{ if title }}...{{ /if }}条件块
{{ entries }}...{{ /entries }}遍历集合
{{ partial "header" }}包含局部模板
{{ yield "content" }}区域输出
{{ slot }}组件插槽

模板层级

模板范围优先级
default.antlers.html所有页面的后备模板最低
blog.antlers.html博客列表中等
blog/show.antlers.html单篇博客文章较高
_entry.antlers.html集合级覆盖最高

导航

创建导航

导航用途
main主站导航
footer页脚链接
sidebar侧边栏菜单

分类法(Taxonomies)

分类法对跨集合的条目进行分类。

分类法示例
tags技术、设计、新闻
categories博客文章分类
colors产品颜色选项

资源与媒体

功能描述
Asset Containers映射到存储磁盘的文件夹
Glide 集成实时图片处理
Alt Text无障碍图片描述
Focal Point智能裁剪中心

表单

表单类型用例
Contact(联系)用户咨询
Newsletter(通讯)邮件订阅
Search(搜索)内容搜索

用户与权限

角色默认权限
Super Admin(超级管理员)完全访问
Editor(编辑)编辑和发布内容
Author(作者)创建和编辑自己的内容
Viewer(查看者)只读访问

多语言支持

功能配置
Locales(区域设置)在 config/statamic/sites.php 中定义
Content(内容)每个区域设置的 Markdown 文件
Routing(路由)自动区域前缀
Fallback(回退)翻译缺失时显示默认区域内容

部署

方法步骤
Git推送内容和模板,在服务器上拉取
CI/CD构建资源、运行迁移、清除缓存
手动通过 FTP/SFTP 上传文件

生产环境清单

任务命令
缓存配置php artisan config:cache
缓存路由php artisan route:cache
缓存视图php artisan view:cache
静态缓存在 config/statamic/static_caching.php 中启用

性能优化

技术收益
静态缓存提供预渲染的 HTML
CDN全球分发资源
图片优化减小文件大小
Stache 缓存加速内容索引

总结

Statamic 将扁平文件存储的简洁性与 Laravel 的强大功能相结合。其 Antlers 模板系统、蓝图机制和 Git 友好的内容管理方式,使其非常适合希望完全掌控内容和基础设施、又不想承担传统数据库开销的开发者。


来源:strapi.md

简介

Strapi 是一个开源的无头 CMS,提供 RESTful 和 GraphQL API 来管理内容。它基于 Node.js 构建,允许开发者定义内容结构并从任何前端消费。本教程涵盖设置、内容建模和 API 使用。

无头 CMS 与传统 CMS 对比

方面无头(Strapi)传统(WordPress)
前端解耦,任意框架内置 PHP 模板
APIREST + GraphQL可选插件
内容交付任何设备或渠道默认仅 Web
灵活性中等
开发者体验API 优先主题优先

系统要求

组件版本
Node.js18.x 或 20.x
npm9.x+
数据库SQLite(默认)、PostgreSQL、MySQL
内存最低 2 GB
磁盘1 GB 可用空间

安装

npx create-strapi-app@latest my-project --quickstart
cd my-project
npm run develop
标志效果
--quickstart使用 SQLite,无需外部数据库
--no-run创建项目但不启动服务器
--template应用启动模板
--dbclient指定数据库类型(postgres、mysql)

项目结构

目录用途
src/api/内容类型、控制器、路由、服务
src/admin/管理面板自定义
config/服务器、数据库、中间件配置
database/迁移和种子数据
public/直接提供的静态文件
extensions/插件覆盖

内容类型

集合类型(Collection Types)

用于可重复的内容条目。

示例字段
Articlestitle、slug、body、author、publishedAt
Productsname、price、description、images
Categoriesname、slug、description

单一类型(Single Types)

用于唯一内容,如站点设置。

示例字段
HomepageheroTitle、heroImage、sections
GlobalsiteName、logo、footerText

创建内容类型

  1. 打开管理面板 /admin。
  2. 导航到 Content-Type Builder。
  3. 点击"Create new collection type"。
  4. 添加字段并配置类型。
  5. 保存以生成 API 端点。

字段类型

字段类型描述选项
Text短字符串maxLength、regex
Rich Text所见即所得编辑器Markdown 或 Quill
Number整数或小数min、max、integer/float
Date日期或日期时间format
Boolean真/假开关默认值
Enumeration下拉选择值列表
Media文件上传multiple、允许类型
Relation链接到其他内容类型多对一、多对多
JSON任意 JSON 数据schema 验证
UIDURL 友好的 slugtargetField、regex

REST API 参考

CRUD 操作

方法端点描述
GET/api/{contentType}列出所有条目
GET/api/{contentType}/:id获取单个条目
POST/api/{contentType}创建条目
PUT/api/{contentType}/:id更新条目
DELETE/api/{contentType}/:id删除条目

查询参数

参数用途示例
filters过滤结果filters[title][$contains]=tech
sort排序结果sort=createdAt:desc
pagination分页pagination[page]=1&pagination[pageSize]=25
populate包含关联populate=author,category
fields选择特定字段fields[0]=title&fields[1]=slug

过滤运算符

运算符含义示例
$eq等于filters[status][$eq]=published
$ne不等于filters[status][$ne]=draft
$lt小于filters[price][$lt]=100
$gt大于filters[price][$gt]=50
$contains包含字符串filters[title][$contains]=api
$in在数组中filters[category][$in]=tech,news
$null为空filters[deletedAt][$null]=true

GraphQL API

安装插件以启用 GraphQL:

npm run strapi install graphql
查询示例
列表query { articles { data { id attributes { title } } } }
单个query { article(id: 1) { data { attributes { title body } } } }
创建mutation { createArticle(data: { title: "New" }) { data { id } } }

认证与权限

功能描述
Public Role未认证的 API 访问
Authenticated Role已登录用户访问
Custom Roles细粒度权限控制
API Tokens用于服务端通信的静态令牌

配置权限

  1. 进入 Settings > Roles > Public。
  2. 选择内容类型。
  3. 切换权限:find、findOne、create、update、delete。
  4. 保存更改。

生命周期钩子

钩子触发时机
beforeCreate条目创建前
afterCreate条目创建后
beforeUpdate条目更新前
afterUpdate条目更新后
beforeDelete条目删除前
afterDelete条目删除后

部署

平台方法
Strapi Cloud推送到 Git,自动部署
HerokuGit 推送配合 Procfile
DigitalOceanApp Platform 或 Droplet
DockerDockerfile + docker-compose
AWSEC2、ECS 或 Lambda

环境变量

变量用途
HOST服务器主机(0.0.0.0)
PORT服务器端口(1337)
APP_KEYS会话安全密钥
API_TOKEN_SALTAPI 令牌加密盐值
ADMIN_JWT_SECRET管理面板 JWT 密钥
JWT_SECRET用户 JWT 密钥
DATABASE_CLIENT数据库类型
DATABASE_URL连接字符串

性能优化建议

建议实施方式
启用缓存使用 Redis 或内存缓存
优化查询选择性使用 fields 和 populate
压缩响应启用 gzip 中间件
使用 CDN通过 Cloudflare 或类似服务提供媒体
数据库索引在常用查询字段上添加索引

总结

Strapi 提供了一个灵活的、API 优先的内容管理系统,适用于任何前端框架。其内容类型构建器、REST 和 GraphQL API 以及插件生态系统,使其成为需要跨多个平台进行结构化内容交付的项目的理想选择。


来源:keystone.md

简介

KeystoneJS 是一个基于 Node.js 构建的无头内容管理系统。它提供了一个灵活的平台,用于通过 API 创建、管理和交付内容,无需耦合前端。

什么是无头 CMS?

无头 CMS 将内容管理与内容展示分离。后端提供 API,任何前端都可以消费这些 API。

特性传统 CMS无头 CMS
前端耦合解耦
内容交付HTML 页面API 响应
灵活性有限
多渠道困难原生支持

为什么选择 KeystoneJS?

优势描述
Schema 驱动在代码中定义数据模型
Admin UI内置管理界面
GraphQL API从 Schema 自动生成 API
身份验证内置认证系统
文件处理集成文件和图片管理

安装

前置要求

要求最低版本
Node.js18.0 或更高
npm8.0 或更高
数据库PostgreSQL、MySQL 或 SQLite

项目设置

npm init keystone-app my-cms
cd my-cms
npm install

项目结构

my-cms/
├── keystone.ts        # 主配置
├── schema.ts          # 内容 Schema
├── auth.ts            # 认证配置
├── package.json       # 依赖
└── .env               # 环境变量

Schema 定义

定义内容类型

每个内容类型都定义为一个包含字段的 list。

import { list } from '@keystone-6/core';
import { text, select, timestamp } from '@keystone-6/core/fields';

export const Post = list({
  fields: {
    title: text({ validation: { isRequired: true } }),
    content: text({ ui: { displayMode: 'textarea' } }),
    status: select({
      options: [
        { label: 'Draft', value: 'draft' },
        { label: 'Published', value: 'published' },
      ],
      defaultValue: 'draft',
    }),
    publishedAt: timestamp(),
  },
});

常用字段类型

字段类型用例示例
text短文本或长文本标题、描述
integer整数数量、分数
float小数价格、评分
select固定选项状态、分类
timestamp日期和时间创建日期
relationship关联记录作者、标签
checkbox布尔值精选、可见
image图片上传缩略图、照片

关联关系

import { relationship } from '@keystone-6/core/fields';

export const Post = list({
  fields: {
    title: text(),
    author: relationship({ ref: 'User.posts', many: false }),
    tags: relationship({ ref: 'Tag.posts', many: true }),
  },
});

export const Tag = list({
  fields: {
    name: text(),
    posts: relationship({ ref: 'Post.tags', many: true }),
  },
});
关系类型基数示例
一对一单条记录对应单条记录文章对应作者资料
一对多单条记录对应多条记录用户对应文章
多对多多条记录对应多条记录文章对应标签

配置

主配置文件

import { config } from '@keystone-6/core';
import { Post, Tag, User } from './schema';

export default config({
  db: {
    provider: 'postgresql',
    url: process.env.DATABASE_URL,
  },
  lists: { Post, Tag, User },
  ui: {
    isAccessAllowed: ({ session }) => !!session,
  },
});

数据库提供者

提供者用例性能
PostgreSQL生产工作负载
MySQL现有基础设施
SQLite开发和测试中等

身份验证

设置身份验证

import { createAuth } from '@keystone-6/auth';

const { withAuth } = createAuth({
  listKey: 'User',
  identityField: 'email',
  secretField: 'password',
  initFirstItem: {
    fields: ['name', 'email', 'password'],
  },
});

会话管理

import { statelessSessions } from '@keystone-6/core/session';

const session = statelessSessions({
  maxAge: 60 * 60 * 24 * 30,
  secret: process.env.SESSION_SECRET,
});
会话类型描述用例
无状态基于 JWT 的令牌API、可扩展性
数据库存储在数据库中服务端渲染应用

访问控制

字段级访问

export const Post = list({
  fields: {
    title: text({
      access: {
        read: true,
        create: ({ session }) => !!session,
        update: ({ session }) => session?.data.isAdmin,
      },
    }),
  },
});

列表级访问

export const Post = list({
  access: {
    operation: {
      query: true,
      create: ({ session }) => !!session,
      update: ({ session }) => !!session,
      delete: ({ session }) => session?.data.isAdmin,
    },
  },
});
访问级别范围示例
操作级CRUD 操作谁可以创建文章
字段级单个字段谁可以查看邮箱
过滤级记量子集用户只能看到自己的文章

GraphQL API

查询内容

query {
  posts(where: { status: { equals: "published" } }) {
    id
    title
    content
    author {
      name
    }
    tags {
      name
    }
  }
}

创建内容

mutation {
  createPost(data: {
    title: "New Post"
    content: "Post content here"
    status: "draft"
  }) {
    id
    title
  }
}

过滤和排序

操作语法示例
等于{ equals: value }状态等于 draft
包含{ contains: text }标题包含关键词
大于{ gt: number }价格大于 100
列表内{ in: [...] }状态在列表中
排序orderBy: { field: asc }按日期升序

文件和图片管理

图片配置

import { config } from '@keystone-6/core';

export default config({
  images: {
    upload: 'local',
    local: {
      storagePath: 'public/images',
      baseUrl: '/images',
    },
  },
});
存储选项描述最佳用途
本地文件系统开发
S3Amazon S3生产
Cloudinary云服务图片变换

部署

构建生产版本

npm run build
npm start

部署平台

平台配置备注
Vercelvercel.jsonServerless
Railwayrailway.json托管服务
DockerDockerfile自托管
AWSElastic Beanstalk可扩展

Docker 配置

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]

最佳实践

实践描述
版本化 Schema在版本控制中跟踪 Schema 变更
使用迁移部署前运行数据库迁移
验证输入启用字段验证规则
缓存响应为频繁访问的数据实现缓存
监控性能跟踪 API 响应时间

总结

概念要点
Schema在代码中定义内容类型
访问控制基于角色的权限管理
API自动生成的 GraphQL
身份验证内置用户管理
部署多平台支持