使用服务器 API 管理 Framer CMS——列出、创建、读取、更新和删除 CMS 集合和条目,上传图片,发布预览,部署到生产环境
帧器 CMS — 服务器 API 技能. 管理帧器 CMS 内容程序化通过帧器- api npm 包. 推送文章,上传图像,创建收藏,以及发布/部署 —— 全部是一项面向实际任务的技能。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。
执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
通过 framer-api npm 包以编程方式管理 Framer CMS 内容。可推送文章、上传图片、创建集合(collection),以及发布(publish)/部署(deploy)——全部可通过终端完成,无需打开 Framer 应用。
若用户在当前项目中首次使用该技能,请运行 references/onboarding.md 中描述的入门流程。
快速检查:查看用户的 .env 文件或环境变量中是否存在 FRAMER_PROJECT_URL 和 FRAMER_API_KEY。若缺失,请执行入门流程。
本技能基于 Framer Server API(即 framer-api npm 包),该包通过 WebSocket 使用 API 密钥连接至 Framer 项目,提供完整的 CMS 增删改查(CRUD)、图片上传、发布与部署能力。
重要提示:项目中必须已安装 framer-api 包。若未安装,请运行:
npm i framer-api
所有操作均通过 ES 模块脚本(.mjs 文件)实现,并采用如下连接模式:
import { connect } from "framer-api"
// 重要:API 密钥需以纯字符串形式传入(第二个参数),而非 {apiKey: "..."}
const framer = await connect(process.env.FRAMER_PROJECT_URL, process.env.FRAMER_API_KEY)
try {
// ... 执行操作 ...
} finally {
await framer.disconnect()
}
| 操作 | 方法 | 说明 |
|---|---|---|
| 列出所有集合 | framer.getCollections() |
返回全部 CMS 集合 |
| 获取单个集合 | framer.getCollection(id) |
根据集合 ID 获取 |
| 创建集合 | framer.createCollection(name) |
创建空集合 |
| 获取字段定义 | collection.getFields() |
返回字段定义(name、type、id) |
| 添加字段 | collection.addFields([{type, name}]) |
向集合中添加新字段 |
| 删除字段 | collection.removeFields([fieldId]) |
根据字段 ID 删除字段 |
| 重排字段顺序 | collection.setFieldOrder([fieldIds]) |
设置字段在编辑器中的显示顺序 |
| 操作 | 方法 | 说明 |
|---|---|---|
| 列出所有条目 | collection.getItems() |
返回全部条目及其字段数据 |
| 创建条目 | collection.addItems([{slug, fieldData}]) |
创建新条目。返回值为 undefined —— 需调用 getItems() 重新获取以获得条目 ID |
| 更新条目字段 | item.setAttributes({ fieldData: { [fieldId]: {type, value} } }) |
必须将字段值包裹在 fieldData: 中;否则值将被静默忽略,不报错 |
| 更新条目 slug 或草稿状态 | item.setAttributes({ slug: "new", draft: false }) |
slug 和 draft 属性直接设置(不在 fieldData 内) |
| 删除单个条目 | item.remove() |
仅删除一个条目 |
| 批量删除条目 | collection.removeItems([itemIds]) |
一次删除多个条目 |
| 重排条目顺序 | collection.setItemOrder([itemIds]) |
设置条目在编辑器中的显示顺序 |
setAttributes 方法具有 非直观的 API 设计 —— 字段值 必须 包裹在 fieldData 键下:
// ✅ 正确 —— 字段值包裹在 fieldData 中
await item.setAttributes({
fieldData: {
[titleFieldId]: { type: "string", value: "New Title" }
}
})
// ❌ 错误 —— 值将被静默忽略,且不抛出错误
await item.setAttributes({
[titleFieldId]: { type: "string", value: "New Title" }
})
// ❌ 错误 —— 同样会被静默忽略
await item.setAttributes({
[titleFieldId]: "New Title"
})
支持部分更新:仅修改指定字段,其余字段保持不变。
非字段属性(如 slug、draft)应直接设于对象顶层,而非置于 fieldData 内:
await item.setAttributes({ slug: "new-slug", draft: false })
创建或更新条目时,字段数据需以 字段 ID(而非字段名)为键:
const fields = await collection.getFields()
const titleField = fields.find(f => f.name === "Title")
await collection.addItems([{
slug: "my-article",
fieldData: {
[titleField.id]: { type: "string", value: "My Article Title" },
}
}])
支持的字段类型及其值格式:
| 类型 | 值格式 | 示例 |
|---|---|---|
string |
string |
{ type: "string", value: "Hello" } |
number |
number |
{ type: "number", value: 42 } |
boolean |
boolean |
{ type: "boolean", value: true } |
date |
string(UTC ISO 格式) |
{ type: "date", value: "2026-04-06T00:00:00Z" } |
formattedText |
string(HTML) |
{ type: "formattedText", value: " |
link |
string(URL) |
{ type: "link", value: "https://example.com" } |
image |
ImageAsset 对象 |
参见图片上传章节 |
enum |
string(枚举项名称) |
{ type: "enum", value: "Published" } |
color |
string(十六进制 / rgba) |
{ type: "color", value: "#FF0000" } |
file |
FileAsset 对象 |
行为类似 image 字段 |
collectionReference |
string(条目 ID) |
{ type: "collectionReference", value: "itemId123" } |
multiCollectionReference |
string[] |
{ type: "multiCollectionReference", value: ["id1","id2"] } |
从公开 URL 上传图片,然后在 CMS 条目中引用返回的 asset:
const asset = await framer.uploadImage("https://example.com/photo.jpg")
// asset = { id, url, thumbnailUrl }
await item.setAttributes({
fieldData: {
[thumbnailField.id]: { type: "image", value: asset.url }
}
})
// 创建预览部署
const result = await framer.publish()
// result = { deployment: { id }, hostnames: [...] }
// 将预览部署提升为生产环境
await framer.deploy(result.deployment.id)
每次部署至生产环境前,务必向用户确认。 发布预览是安全操作;而部署将直接影响线上环境。
await framer.getProjectInfo() // { id, name, apiVersion1Id }
await framer.getCurrentUser() // { id, name, avatar }
await framer.getPublishInfo() // 当前部署状态
await framer.getChangedPaths() // { added, removed, modified }
await framer.getChangeContributors() // 贡献者 UUID 列表
await framer.getDeployments() // 全部部署历史
| 操作 | 方法 | 说明 |
|---|---|---|
| 颜色样式 | getColorStyles(), createColorStyle() |
设计令牌(Design Tokens) |
| 文本样式 | getTextStyles(), createTextStyle() |
排版令牌(Typography Tokens) |
| 代码文件 | getCodeFiles(), createCodeFile(name, code) |
自定义代码覆盖 |
| 自定义代码 | getCustomCode() |
注入到 head / body 的代码 |
| 字体 | getFonts() |
项目所用字体 |
| 多语言区域设置(Locales) | getLocales(), getDefaultLocale() |
i18n 支持 |
| 页面 | createWebPage(path), removeNode(id) |
页面管理 |
| 截图 | screenshot(nodeId, options) |
任意节点的 PNG 缓冲区 |
| 重定向 | addRedirects([{from, to}]) |
需付费计划支持 |
| 节点树 | getNode(id), getChildren(id), getParent(id) |
DOM 遍历 |
完整流程(含字段解析、图片上传及错误处理)请参见 references/cms-operations.md。
const items = await collection.getItems()
for (const item of items) {
await item.setAttributes({
fieldData: {
[metaField.id]: { type: "string", value: generateMeta(item) }
}
})
}
const changes = await framer.getChangedPaths()
if (changes.added.length || changes.modified.length || changes.removed.length) {
const result = await framer.publish()
console.log("预览地址:", result.hostnames)
// 部署前请先向用户确认:await framer.deploy(result.deployment.id)
}
connect() 调用会建立持久化 WebSocket 连接。操作完成后务必调用 disconnect();或使用 using framer = await connect(...) 实现自动清理。getFields() 并将字段名解析为对应 ID。uploadImage() 返回的完整 framerusercontent.com URL,而非 asset ID。Object.keys(framer) 中,但可正常调用。formattedText 字段:支持标准 HTML 标签(h1–h6、p、ul、ol、li、a、strong、em、img、blockquote、pre、code、table 等)。draft: true;草稿内容默认不参与发布。"thisPlugin" 管理的集合仅可通过 API 读取,不可修改;仅 "user" 管理的集合支持写入操作。相关专题
热门下载
相关下载
精品课程
共6课时 | 54.7万人学习
共89课时 | 133.9万人学习
共49课时 | 82.5万人学习