关于 frappe-impl-website
面向 Frappe 开发者的网站与门户实施指南,涵盖页面、表单、博客、路由、主题和 SEO 配置,并提供访客访问安全建议。
主要功能
- 01创建静态页面与自定义门户页面
- 02配置 Web Form 和访客提交
- 03发布 DocType 网页与博客文章
- 04设置网站路由与主题样式
- 05添加 SEO 元数据并配置 Sitemap
- 06管理访客访问与安全设置
适用场景
- 01构建公开内容页或自定义门户
- 02收集外部用户提交的数据
- 03将 DocType 记录发布为网页
- 04设置博客、网站路由及搜索元数据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ frappe_claude_skill_package --skill frappe-impl-website安装后在 Claude Code 中输入/frappe-impl-website确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/.gitkeepanti-patterns.mddecision-tree.mdexamples.mdgenerators.mdworkflows.md详细介绍
Frappe 网站与门户 — 实施工作流
构建网站、门户和面向公众页面的分步工作流。钩子语法请参阅 frappe-impl-hooks。Jinja 模板请参阅 frappe-impl-jinja。
版本:v14/v15/v16 | 注意:v15+ 使用 Bootstrap 5;v14 使用 Bootstrap 4。
快速判断:选择哪种页面类型?
WHAT do you need?
├── Static content page (About, Terms) → Web Page DocType or www/ HTML
├── Data entry by external users → Web Form
├── List of records visible on website → has_web_view on DocType
├── Blog / news articles → Blog Post + Blog Category
├── Custom app with sidebar/toolbar → Custom Portal Page (www/)
└── Dynamic route with parameters → website_route_rules in hooks.py
完整决策树请参阅 references/decision-tree.md。
工作流 1:创建门户页面(www/)
门户页面位于应用的 www/ 目录中。文件名会成为 URL 路由。
- 创建
myapp/www/custom_page.html:
{% extends "templates/web.html" %}
{% block page_content %}
<h1>{{ title }}</h1>
<div>{{ content }}</div>
{% endblock %}
- 创建对应的控制器
myapp/www/custom_page.py:
import frappe
def get_context(context):
context.title = "My Custom Page"
context.content = "Hello World"
context.no_cache = 1 # ALWAYS set for dynamic content
- 结果:页面可通过
/custom_page访问
自动加载的文件类型:.html(模板)、.py(控制器)、.css(样式)、.js(脚本)。
子目录模式 — 用于嵌套路由:
myapp/www/
├── services/
│ ├── index.html → /services
│ ├── index.py
│ ├── consulting.html → /services/consulting
│ └── consulting.py
上下文变量参考
| 键 | 类型 | 效果 |
|---|---|---|
title | str | 页面标题和浏览器标签页标题 |
no_cache | bool | 禁用页面缓存 |
no_header | bool | 隐藏页面页眉 |
no_breadcrumbs | bool | 移除面包屑导航 |
add_breadcrumbs | bool | 根据文件夹结构自动生成 |
show_sidebar | bool | 显示网站侧边栏 |
sitemap | int | 0 = 从站点地图中排除,1 = 包含 |
metatags | dict | SEO 元标签(参见工作流 7) |
规则:对于包含用户专属或频繁变化内容的页面,始终设置 no_cache = 1。
工作流 2:创建 Web 表单
Web 表单允许外部用户提交数据并创建 Frappe 文档。
- 导航至 Web Form 列表 → New Web Form
- 设置 Title,选择目标 DocType,设置 Route(URL 别名)
- 添加字段——字段的
fieldname始终要与目标 DocType 的字段名称一致 - 配置访问权限:
- Login Required:取消勾选以允许访客提交
- Allow Edit:允许用户编辑其提交内容
- Allow Multiple:允许用户多次提交
- 保存并发布
访客提交
ALLOWING guest submissions?
├── YES → Uncheck "Login Required"
│ → Set "Guest Title" for the submission form
│ → ALWAYS add rate limiting in site_config:
│ "rate_limit": {"web_form": "5/hour"}
│ → ALWAYS validate server-side (guests can bypass JS)
└── NO → Keep "Login Required" checked (default)
Web 表单自定义脚本(客户端)
frappe.web_form.on("after_load", function() {
// Runs after form loads in browser
});
frappe.web_form.on("before_submit", function() {
// Validate before submission — return false to cancel
let val = frappe.web_form.get_value("email");
if (!val) {
frappe.throw("Email is required");
return false;
}
});
frappe.web_form.on("after_submit", function() {
// Redirect or show message after success
window.location.href = "/thank-you";
});
Web 表单自定义脚本(服务器端:Python)
在 Web Form 文档中添加 Python 脚本:
def get_context(context):
# Add custom context variables for the template
context.categories = frappe.get_all("Category", fields=["name", "title"])
规则:绝不能只信任 Web 表单的客户端验证。始终要在目标 DocType 的控制器或服务器脚本中进行验证。
工作流 3:在 DocType 上启用 has_web_view
这样可以将单个文档作为网页访问(例如 /articles/my-article)。
- 打开 DocType → 勾选 Has Web View 和 Allow Guest to View
- 设置 Route 字段前缀(例如
articles) - 始终将以下字段添加到 DocType:
route(Data,隐藏)— 自动生成的 URL 别名published(Check)— 控制可见性
- 在 DocType 目录中创建模板:
{doctype_name}.html— 单条记录模板{doctype_name}_row.html— 列表项模板
- 在
hooks.py中注册为网站生成器:
website_generators = ["Article"]
- 在控制器中实现
get_context:
class Article(WebsiteGenerator):
website = frappe._dict(
template="templates/generators/article.html",
condition_field="published",
page_title_field="title",
)
def get_context(self, context):
context.related = frappe.get_all(
"Article",
filters={"published": 1, "name": ("!=", self.name)},
fields=["title", "route"],
limit=5,
)
规则:始终包含 published 检查字段。绝不能向访客公开未发布的文档。
工作流 4:网站路由规则(hooks.py)
路由规则将 URL 模式映射到控制器或页面。
# hooks.py
website_route_rules = [
# Map parameterized URL to a page
{"from_route": "/projects/<name>", "to_route": "projects/project"},
# Map URL prefix to DocType
{"from_route": "/kb/<path:name>", "to_route": "knowledge-base"},
]
# Redirects (301/304)
website_redirects = [
{"source": "/old-page", "target": "/new-page"},
{"source": r"/docs(/.*)?", "target": r"https://docs.example.com\1"},
]
# Homepage for logged-in users (role-based)
role_home_page = {
"Customer": "orders",
"Supplier": "rfqs",
}
# Dynamic homepage
get_website_user_home_page = "myapp.utils.get_home_page"
主页的优先级顺序:get_website_user_home_page > role_home_page > Portal Settings > Website Settings。
工作流 5:博客设置
- 创建 Blog Category 文档(例如“新闻”“更新”)
- 创建 Blog Post 文档:
- 选择分类,编写内容(Markdown 或富文本)
- 设置 Published 和 Published On 日期
- 博客路由会自动生成为
/blog/{slug}
- 在 Website Settings 中配置:
- 设置博客标题
- 启用/禁用评论
规则:始终设置 Published On 日期——没有日期的文章绝不会出现在 RSS 源中。
工作流 6:网站主题与自定义 CSS
通过 Website Theme DocType
- 导航至 Website Theme → New
- 配置:字体、颜色、导航栏样式、按钮圆角
- 在 Custom CSS 字段中添加自定义 CSS
- 在 Website Settings 中将其设为活动主题
通过 hooks.py
# Inject CSS/JS on all web pages
website_context = {
"favicon": "/assets/myapp/images/favicon.png",
}
update_website_context = "myapp.overrides.website_context"
# Override base template
base_template = "myapp/templates/custom_base.html"
工作流 7:SEO:元标签、Open Graph 和站点地图
在门户页面中(frontmatter 或上下文)
def get_context(context):
context.metatags = {
"title": "My Page Title",
"description": "Page description for search engines",
"image": "/assets/myapp/images/og-image.png",
"og:type": "website",
"twitter:card": "summary_large_image",
}
在 Web Page DocType 中
直接设置元数据字段:Meta Title、Meta Description、Meta Image。
站点地图
- Frappe 会根据已发布的 Web Page 和 has_web_view 文档自动生成
/sitemap.xml - 排除页面:在上下文或 frontmatter 中设置
sitemap = 0 - 自定义 robots.txt:在
site_config.json中设置robots_txt路径
规则:公共页面必须始终设置 meta description。绝不能留空——搜索引擎会降低没有描述的页面的排名。
工作流 8:访客访问与安全性
# site_config.json — rate limiting
{
"rate_limit": {
"web_form": "5/hour",
"api": "100/hour"
},
"allowed_referrers": ["https://mysite.com"],
"allow_cors": "https://mysite.com"
}
安全规则:
- 始终启用 CSRF 保护(默认设置)。生产环境中绝不能设置
ignore_csrf - 始终对访客可访问的端点实施速率限制
- 始终清理 Web Forms 中的用户输入(Frappe 默认会清理标准字段)
- 未设置访问控制时,绝不能在面向访客的 URL 中暴露内部 DocType 名称
反模式
| 反模式 | 正确做法 |
|---|---|
在 get_context 中硬编码 HTML | 使用带上下文变量的 Jinja 模板 |
动态页面未设置 no_cache | 用户专属内容必须始终设置 no_cache = 1 |
| 访客 Web Form 未设置速率限制 | 始终为访客表单配置速率限制 |
has_web_view 缺少 published 字段 | 始终添加 published 检查以防止数据泄露 |
将 website_route_rules 用于简单重定向 | 改用 website_redirects |
| 将业务逻辑放入 www/ 控制器 | 将业务逻辑放在 DocType 控制器中;www/ 用于呈现 |
参见 references/anti-patterns.md,了解包含示例的扩展反模式说明。
另请参阅
frappe-impl-hooks— Website hooks 详解frappe-impl-jinja— Jinja 模板模式frappe-impl-controllers— DocType 控制器(WebsiteGenerator)frappe-syntax-clientscripts— Web Forms 的客户端 APIreferences/generators.md— 门户生成器、博客系统、自定义路由模式references/workflows.md— 扩展工作流详解references/examples.md— 完整代码示例references/decision-tree.md— 页面类型完整决策树