Hope CMS 文档

Hope CMS(希望CMS)是一款面向中文站长与 PHP 开发者的轻量开源内容管理系统:安装快、结构清楚、主题/插件零侵入扩展,适合个人博客、工作室站、资讯站与付费资源站。

请仅从官方域名下载安装包,其他来源存在安全风险。

命名说明

名称 用途
Hope CMS 程序主名称(文档、导航)
希望CMS 中文副名称

你能用它做什么

场景 说明
个人 / 技术博客 Markdown 写作、分类标签、评论、SEO
企业 / 工作室官网 独立页面模板、主题切换、侧栏组件
资讯 / 内容站 多作者角色、媒体库、伪静态链接
付费资源 / 会员站 个人中心、余额充值、支付网关(配合 Shop 等主题)
小程序 / 前后端分离 REST API(API Key、限流、CORS 视配置而定)

核心能力

  • 内容:Markdown(Editor.md)、分类 / 标签 / 封面 / 别名 / 置顶 / 阅读密码
  • 用户:管理员 / 编辑 / 作者 / 访客;后台模块权限
  • SEO 与链接:站点 / 文章 / 分类 / 标签 TDK;动态 / 伪静态 / index.php 三种链接模式
  • 扩展:挂载点(hope_listen / hope_emit)、主题、插件、侧边栏组件
  • 媒体与评论:附件库、评论审核、验证码、邮件通知
  • 个人中心:资料、余额、邀请奖励、在线支付(微信 / 支付宝等)
  • 运维:备份导入、更新缓存、SMTP、多语言后台、AI 工作台(可选)
  • 数据层:链式查询(HopeDb);插件在 callback_init 内建表

官方示例: 主题 content/theme/default/ · 插件 content/plugin/tips/

官网主题(本主题 hopecms)还可提供:用户论坛、站内开发文档、主题生成器等。

环境一览

项目 要求
PHP 7.0+(推荐 8.0+;建议同时验证 8.x)
数据库 MySQL 5.6+ / MariaDB 10.3+(mysqlipdo_mysql
Web Apache / Nginx(IIS 需 URL Rewrite)
扩展 建议 mbstringjsoncurlgd/imagickopenssl

详细步骤见 安装指南

文档导航

按阅读顺序:

分组 章节 内容
入门 安装指南 上传、安装向导、安全加固
入门 升级与更新 覆盖升级、插件/主题回调、更新缓存
入门 常见问题 安装排障、旧版兼容、开发疑问
入门 目录说明 content/system/ 结构总览
开发基础 开发准备工作 目录、常量、请求流程、常用 API
开发基础 挂载点手册 HopeHooks 全表与 hope_listen / hope_emit
开发基础 数据库与 SQL HopeDb、建表、MetaStorage
主题 主题开发指南 目录结构、模板、CSF 设置、生命周期
主题 侧边栏开发说明 widgets 注册与渲染
插件 插件开发指南 结构、钩子、设置页、前台页、发布清单
接口 伪静态与路由 链接模式、服务器配置、插件路由
接口 API 开发文档 REST、个人中心 API、鉴权
关于 联系我们 官方渠道与反馈方式

目录总览见 目录说明

二次开发原则

  1. 不要改 system/ 业务逻辑(升级会覆盖);扩展放在 content/theme/content/plugin/
  2. 主题负责皮肤与布局;跨主题能力做成插件
  3. 站点标题 / 副标题 / SEO / 版权走后台「设置」(Settings::get('sitename') 等)
  4. 输出用户内容使用 htmlspecialchars;数据库用 HopeDb,禁止拼接不可信 SQL

官方域名

软件许可证

Hope CMS(希望CMS)核心代码按 Apache License 2.0 发布。捆绑的第三方库以其目录内说明为准。

安装指南

从拿到安装包到站点可访问,通常只需:上传 → 运行向导 → 加固安全

环境要求

项目 要求
PHP 7.0+(推荐 8.0+;建议同时验证 7.4 / 8.x)
数据库 MySQL 5.6+ / MariaDB 10.3+(mysqlipdo_mysql
Web Apache / Nginx(IIS 需 URL Rewrite)
扩展 建议:mbstringjsoncurlgdimagickopenssl

目录需可写:content/upload/content/cache/(Linux 常见 755/775,属主为 Web 用户)。


三步安装

第一步:上传程序

  1. 官方下载页 获取最新安装包并解压
  2. 将全部文件上传到网站根目录(虚拟主机常见 public_html / wwwroot),或子目录
  3. 确认 content/cache/content/upload/ 可写
子目录安装时,后续需正确配置站点 URL,伪静态还要改 RewriteBase / Nginx 前缀。

第二步:运行安装向导

浏览器访问:

http://你的域名/install.php

按向导填写:

说明
数据库主机 多为 localhost
库名 / 用户 / 密码 事先在面板或 phpMyAdmin 建空库
表前缀 默认一般可用;同库多套程序时请改前缀
管理员账号 站点最高权限,密码请足够复杂

完成后会写入 content/cache/install.lock,并尽量将 install.php 重命名为 install.php.disabled

第三步:删除安装入口并登录

  1. 立即删除或重命名 install.php(若仍存在)
  2. 访问前台域名确认主题正常
  3. 后台默认入口:admin.php(见下文安全加固)

安装后必做

  1. 登录后台
  2. 重命名后台入口:将根目录 admin.php 改为不易猜测的文件名(如 manage_x8k2.php),并更新书签
    仍使用 admin.php 时,示例插件「小贴士」会在后台首页提示安全风险
  3. 外观 → 主题:启用所需主题;有 settings.php 时可配置外观
  4. 设置 → 站点信息 / SEO:站点标题、副标题、描述、版权(主题通过系统配置读取)
  5. 设置 → 链接:选择动态 / 伪静态;伪静态需配置服务器,见 伪静态与路由
  6. 插件 → 插件管理:按需启用(支付、OAuth 等)
  7. 按需配置 SMTP、支付网关
  8. 执行一次 设置 → 更新缓存
使用 zib / Shop 等旧结构主题,或依赖旧 API 的插件时,见 常见问题 · 旧版兼容

重装

  1. 备份数据库与 content/upload/
  2. 删除 content/cache/install.lock
  3. 如程序要求,设置环境变量 HOPE_ALLOW_REINSTALL=1
  4. 必要时从 install.php.bak 恢复 install.php
  5. 重新访问安装向导
重装会覆盖库表数据,生产环境务必先备份。

常见问题

打开 install.php 空白 / 报错

  • 检查 PHP 版本与必装扩展
  • 查看 content/cache/error.log 或 Web 服务器错误日志
  • 确认未误删 system/content/ 关键文件

提示目录不可写

  • 调整 content/cachecontent/upload 权限与属主
  • 部分主机禁止 777,优先用属主可写的 755/775

安装完成仍可访问 install.php

  • 手动删除或重命名 install.php
  • 确认存在 content/cache/install.lock

子目录安装后样式 / 链接错乱

  • 后台核对站点 URL(含路径与尾斜杠)
  • 伪静态时修正 RewriteBase 或 Nginx location 前缀
  • 更新缓存后再测

后台无法登录

  • 确认使用的是重命名后的入口文件
  • 清除浏览器 Cookie 后重试
  • 检查数据库用户表管理员是否安装成功

前台 500 / 白屏

  • 开启开发者模式排查(见 开发准备工作
  • 确认 system/config.php 数据库信息正确
  • PHP 版本过低或缺少扩展时,安装后也可能在个别页面报错

从旧版本升级

已有站点不要再跑安装向导。覆盖文件、插件字段迁移与缓存刷新见 升级与更新

开发环境与目录约定见 开发准备工作

升级与更新

本文说明 Hope CMS 程序覆盖升级插件/主题升级数据库字段迁移站点缓存刷新

适用场景速查

场景 推荐做法 详见
覆盖更新核心包 备份 → 覆盖 system/ 等 → 更新缓存 程序升级
插件版本迭代加字段 callback_up() + 幂等 schema 插件更新
主题启用时建表 / 初始化 主题 callback.phpcallback_init() 主题更新
改菜单/标签/分类名后前台未变 后台「更新缓存」 更新缓存
仅刷新某类缓存 $SNAP->refresh([...]) 更新缓存
覆盖更新可能改写 system/。业务扩展请写在 content/plugin/content/theme/,勿改核心后指望下次升级保留。

升级前建议:备份数据库 + 备份 content/upload/ +(可选)整站文件快照。


程序升级

  1. 后台导出或 mysqldump 备份数据库
  2. 备份整站(至少 system/content/、入口 PHP)
  3. 用新版覆盖文件;保留 system/config.php 与本地已改配置
  4. 保留 content/upload/content/cache/install.lock、自定义主题/插件
  5. 登录后台执行 更新缓存;若从 1.0.4 等旧版覆盖升级,可再点 清理旧版残余(或依赖在线升级自动清理)
  6. 抽查:首页、文章、登录、后台写文章、已启用插件

若发行说明要求执行 SQL 或一次性脚本,按说明操作;不要重复跑 install.php

升级后若旧结构主题异常,见 常见问题 · 旧版兼容

清理旧版残余文件

从 HopeCMS 1.0.4 覆盖升级后,旧的 controller / modelbase.php、旧类名 lib 等文件可能仍留在 system/
逻辑见 system/lib/legacy_cleanup.php

  • 在线升级成功后自动执行
  • 也可在后台 设置 → 更新缓存 旁手动「清理旧版残余」

仅删除白名单路径,不会动 config.php、主题、插件、上传目录。


插件更新

插件目录:content/plugin/{插件名}/

生命周期

回调 时机 建议
callback_init() 启用时 建表、初始化 MetaStorage、幂等 schema
callback_up() 更新时 再跑同一 schema 升级函数
callback_rm() 删除时 MetaStorage::deleteAllName('YES');按需 HopeSql::dropTables

启用顺序:加载 {插件}_callback.phpcallback_init()不会自动执行 install.sql)。

推荐写法

// tips_callback.php
function callback_up() {
    callback_init();
}
function callback_init() {
    // 有表时:myplugin_upgrade_schema();
}
function callback_rm() {
    MetaStorage::getInstance('tips')->deleteAllName('YES');
}

有表插件将 CREATE + ALTER 放在同一升级函数。完整示例见 数据库与 SQL

字段升级原则

  1. 建表用 CREATE TABLE IF NOT EXISTS
  2. 新字段先 SHOW COLUMNSALTER(可重复执行)
  3. callback_initcallback_up 调用同一函数
  4. 禁止改核心表结构(articleuseroption 等)

主题更新

  • 建表 / 初始化:主题根目录 callback.phpcallback_init()(删除时 callback_rm()
  • CSF settings.php 增删字段后,读取必须带默认值:hope_option('key', 'default') / _hope()
  • 新增 pages/*.php 页面模板后:后台新建页面并选择该模板
  • $prefix(如 default_options不要随意改名,否则已保存配置失效

主题结构见 主题开发指南


更新缓存

后台:设置 → 数据 → 更新缓存(或系统设置中的「更新缓存」入口)。

会做什么

全量 SnapshotBank::refresh()(全局实例常为 $SNAP),重建包括但不限于:

optionsuserstacommenttagscategorylinkmenunewlogrecordlogaliaslogcategorylogtags

并调用 Settings::resetRoutingTableCache() 清空伪静态路由表内存缓存(保存「设置 → 链接」时也会重置)。

菜单标题同步

刷新 menu 时会同步文章 / 页面 / 分类 / 标签类型菜单项标题为来源最新名称;自定义链接名不受影响。

改了标签名、分类名或文章标题后,点一次「更新缓存」即可让导航跟上。

代码中局部刷新

global $SNAP;
$SNAP = SnapshotBank::getInstance();

$SNAP->refresh();                                // 全量
$SNAP->refresh(['tags', 'menu', 'category']);    // 指定
$SNAP->refreshPosts();                           // 文章相关常用组合

缓存文件在 content/cache/*.php;请确保目录可写。


开发自检清单

  • [ ] 插件 / 主题 Version 头信息已递增
  • [ ] 新表与新字段在幂等升级函数中(callback_init / callback_up
  • [ ] callback_rm 已清理 MetaStorage;有表则明确是否 DROP
  • [ ] 未改核心表结构与 system/ 业务文件
  • [ ] 主题新配置均有默认值;$prefix 未误改
  • [ ] 升级前已备份;升级后已「更新缓存」并抽查前台

相关文档

常见问题

集中说明安装、升级与二次开发中的常见疑惑。旧主题 / 旧插件兼容说明只在本文维护,其它章节不再重复。

相关:安装指南 · 升级与更新 · 主题开发指南 · 插件开发指南


安装与后台

打开 install.php 空白 / 报错

  • 检查 PHP 版本与必装扩展(见 安装指南
  • 查看 content/cache/error.log 或 Web 服务器错误日志
  • 确认未误删 system/content/ 关键文件

安装后无法进后台

  • 确认已删除或重命名根目录 install.php
  • 入口默认为 admin.php;若已改名,请使用新文件名
  • 清除浏览器缓存后重试

前台样式丢失 / 链接异常

  • 后台 设置 → 更新缓存
  • 检查「设置 → 链接」模式是否与服务器伪静态配置一致(见 伪静态与路由

升级后仍看到旧报错 / 旧类文件

从 1.0.4 覆盖升级后,可用后台 设置 → 清理旧版残余system/lib/legacy_cleanup.php)删除废弃的 controller/model 等文件;在线升级成功时也会自动清理。


旧版兼容(legacy_compat)

内核只认主题与 API 的新规范。需要继续跑旧结构主题,或仍使用旧函数/类名的第三方插件时,启用插件 「旧版兼容」content/plugin/legacy_compat/)。

defaulthopecms 等已迁移主题,以及已改用现行 API 的插件,不必启用。

何时启用

场景 是否需要
zib / Shop / fly 等仍用 header.phplog_list.phppage/user/ 的主题 需要
第三方插件仍写 addAction / Option / View / Cache::readCache 需要
仅用已迁移主题 + 现行 API 插件 不必

怎么启用

  1. 后台 插件 → 插件管理 启用「旧版兼容」
  2. 启用时会自动排到 active_plugins 最前,保证其它旧插件加载前垫片已就绪
  3. 再启用或切换旧结构主题;执行一次 更新缓存

升级程序后若旧主题突然空白或找不到模板:优先检查本插件是否仍启用。

旧主题路径对照

旧(需启用本插件)
head.php / foot.php header.php / footer.php
archive.php / single.php log_list.php / echo_log.php
archive_* / single_* log_list_* / echo_log_*
author.php log_author.php
functions.php / settings.php / hooks.php module.php / options.php / plugins.php
pages/ / account/ page/ / user/
widgets/config.phpwidget-*.php side_config.phpside_*.php

Handler 仍可使用逻辑名 headerlog_listecho_log 等,内核映射到新文件;旧物理文件由本插件注入候选路径。

旧插件 API 对照(节选)

现行
addAction / doAction / doMultiAction hope_listen / hope_emit / hope_emit_pipe
$hopeHooks $hopeEvents
Option Settings
View::getView PageComposer::themePath
Url::log / Url::sort SiteUrl::post / SiteUrl::category
Cache + readCache / updateCache SnapshotBank + read / refresh
$CACHE Cache 代理($SNAP 仍为 SnapshotBank)
Storage / Database / LoginAuth MetaStorage / HopeDb / AuthSession
PLUGIN_PATH / TPLS_PATH HOPE_PLUGINS_PATH / HOPE_THEMES_PATH

完整对照表:content/plugin/legacy_compat/naming_map.php。插件说明:content/plugin/legacy_compat/README.md

新项目要不要写旧名?

不要。新主题按 head.php / archive.php / pages/ / account/ / widgets/ 规范编写;新插件直接使用 hope_listenSettingsHopeDb 等现行 API。


主题与插件开发

主题设置页不出现

主题根目录需有 settings.php(CSF)。确认当前主题已启用,并刷新后台菜单。

侧边栏组件不显示

  • 确认 widgets/config.php 已注册对应 side_* key
  • 确认存在 widgets/widget-{name}.php
  • 换主题后到 外观 → 侧边栏 重新勾选组件

插件启用后无效果

  • 确认入口文件头信息与目录名一致
  • 钩子是否写在入口或 *_lib.php 且已被 require
  • 查看是否与其它插件互斥;需要时检查 content/cache/error.log

更多

目录总览见 目录说明。反馈渠道见 联系我们

目录说明

Hope CMS 根目录只保留两个文件夹:content/(内容区)与 system/(程序区),外加少量入口文件。

相关:开发准备工作 · 常见问题


根目录

hope/
├── index.php      # 前台入口 → system/bootstrap.php
├── admin.php      # 后台入口 → system/bootstrap.php
├── install.php    # 安装向导
├── content/       # 主题、插件、上传、缓存等可变内容
└── system/        # 内核、业务、后台逻辑、公共库
文件 / 目录 说明
index.php 前台统一入口
admin.php 后台统一入口
install.php 首次安装(库表 SQL 内嵌)
content/ 站点内容与扩展(升级主题/插件主要改这里)
system/ 程序核心(一般升级程序改这里)

content/ — 内容区

content/
├── theme/       # 前台主题
├── plugin/      # 插件
├── admin/       # 后台视图(HTML / CSS / JS)
├── upload/      # 用户上传文件
├── cache/       # 运行时缓存(配置、分类、统计等)
├── lang/        # 语言包
├── logs/        # 日志
├── static/      # 静态资源
└── theme_ref/   # 主题参考材料(非运行必需)
目录 作用
theme/ 可切换的前台主题,当前主题由站点配置决定
plugin/ 可启用/停用的插件
admin/ 后台界面模板与静态资源,与 system/admin 控制器配合
upload/ 媒体与附件存储
cache/ PHP 数组缓存文件,加速读写
lang/ 多语言文案
logs/ 运行/审计日志
static/ 公共静态文件
theme_ref/ 参考或备份主题资源,默认不参与运行

站内开发文档位于当前主题 content/theme/hopecms/docs/


system/ — 程序区

system/
├── Hope/            # 内核命名空间:启动、路由、配置、事件
├── app/             # 业务分层:handler / store / service
├── admin/           # 后台控制器
├── lib/             # 公共库
├── options/         # 主题选项框架(Codestar)
├── deploy/          # 部署示例(如 nginx)
├── bootstrap.php    # 内核引导(前台 / 后台共用)
├── config.php       # 数据库等站点配置
└── checkcode.php    # 验证码兼容入口

system/Hope/ — 内核

system/Hope/
├── Foundation/            # Application、Paths、ClassLoader、path_constants
├── Bootstrap/             # RuntimeBoot 启动编排
├── Http/                  # FrontRouter、Request、RouteMatch
├── Config/                # Settings 站点配置
├── Runtime/               # SnapshotBank 快照缓存
├── Presentation/          # PageComposer 视图路径解析
└── Event/                 # HookBus 事件总线

system/app/ — 业务分层

目录 角色 示例
handler/ 前台请求处理 Post_HandlerCategory_HandlerUser_Handler
store/ 数据访问 Post_StoreComment_StoreUser_Store
service/ 领域服务 UserServiceNoticeServiceMediaService

system/admin/ — 后台控制器

按功能拆分,例如:article.phparticle_edit.phpcomment.phpsetting.phptheme.phpplugin.php 等。
视图在 content/admin/

system/lib/ — 公共库

lib/
├── auth/          # 登录会话、密码、授权
├── database/      # HopeDb / HopeMysqli / 查询与元存储
├── http/          # 请求输入、站点 URL、JSON 输出、HTTP 客户端
├── mail/          # 邮件发送
├── payment/       # 支付通道与收银台
├── captcha/       # 验证码与字体
├── markdown/      # Markdown 解析
├── support/       # 语言、异常等支撑
├── view/          # 侧栏日历、应用商店视图 helpers
├── common.php     # 全局辅助函数
├── hooks.php      # 钩子常量
├── sidebar.php    # 侧栏注册与渲染
└── upgrade_helper.php

其他

路径 说明
system/options/ 主题选项 UI 框架(CSF)
install.php(根目录) 安装向导;库表 SQL 已内嵌于 hope_install_schema_template()
system/deploy/ 部署配置示例
content/plugin/legacy_compat/naming_map.php 旧命名 → 新命名对照(说明见 常见问题
system/config.php DB_*、表前缀、密钥等

请求流程

前台

index.php
  → system/bootstrap.php
  → Application 启动
  → FrontRouter 匹配路由
  → app/handler/*
  → content/theme/<当前主题>/

后台

admin.php
  → system/bootstrap.php(加载内核)
  → system/admin/globals.php
  → system/admin/<act>.php
  → content/admin/<act>.php(视图)

记忆口诀

  • content:装什么(主题、插件、文件、缓存)
  • system:怎么跑(内核、业务、后台、公共库)

二次开发时:改界面与扩展优先看 content/;改路由、保存逻辑、权限与数据层优先看 system/

开发准备工作

Hope CMS 支持主题与插件扩展。本文说明本地环境、目录约定、请求流程与常用 API,便于二次开发。

相关:挂载点手册 · 主题开发指南 · 插件开发指南 · 数据库与 SQL


开发环境

项目 要求
PHP 7.0+(建议同时测试 8.0 / 8.3
MySQL 5.6+ / MariaDB 10.3+
Web Apache / Nginx
扩展 mysqlipdo_mysql;建议 mbstringjsoncurl
浏览器 Chrome / Edge 等现代浏览器

将站点根目录(含 index.php)设为 Web 根目录,并确保 content/upload/content/cache/ 可写。


目录结构

根目录只保留 content/(内容区)与 system/(程序区),外加入口文件:

hope/                              # 站点根(HOPE_ROOT)
├── index.php                      # 前台入口
├── admin.php                      # 后台入口
├── install.php                    # 安装向导(库表 SQL 内嵌)
├── system/                        # 内核(升级会覆盖,勿直接改业务)
│   ├── Hope/                      # Foundation / Bootstrap / Http / Config / Runtime / Presentation / Event
│   ├── app/
│   │   ├── handler/               # 前台请求处理(*_Handler)
│   │   ├── store/                 # 数据访问(*_Store)
│   │   └── service/               # 领域服务
│   ├── admin/                     # 后台控制器(与 content/admin 视图配对)
│   ├── lib/                       # 公共库(common.php、hooks.php、sidebar.php、database/、http/…)
│   ├── options/                   # 主题选项框架(CSF)
│   ├── bootstrap.php              # 内核引导
│   └── config.php                 # 数据库、AUTH_KEY 等
└── content/                       # ★ 开发者主要工作区
    ├── theme/                     # 主题
    ├── plugin/                    # 插件
    ├── admin/                     # 后台 HTML / CSS / JS
    ├── upload/                    # 用户上传
    ├── cache/                     # 运行时缓存
    ├── lang/                      # 语言包
    └── logs/                      # 日志

记忆口诀: content 装什么;system 怎么跑。

完整说明见 目录说明


快速上手:示例插件

官方示例: content/plugin/tips/

  1. 复制 tips 目录并改名,修改 Plugin Name 与函数前缀
  2. 后台 插件 → 插件管理 启用
  3. 启用时加载 {插件}_callback.php 并调用 callback_init()
// tips.php
hope_listen('adm_main_top', 'tips_render_admin_banner');
hope_listen('adm_head', 'tips_enqueue_admin_css');

// tips_callback.php
function callback_init() { /* 启用即生效 */ }
function callback_rm() {
    MetaStorage::getInstance('tips')->deleteAllName('YES');
}

完整说明见 插件开发指南


快速上手:示例主题

官方示例: content/theme/default/

  1. 复制 default 为新主题目录,修改 head.php 元信息与 settings.php$prefix
  2. pages/ 下新建页面模板,首行写 /*@name 关于我们*/
  3. 后台 页面 → 新建页面,选择对应模板
  4. 布局参考同主题 head.php / foot.php
<?php
/*@name 关于我们*/
defined('HOPE_ROOT') || exit('access denied!');
?>
<section class="about">
    <h1><?= htmlspecialchars((string) Settings::get('sitename')) ?></h1>
</section>
<?php include PageComposer::themePath('footer'); ?>

文件清单、CSF、模板变量见 主题开发指南


请求流程

入口 流程
前台 index.php bootstrap.php → Application → 加载插件 → include 主题 hooks.phphope_emit('init')FrontRouter*_Handler → 主题模板
后台 admin.php bootstrap.phpsystem/admin/globals.phpact 分发 → system/admin/{act}.phpcontent/admin/{act}.php
REST API ?rest-api=方法名 → API Handler → JsonOut::ok() / JsonOut::error()
插件设置页 {后台入口}?act=plugin_set&plugin=插件名{插件}_setting.phpplugin_setting_view()

插件可通过 HopeHooks::ROUTING_REGISTER 注册前台伪静态路由,见 伪静态与路由


常用常量

常量 说明
HOPE_ROOT 站点根目录绝对路径(含尾 /
DB_PREFIX 表前缀(system/config.php
SITE_URL 站点 URL(含末尾 /
THEME_PATH / THEME_URL 当前主题物理路径 / URL
HOPE_THEMES_PATH / HOPE_THEMES_URL 主题根目录
HOPE_PLUGINS_PATH / HOPE_PLUGINS_URL 插件根目录
ADMIN_TEMPLATE_PATH 后台视图目录(content/admin/
ISLOGIN / UID / ROLE 登录态、用户 ID、角色

路径常量:HOPE_PATH_APPHOPE_PATH_STOREHOPE_PATH_HANDLERHOPE_PATH_SERVICEHOPE_PATH_ADMINHOPE_PATH_LIBRARY


用户角色

常量 典型权限
ROLE_ADMIN admin 全部后台权限
ROLE_EDITOR editor 管理内容与评论
ROLE_WRITER writer 管理自己的文章
ROLE_VISITOR visitor 前台只读

插件后台页由核心保障管理员权限;独立 AJAX 需自行校验:

if (!AuthSession::isLogin() || ROLE !== ROLE_ADMIN) {
    JsonOut::authError('权限不足');
}

挂载点(速览)

hope_listen(HopeHooks::ADM_HEAD, 'tips_enqueue_admin_css');
hope_listen(HopeHooks::ADM_MAIN_TOP, 'tips_render_admin_banner');
hope_emit(HopeHooks::INDEX_HEAD);
函数 行为
hope_listen($hook, $callback) 注册
hope_emit($hook, ...) 执行全部回调
hope_emit_once($hook, $input, &$ret) 仅第一个,可改 $ret
hope_emit_pipe($hook, $input, &$ret) 链式变换 $ret
hope_unlisten / hope_has_listener 移除 / 判断

完整列表见 挂载点手册。常量源码:system/lib/hooks.php


配置与选项

系统设置

$sitename = Settings::get('sitename');
Settings::updateOption('apikey', $key);
Settings::updateOption('is_openapi', 'y');

主题配置(CSF)

$color = hope_option('primary_color', '#3b82f6');
$layout = _hope('site_layout', 'double');

站点标题等请用 Settings::get('sitename') / hope_site_name()

插件私有配置

$storage = MetaStorage::getInstance('tips');
$storage->setValue('config', ['foo' => 'bar'], 'array');
$config = $storage->getValue('config');
$storage->deleteAllName('YES'); // 卸载时

输入输出

$id   = RequestInput::getIntVar('id');
$page = RequestInput::getIntVar('page', 1, 1);
$name = RequestInput::postStrVar('name');
$pwd  = RequestInput::postRawStr('password');

JsonOut::ok(['list' => $rows]);
JsonOut::error('参数错误');
JsonOut::authError('未登录');

hope_abort('权限不足', './');

模板与 URL

include PageComposer::themePath('header');     // → head.php
include PageComposer::themePath('log_list');   // → archive.php
include PageComposer::themePath('pages/about'); // 独立页模板
include PageComposer::userPath('index');       // account/

SiteUrl::post($gid);
SiteUrl::category($sid);
SiteUrl::tag($tagname);
SiteUrl::plugin('tips', ['id' => 1]);
SiteUrl::userCenter(['api' => 1]);

URL 规则受后台「设置 → 链接」影响,见 伪静态与路由


命名迁移速查

现行
Option Settings
View::getView PageComposer::themePath
Url:: / Url::log SiteUrl:: / SiteUrl::post
addAction / doAction hope_listen / hope_emit
Database / Storage HopeDb / MetaStorage
Cache / $CACHE SnapshotBank / $SNAP
Input / Output RequestInput / JsonOut
LoginAuth AuthSession
*_Controller / *_Model *_Handler / *_Store

完整对照与运行时垫片见 常见问题 · 旧版兼容


开发规范

  • PHP 遵循 PSR-1PSR-12
  • 文件开头:defined('HOPE_ROOT') || exit('access denied!');
  • 主题配置用 hope_option / _hope,始终带默认值
  • 禁止在业务里 HopeDb::getInstance()->query() 拼接不可信输入
  • 输出用户内容用 htmlspecialchars / hope_html_clean

开启开发者模式

方式一:system/config.php 末尾:

const ENVIRONMENT = 'develop';

方式二: 后台开启「调试模式」。

上线前请改回 production 并关闭调试。错误日志多在 content/cache/error.logcontent/logs/


下一步

挂载点手册

Hope CMS 通过挂载点(Hook)在不改核心的前提下扩展功能。常量定义于 system/lib/hooks.phpHopeHooks),注册/触发 API 在 system/lib/common.php

相关:开发准备工作 · 插件开发指南 · 伪静态与路由


API 一览

// 注册(推荐常量)
hope_listen(HopeHooks::INDEX_HEAD, 'myplugin_head_css');
hope_listen('adm_main_top', 'tips_render_admin_banner'); // 字符串亦可

// 触发
hope_emit(HopeHooks::INDEX_HEAD);
hope_emit(HopeHooks::SAVE_LOG, $gid, $logData);
函数 行为 典型场景
hope_listen($hook, $callback) 注册回调 插件入口
hope_emit($hook, ...$args) 执行该点全部回调 输出 CSS/JS、记日志
hope_emit_once($hook, $input, &$ret) 第一个回调,可改 $ret 接管上传、用户中心 API
hope_emit_pipe($hook, $input, &$ret) 链式执行,逐级变换 $ret 正文过滤
hope_unlisten($hook, $callback) 移除回调 调试 / 互斥
hope_has_listener($hook, $callback) 是否已注册 条件注册

约定:

  • 回调内输出用户内容用 htmlspecialchars
  • 需要 JSON 中断时用 JsonOut::* / hope_abort(),避免半截 HTML
  • 函数名加插件/主题前缀,避免冲突

启动与路由

常量 字符串 说明
HopeHooks::INIT init 插件与主题 hooks.php 加载完成后
HopeHooks::ROUTE_DISPATCH route_dispatch 路由分发前(model, method, params)
HopeHooks::ROUTING_REGISTER routing_register 路由表构建后扩展(hope_emit_pipe,可追加规则)
HopeHooks::PAGE_NOT_FOUND page_not_found 404 页
hope_listen(HopeHooks::ROUTING_REGISTER, 'myplugin_register_routes');

详见 伪静态与路由


前台页面

常量 字符串 建议埋点位置
INDEX_HEAD index_head </head>
INDEX_BODY_START index_body_start <body>
INDEX_SIDEBAR index_sidebar 侧边栏 widgets 之前
INDEX_FOOTER index_footer 页脚脚本前
INDEX_BODY_END index_body_end </body>

主题模板负责 hope_emit(...),插件负责 hope_listen(...)


文章与评论

常量 字符串 参数 / 说明
LOG_VIEW log_view 文章页渲染前(logid, logData)
ARTICLE_CONTENT_ECHO article_content_echo 正文输出前过滤(hope_emit_pipe
LOG_RELATED log_related 相关推荐 / 扩展区
LOG_DIRECT_LINK log_direct_link 外链跳转前
SAVE_LOG save_log 文章/页面保存后
DEL_LOG del_log 文章/页面删除后
COMMENT_FORM comment_form 评论表单区
COMMENT_POST comment_post 评论提交前
COMMENT_SAVED comment_saved 评论保存后
COMMENT_REPLY comment_reply 后台回复评论后
POST_COMMENT post_comment 前台评论发布成功
POST_NOTE post_note 微语/笔记发布
hope_listen(HopeHooks::ARTICLE_CONTENT_ECHO, function ($content, &$ret) {
    $ret = str_replace('foo', 'bar', $ret ?: $content);
});

用户与登录

常量 字符串 说明
USER_MENU user_menu 用户中心侧栏扩展
USER_CENTER_API user_center_api 个人中心 API(hope_emit_once,可接管 action)
LOGIN_HEAD login_head 登录页 head
LOGIN_EXT login_ext 登录表单扩展
LOGIN_SUCCESS login_success 登录成功
SIGNUP_EXT signup_ext 注册表单扩展
hope_listen(HopeHooks::USER_MENU, function () {
    echo '<a href="' . htmlspecialchars(SiteUrl::plugin('myplugin')) . '">我的扩展</a>';
});

后台

常量 字符串 说明
ADM_HEAD adm_head 后台 <head>
ADM_FOOTER adm_footer 后台页脚
ADM_MAIN_TOP adm_main_top 后台首页顶部(如 tips 横幅)
ADM_MAIN_BOTTOM adm_main_bottom 后台首页底部
ADM_MENU adm_menu 侧栏菜单项(靠前)
ADM_MENU_EXT adm_menu_ext 侧栏菜单末尾
ADM_WRITELOG_BAR adm_writelog_bar 写文章工具栏
ADM_WRITELOG_TITLE adm_writelog_title 写文章标题旁扩展
ADM_COMMENT_DISPLAY adm_comment_display 评论列表扩展
ADM_LINK_DISPLAY adm_link_display 链接列表扩展
ADM_USER_DISPLAY adm_user_display 用户列表行($user
ADM_USER_FORM adm_user_form 用户编辑表单
hope_listen(HopeHooks::ADM_MENU_EXT, function () {
    echo '<li><a href="./?act=plugin_set&plugin=myplugin">我的插件</a></li>';
});

具体菜单 HTML 请对照当前后台模板。


用户管理事件

常量 字符串 参数
ADD_USER add_user uid, userData
UPDATE_USER update_user uid, userData
DEL_USER del_user uid
FORBID_USER forbid_user uid
UNFORBID_USER unforbid_user uid

媒体与下载

常量 字符串 说明
UPLOAD_MEDIA upload_media 附件上传(常配合 hope_emit_once 接管)
DEL_MEDIA del_media 附件删除
ATTACH_UPLOAD attach_upload 编辑器附件上传
DOWNLOAD_RESOURCE download_resource 资源下载

分类、设置与插件生命周期

常量 字符串 说明
SAVE_CATEGORY / DEL_CATEGORY save_category / del_category 分类保存 / 删除后
SAVE_SETTING save_setting 系统设置保存后
PLUGIN_ACTIVE plugin_active 插件启用
PLUGIN_INACTIVE plugin_inactive 插件停用
PLUGIN_DELETED plugin_deleted 插件删除
LANG_LOADED lang_loaded 语言包加载后
GET_GRAVATAR get_Gravatar Gravatar 地址(hope_emit_once

示例:最小可用

// myplugin.php
hope_listen(HopeHooks::ADM_HEAD, 'myplugin_admin_css');
hope_listen(HopeHooks::SAVE_LOG, 'myplugin_on_save');

function myplugin_admin_css() {
    echo '<link rel="stylesheet" href="' . HOPE_PLUGINS_URL . 'myplugin/assets/admin.css">' . "\n";
}

function myplugin_on_save($gid, $data = null) {
    // 文章保存后的业务逻辑
}

源码常量以 system/lib/hooks.php 为准;本页与代码不一致时以代码为准。

数据库与 SQL

Hope CMS 使用 MySQL / MariaDB。业务访问统一通过 HopeDbHopeSql 完成。

  • 生命周期 / MetaStorage:对照示例插件 tips
  • 自建表:对照 oauthvideomusic*_upgrade_schema() / callback_init()

相关:插件开发指南 · 升级与更新


核心类与文件

路径 说明
HopeDb system/lib/database/hope_db.php 数据库入口,链式查询与快捷方法
HopeQuery system/lib/database/hope_query.php 链式查询构建器
HopeSql system/lib/database/hope_sql.php SQL 文件读取与批量执行
MetaStorage system/lib/database/meta_storage.php 插件键值存储(hope_storage 表)
HopeMysqli / HopePdo 同目录 底层驱动

表前缀

const DB_PREFIX = 'hope_'; // system/config.php

约定:

  • HopeDb::table('article') 不要手动加前缀,框架会拼为 hope_article
  • 原生 SQL 可拼接 DB_PREFIX,或在 HopeSql / HopeDb::executeFile 中使用 {db_prefix}
  • 少数场景:DB_PREFIX . 'myplugin_log'

链式查询(推荐)

$rows = HopeDb::table('myplugin_log')
    ->where(['status' => 1, 'uid' => $uid])
    ->whereLike('title', $keyword)
    ->whereIn('id', $ids)
    ->order('id DESC')
    ->limit(20, 0)
    ->findAll();

$row = HopeDb::table('myplugin_log')->where(['id' => $id])->find();

$total = HopeDb::table('myplugin_log')->where(['status' => 1])->count();

$list = HopeDb::table('myplugin_log', 'l')
    ->select(['l.id', 'l.title', 'u.nickname'])
    ->leftJoin('user', 'u', 'l.uid = u.uid')
    ->where(['l.status' => 1])
    ->order('l.id DESC')
    ->limit(10)
    ->findAll();

链式方法一览

方法 说明
select($fields) 指定字段
where($condition) 数组或字符串条件
whereRaw($sql) 原生 WHERE 片段
whereIn / whereLike IN / 模糊
join / leftJoin 表关联
order / limit / group 排序、分页、分组
findAll / find 多行 / 单行
insert / update / delete / count 写与计数

快捷方法

HopeDb::select('article', ['hide' => 'n']);
HopeDb::getOne('user', ['uid' => 1]);
HopeDb::insert('myplugin_log', ['title' => '示例', 'status' => 1]);
HopeDb::update('myplugin_log', ['id' => 1], ['status' => 0]);
HopeDb::delete('myplugin_log', ['id' => 1]);
HopeDb::count('myplugin_log', ['status' => 1]);

原生 SQL

$rows = HopeDb::fetchAll(
    'SELECT * FROM `' . DB_PREFIX . 'myplugin_log` WHERE uid = ' . (int) $uid
);

$row = HopeDb::fetchOne('SELECT COUNT(*) AS cnt FROM `' . DB_PREFIX . 'myplugin_log`');

HopeDb::execute('UPDATE `' . DB_PREFIX . 'myplugin_log` SET views = views + 1 WHERE id = ' . (int) $id);

$safe = HopeDb::escape($keyword);
优先链式 where / whereLike;原生 SQL 中数值 (int),字符串务必 HopeDb::escape()

插件/主题建表(callback_init)

不再使用目录下的 install.sql 自动执行。启用时核心只调用 callback_init()

function myplugin_upgrade_schema() {
    $table = DB_PREFIX . 'myplugin_log';
    if (HopeDb::fetchOne("SHOW TABLES LIKE '{$table}'")) {
        return;
    }
    HopeDb::execute("CREATE TABLE IF NOT EXISTS `{$table}` (
        `id` int unsigned NOT NULL AUTO_INCREMENT,
        `title` varchar(255) NOT NULL DEFAULT '',
        `uid` int unsigned NOT NULL DEFAULT 0,
        `status` tinyint NOT NULL DEFAULT 1,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", true);
}

function callback_init() {
    myplugin_upgrade_schema();
}

function callback_rm() {
    MetaStorage::getInstance('myplugin')->deleteAllName('YES');
    HopeSql::dropTables(['myplugin_log']);
}

何时执行

时机 调用
插件启用 callback_init()
主题启用 主题 callback.phpcallback_init()
插件升级 callback_up()(通常再调同一 upgrade)
手动 SQL 文件 HopeDb::executeFile / HopeSql::executeFile

HopeSql 高级选项

HopeSql::executeFile(HOPE_ROOT . 'path/to/custom.sql', [
    'replace_prefix' => true,
    'ignore_error'   => false,
    'charset_setup'  => false,
    'version_gate'   => false,
]);

HopeSql::dropTables(['table_a', 'table_b']):逻辑表名(不含前缀)批量 DROP。


字段升级(Schema Migration)

function myplugin_upgrade_schema_fields() {
    static $done = false;
    if ($done) return;
    $done = true;

    $table = DB_PREFIX . 'myplugin_log';
    HopeDb::execute("CREATE TABLE IF NOT EXISTS `{$table}` (...)", true);

    $existing = [];
    foreach (HopeDb::fetchAll("SHOW COLUMNS FROM `{$table}`") as $col) {
        $existing[$col['Field']] = true;
    }

    if (empty($existing['new_field'])) {
        HopeDb::execute(
            "ALTER TABLE `{$table}` ADD COLUMN `new_field` varchar(100) NOT NULL DEFAULT ''",
            true
        );
    }
}

callback_init() / callback_up() 中调用同一函数即可。


MetaStorage 插件存储

$storage = MetaStorage::getInstance('tips');

$storage->setValue('config', [
    'enabled' => 'y',
    'per_page' => 20,
], 'array');

$config = $storage->getValue('config');
$storage->deleteAllName('YES');

适合开关、JSON 配置、计数;列表/关联数据请自建表。


系统核心表(只读参考)

不得修改以下核心表结构,仅可通过 Store / API 读写:

逻辑名 实际表名 说明
article hope_article 文章/页面
user hope_user 用户
comment hope_comment 评论
sort / category 视版本 分类
tag hope_tag 标签
media hope_media 附件
option hope_option 系统配置
storage hope_storage 插件键值存储
pay_order hope_pay_order 支付订单

插件自建表命名建议:{DB_PREFIX}{插件名}_{用途},如 hope_oauth_bind


开发建议

  1. 生命周期 → 先写好 callback_* 与 MetaStorage
  2. 新建表callback_init / *_upgrade_schema()
  3. 加字段 → 同一升级函数内 SHOW COLUMNS + ALTER
  4. 日常查询 → 优先 HopeDb::table() 链式
  5. 复杂 SQLfetchAll / fetchOne / execute,注意转义
  6. 卸载清理callback_rm() 必须清 MetaStorage;有表则明确是否 DROP

主题开发指南

主题位于 content/theme/{主题目录}/。启用后前台页面由该目录下的 PHP 模板渲染。

官方示例主题:content/theme/default/。学习列表页、侧边栏、用户中心、CSF 设置时优先对照此主题。

相关文档:开发准备工作 · 挂载点手册 · 侧边栏开发说明 · 伪静态与路由 · 数据库与 SQL

站内「主题生成器」页可拼装主题 PHP 片段(输出适配现行 Hope CMS API)。


1. 从零创建主题

  1. 复制 content/theme/default/content/theme/你的主题/
  2. 修改 head.php 顶部 Theme Name / Version / Description
  3. 修改 settings.php$prefix(如 yourtheme_options)与标题文案
  4. functions.php 中函数前缀(如 nova_*)改为自己的命名空间,避免冲突
  5. 后台 外观 → 主题 启用;如有 callback.php,启用时会执行 callback_init()
  6. 建议执行一次 设置 → 更新缓存
  7. 外观 → 侧边栏 检查组件是否仍可用
不要直接改正在线上使用的主题;复制一份再改,便于回滚。

2. 目录结构

官方 default 采用下列命名(推荐新主题照此创建):

content/theme/default/
├── head.php               # 必需:主题元信息 + HTML 头部
├── foot.php               # 必需:页脚与闭合标签
├── archive.php            # 必需:首页 / 分类 / 标签 / 搜索 / 归档列表
├── single.php             # 必需:文章详情
├── 404.php                # 推荐:404 页
├── functions.php          # 推荐:主题函数库(模板中 require)
├── settings.php           # 可选:CSF 主题设置
├── hooks.php              # 可选:主题级钩子(每请求自动 include)
├── callback.php           # 可选:启用 / 删除 / 升级回调
├── preview.png            # 推荐:后台主题列表预览图
├── widgets/               # 可选:侧边栏
│   ├── sidebar.php
│   ├── config.php         # 组件注册表(注册 key 仍可用 side_*)
│   └── widget-*.php       # 如 widget-blogger.php
├── pages/                 # 可选:独立页面模板
│   └── page.php
├── account/               # 可选:登录 / 注册 / 用户中心
│   ├── index.php
│   ├── login.php
│   ├── register.php
│   ├── auth.php
│   └── profile.php
├── partials/              # 可选:可复用片段
└── assets/                # 静态资源
    ├── css/
    ├── img/
    └── js/

最小可运行主题

至少需要:head.phpfoot.phparchive.phpsingle.php。其余按需增加。


3. 主题元信息

写在 head.php 文件最顶部的注释块,后台主题列表会解析:

<?php
/*
Theme Name: 默认主题
Theme Type: cms
Theme Url: http://www.hopecms.cn
Author: Hope CMS
Author Url: http://www.hopecms.cn
Version: 1.0.0
Description: Hope CMS 默认主题:大标题首页、双栏列表、标签云侧栏与个人中心。
*/
defined('HOPE_ROOT') || exit('access denied!');
require_once PageComposer::themePath('module'); // → functions.php
字段 说明
Theme Name 后台显示名称(必需)
Version 版本号
Description 简介
Theme Type 可选分类关键词(见下表);可写多个,后台按匹配显示中文标签
Author / Theme Url 作者与主题主页

Theme Type 与后台展示对应关系(Theme_Store):

写入值(英文关键词) 后台显示
cms 博客
music 音乐
video 视频
forum 论坛

示例:Theme Type: cms → 显示「博客」;Theme Type: cms video → 显示「博客.视频」。


4. 核心模板与变量

控制器先 include PageComposer::themePath('header'),再 include 列表或详情模板;模板内再 include footer(逻辑名;物理文件可为 head.php / foot.php)。

4.1 列表页 archive.php(逻辑名 log_list

用于首页、分类、标签、搜索、日期归档、作者页等。

变量 说明
$logs 当前页文章数组
$lognum 符合条件的文章总数
$page / $index_lognum / $pageurl 分页参数
$sortName / $sort 分类名 / 分类信息(分类页)
$tag 标签名(标签页)
$keyword 搜索关键词(搜索页)
$record 归档年月(归档页)
$author_name 作者展示名(作者页)
$page_html = hope_pagination($lognum, $index_lognum, $page, $pageurl);
foreach ($logs as $value) {
    // $value['gid'] $value['log_title'] $value['log_cover'] ...
    echo '<a href="' . SiteUrl::post($value['gid']) . '">'
        . htmlspecialchars($value['log_title']) . '</a>';
}

列表变体(可选):archive_card.php / archive_grid.php / archive_seamless.php,可由主题设置切换;薄封装内通常 include PageComposer::themePath('archive')

4.2 详情页 single.php(逻辑名 echo_log

变量 说明
$logid / $gid 文章 ID
$log_title / $log_content 标题 / 正文 HTML
$log_cover 封面图 URL
$date / $views / $comnum 时间戳 / 阅读 / 评论数
$author / $sortid / $tags 作者 UID / 分类 ID / 标签 ID 串
$neighborLog 上一篇 / 下一篇
$password 访问密码(有则需校验)
<?php include PageComposer::themePath('sidebar'); ?>
<?php include PageComposer::themePath('footer'); ?>

4.3 head.php / foot.php 常用变量

变量 说明
$site_title 当前页 <title>
$site_key / $site_description SEO keywords / description
$sitename 站点名(系统设置)

头部 / 页脚应输出挂载点:

<?php hope_emit('index_head'); ?>
<?php hope_emit('index_footer'); ?>

站点标题请读系统设置,例如:

htmlspecialchars((string) Settings::get('sitename'));
// 或主题助手:hope_site_name() / hope_site_info()

5. 自定义页面

后台创建「页面」时可选择模板,文件放在 pages/

<?php
/*@name 关于我们*/
defined('HOPE_ROOT') || exit('access denied!');
?>
<main>
    <h1>关于我们</h1>
    <div><?= $log_content ?></div>
</main>
<?php include PageComposer::themePath('footer'); ?>
  • @name 后的文字会出现在后台模板下拉里
  • 页面同样会先加载 head.php(逻辑名 header),模板内记得闭合 footer
  • 复杂站点(如本主题 hopecms)可有多个:page_docs.phppage_download.phppage_generator.php(主题生成器)等

6. functions.php

建议所有主题辅助函数集中在此,并在 head.php 中:

require_once PageComposer::themePath('module'); // 逻辑名 → functions.php
function your_asset($path) {
    $path = ltrim((string) $path, '/');
    if ($path !== '' && strpos($path, 'assets/') !== 0) {
        $path = 'assets/' . $path;
    }
    return THEME_URL . $path;
}

function your_brand() {
    $name = trim((string) Settings::get('sitename'));
    return htmlspecialchars($name !== '' ? $name : 'Hope CMS');
}
常量 说明
THEME_PATH 当前主题物理路径
THEME_URL 当前主题 URL
SITE_URL 站点根 URL(含末尾 /

生成内容链接用核心类,不要手拼规则:

SiteUrl::post($gid);          // 文章
SiteUrl::category($sid);      // 分类
SiteUrl::tag($tagname);       // 标签
SiteUrl::author($uid);        // 作者
SiteUrl::userCenter();        // 个人中心

7. settings.php(主题设置)

主题目录内有 settings.php 时,后台出现主题设置页(Codestar / CSF)。

文件 用途
default/settings.php 可运行起点(精简实用)
content/theme/参考主题配置.php CSF 字段大全(不会自动加载,仅对照拷贝)

约定

说明
$prefix 唯一,推荐 {主题目录}_options设定后勿改
读取 hope_option('字段id', '默认值')_hope()
无文件 无主题设置页,主题仍可正常启用
站点信息 标题 / 副标题 / SEO / 版权走后台「设置」;主题用 Settings::get('sitename') 读取
<?php
if (!defined('HOPE_ROOT')) exit;

$prefix = 'yourtheme_options';

CSF::createOptions($prefix, [
    'plugin_title' => '某某主题设置',
    'footer_text'  => 'Hope CMS',
    'theme'        => 'light', // light | dark | auto
]);

CSF::createSection($prefix, [
    'title'  => '基本设置',
    'icon'   => 'fa fa-cog',
    'fields' => [
        [
            'type'    => 'notice',
            'style'   => 'info',
            'content' => '站点标题、副标题、SEO 描述与页脚版权请在后台「设置 → 站点信息 / SEO 设置」中维护。',
        ],
        [
            'id'      => 'primary_color',
            'type'    => 'color',
            'title'   => '主题色',
            'default' => '#3b82f6',
        ],
        [
            'id'      => 'hero_enable',
            'type'    => 'switcher',
            'title'   => '启用首页 Hero',
            'default' => true,
        ],
    ],
]);

options完整的.php 覆盖:文本、选择、开关、上传、颜色、调色板、repeater/group、accordion/tabbed、code_editor、依赖 dependency、backup 等。

WordPress Codestar 可迁移:API 用 CSF::;读取用 hope_option(),不要用 get_option


8. hooks.php(主题钩子)

每个前台请求在加载已启用插件之后,会自动 include 当前主题的 hooks.php(若存在),再执行 hope_emit('init')

适合:注册主题专属钩子、挂文章自定义字段、改写用户中心菜单等。

<?php
defined('HOPE_ROOT') || exit('access denied!');

hope_listen('index_head', 'yourtheme_extra_css');
hope_listen('user_menu', 'yourtheme_user_menu_item');

9. callback.php(主题生命周期)

函数 时机
callback_init() 主题启用
callback_rm() 主题删除
callback_up() 主题升级后(若实现)

可在启用时建表、写默认配置;删除时清理 MetaStorage / 自建表。建表写法见 数据库与 SQL

<?php
defined('HOPE_ROOT') || exit('access denied!');

function callback_init() {
    // 同步默认配置、建扩展表
}

function callback_rm() {
    // MetaStorage::getInstance('yourtheme')->deleteAllName('YES');
}

10. 侧边栏与用户中心

  • 侧边栏widgets/ + config.php,详见 侧边栏开发说明
  • 用户中心:优先使用主题 account/;若主题未提供,系统可能回退到其它主题的 user/
  • 登录 / 注册页同理,建议主题内自备完整 account/ 目录
include PageComposer::userPath('index');

11. 挂载点(主题侧)

主题模板负责 埋点,插件负责 注册回调

挂载点 建议位置
index_head </head>
index_body_start <body>
index_footer / index_body_end 页脚脚本区
index_sidebar 侧边栏容器内
log_related 文章相关推荐区

完整列表见 挂载点手册


12. 检查清单与注意事项

  1. 不硬编码域名,用 SITE_URLTHEME_URLSiteUrl::*
  2. 输出用户内容用 htmlspecialchars
  3. 勿修改 system/;业务扩展用主题 hooks.php 或独立插件
  4. $prefix 与函数名前缀全局唯一
  5. hope_option / _hope 始终带默认值
  6. SITE_URL 已有尾斜杠,拼接时避免双斜杠
  7. 静态资源建议放在 assets/
  8. 启用新主题后更新缓存;换主题后检查侧边栏组件是否仍注册
  9. 站点标题 / SEO 用系统设置,不在主题 CSF 重复配置

侧边栏开发说明

Hope CMS 主题侧边栏由「容器模板 + 配置注册 + 组件文件」组成,统一放在 widgets/ 目录。后台在 外观 → 菜单 → 侧边栏 中按组管理组件;前台按槽位渲染。

无侧边栏的主题可不创建 widgets/ 目录。

相关:主题开发指南


目录约定

推荐(与官方 default 一致):

content/theme/default/
├── functions.php
└── widgets/
    ├── sidebar.php          # 默认侧边栏容器
    ├── config.php           # $sidebar 组件注册表
    ├── widget-search.php
    ├── widget-newlog.php
    ├── widget-hotlog.php
    └── ...
文件 作用
widgets/sidebar.php / sidebarN.php 侧边栏外壳;文件名决定后台「侧边栏组」
widgets/config.php 中的 $sidebar 向后台声明可用组件类型与默认字段
widgets/widget-{name}.php 单个组件渲染逻辑

*注册 key 仍建议使用 `side_`**(与后台已存配置兼容)。默认解析:

  1. widgets/widget-{name}.php(如 key side_bloggerwidget-blogger.php

列表页、文章页中引入:

<?php include PageComposer::themePath('sidebar'); ?>

第二组:

<?php include PageComposer::themePath('sidebar1'); ?>

容器模板

<?php
defined('HOPE_ROOT') || exit('access denied!');
?>
<aside class="sidebar">
    <?php hope_emit('index_sidebar'); ?>
    <?php if (!hope_render_sidebar_widgets('sidebar')): ?>
        <?php
        hope_include_sidebar_widget('side_newlog', '最新文章', ['显示数量' => '5']);
        ?>
    <?php endif; ?>
</aside>

要点:

  1. hope_emit('index_sidebar'):插件可在此插入内容
  2. hope_render_sidebar_widgets($slot):按组输出;$slot 与文件名一致(sidebar / sidebar1
  3. 核心 API 在 system/lib/sidebar.php

注册组件(widgets/config.php

<?php
defined('HOPE_ROOT') || exit('access denied!');

$sidebar = [
    'side_search' => [
        'title' => '搜索',
        'default' => [
            '输入提示' => '搜索文章、标签…',
        ],
    ],
    'side_hotlog' => [
        'title' => '热门文章',
        'default' => [
            '显示数量' => '5',
        ],
    ],
];
字段 说明
数组键 组件标识(建议 side_*),对应 widget-*.php
title 后台下拉显示的名称
default 可选;字段名 → 默认值

自定义 HTML 组件无需注册:后台类型选「自定义组件」。


编写组件文件

例如 widgets/widget-hotlog.php(注册 key 为 side_hotlog):

<?php
defined('HOPE_ROOT') || exit('access denied!');

$limit = (int) hope_widget_field($fields, '显示数量', $widget_config['default']['显示数量'] ?? 5);
$Post_Store = new Post_Store();
$logs = $Post_Store->getHotLog(max(1, $limit));
?>
<div class="widget widget-hotlog">
    <h3 class="widget-title"><?= htmlspecialchars($widget_title ?: '热门文章') ?></h3>
    <!-- 循环输出 $logs -->
</div>

渲染时注入的变量:

变量 说明
$widget_title 后台填写的组件名称
$fields 组件自定义字段(键多为中文,与 default 一致)
$widget_config $sidebar[$widget_key]
$widget_key 组件标识
$limit = (int) hope_widget_field($fields, '显示数量', $widget_config['default']['显示数量'] ?? 5);
$hint  = hope_widget_field($fields, '输入提示', '搜索…');

自定义 HTML 组件

无需在 config.php 注册。后台添加侧边栏项时类型选「自定义组件」,直接填 HTML。

未配置任何组件时,容器内应用 hope_include_sidebar_widget(...) 做兜底,避免空白侧栏。

切换主题后:旧主题注册的组件类型若新主题没有对应文件,该项可能不渲染——启用新主题后请到 外观 → 侧边栏 检查并调整。


多侧边栏组

  1. widgets/ 增加 sidebar1.phpsidebar2.php…(内调 hope_render_sidebar_widgets('sidebar1')
  2. 后台「菜单 → 侧边栏」会出现组切换 Tab
  3. 添加的组件会写入对应组

渲染流程

后台菜单(type=sidebar, url=slot)
    → SnapshotBank menu 缓存
    → hope_menu_sidebar_widgets(slot)
    → hope_render_sidebar_widget()
         ├─ 解析 widget-*.php / side_*.php → include
         └─ 否则输出自定义 content

检查清单

  1. config.php$sidebar 键名与组件文件映射一致(side_foowidget-foo.php
  2. 容器已调用 hope_render_sidebar_widgets('sidebar')
  3. 后台能看到已注册组件,多组时能切换
  4. 未配置组件时有合理兜底
  5. 无侧边栏主题不创建 widgets/

更多主题约定见 主题开发指南

插件开发指南

插件是在不修改 system/ 核心的前提下扩展 Hope CMS 的主要方式:通过挂载点插入逻辑、可选建表、提供后台设置页与前台页面。

官方示例插件: content/plugin/tips/(小贴士)。无自建表、结构完整,适合作为脚手架。

有表 / 存储的对照:content/plugin/oauth/callback_init 建表 + MetaStorage 配置)。

相关文档:开发准备工作 · 挂载点手册 · 数据库与 SQL · 升级与更新 · 伪静态与路由 · API 开发文档 · 常见问题


1. 从 tips 起步

  1. 复制 content/plugin/tips/content/plugin/你的插件名/
  2. 目录名与入口文件名一致:你的插件名/你的插件名.php
  3. 重命名 tips_*.php,并全局替换函数前缀(如 tips_myplugin_
  4. 修改入口文件头信息中的 Plugin Name / Description / Version
  5. 后台 插件 → 插件管理 启用
  6. 确认钩子生效;需要持久化时再补 MetaStorage / 建表

启用时核心流程:写入 active_plugins → 加载 {插件}_callback.php → 调用 callback_init()不会自动执行 install.sql)。

每请求加载:对已启用插件 include_once content/plugin/{名}/{名}.php,再加载当前主题 hooks.php,最后 hope_emit('init')


2. 目录结构

content/plugin/tips/
├── tips.php                 # 必需:入口 + 头信息 + 注册钩子
├── tips_callback.php        # 强烈推荐:启用 / 更新 / 删除
├── tips_setting.php         # 可选:后台设置页(有则显示「设置」)
├── tips_lib.php             # 推荐:业务函数
├── tips_show.php            # 可选:前台独立页(SiteUrl::plugin)
├── preview.png              # 可选:插件列表预览图
└── assets/
    └── tips.css
文件 必需 说明
{名}.php 入口;启用期间每个请求都会加载
{名}_callback.php 强烈建议 callback_init / callback_up / callback_rm
{名}_setting.php 定义 plugin_setting_view()
{名}_lib.php 建议 函数库
{名}_show.php 前台展示页
{名}_rewrite.php 按需拆分(如伪静态规则)

命名规则:目录名、入口文件名、钩子函数前缀保持一致。


3. 入口文件与头信息

<?php
/*
Plugin Name: 小贴士
Version: 1.0.0
Plugin URL: http://www.hopecms.cn
Description: 插件启用后,在后台首页随机展示一句内置使用提示。
Author: Hope CMS
Author URL: http://www.hopecms.cn
*/
!defined('HOPE_ROOT') && exit('error');

require_once HOPE_ROOT . 'content/plugin/tips/tips_lib.php';

hope_listen('adm_main_top', 'tips_render_admin_banner');
hope_listen('adm_head', 'tips_enqueue_admin_css');
头字段 说明
Plugin Name 后台显示名(必需)
Version 版本号
Description 简介
Plugin URL / Author / Author URL 可选元数据

active_plugins 中存储的是相对路径:tips/tips.php


4. 生命周期回调

文件:content/plugin/{名}/{名}_callback.php

函数 时机 典型工作
callback_init() 启用 建表、写默认 MetaStorage、注册一次性数据
callback_up() 更新插件后 通常再调 callback_init()*_upgrade_schema()
callback_rm() 删除 删 MetaStorage、HopeSql::dropTables([...])

tips(无表)

<?php
defined('HOPE_ROOT') || exit('access denied!');

function callback_init() {
}

function callback_up() {
    callback_init();
}

function callback_rm() {
    MetaStorage::getInstance('tips')->deleteAllName('YES');
}

有表时(对照 oauth)

function callback_init() {
    require_once HOPE_ROOT . 'content/plugin/oauth/oauth_lib.php';
    oauth_upgrade_schema(); // 内含 CREATE TABLE IF NOT EXISTS
    $storage = MetaStorage::getInstance('oauth');
    if (!$storage->getValue('config')) {
        $storage->setValue('config', oauth_default_config(), 'array');
    }
}

function callback_rm() {
    MetaStorage::getInstance('oauth')->deleteAllName('YES');
    HopeSql::dropTables(['oauth_bind']); // 不带表前缀
}

要点:

  • 建表在 PHP 里执行,不要依赖自动跑 install.sql
  • HopeDb::table('xxx') 不带前缀;原生 SQL / dropTables 注意 DB_PREFIX
  • 卸载是否删表由你决定:商业数据可选择只清 MetaStorage、保留业务表

详见 数据库与 SQL升级与更新


5. 挂载点(Hook)

hope_listen('adm_main_top', 'tips_render_admin_banner');
hope_listen(HopeHooks::ADM_HEAD, 'tips_enqueue_admin_css'); // 推荐常量
API 行为
hope_emit($hook, ...) 执行该点全部回调
hope_emit_once($hook, $input, &$ret) 只跑第一个,可改 $ret
hope_emit_pipe($hook, $input, &$ret) 链式变换 $ret
hope_unlisten / hope_has_listener 移除 / 判断

常用挂载点

常量 / 字符串 用途
init 插件与主题 hooks 加载完后
index_head / index_footer 前台头尾
index_body_start / index_body_end body 始末
adm_head / adm_footer 后台头尾
adm_menu / adm_menu_ext 后台侧栏菜单
adm_main_top 后台首页顶部(tips 横幅)
adm_writelog_bar 写文章工具栏
user_menu 用户中心侧栏
user_center_api 用户中心 API 扩展
save_log / del_log 文章保存 / 删除后
log_view / log_related 文章渲染前 / 相关推荐
comment_saved / post_comment 评论相关
upload_media 媒体上传(常配合 hope_emit_once)
plugin_active / plugin_inactive 启停插件时
routing_register 注册前台路由

完整参数与示例见 挂载点手册

约定: 钩子回调里输出 HTML 时对用户数据做 htmlspecialchars;需要中断请求时用 JsonOut::* / hope_abort()


6. 后台设置页

存在 {名}_setting.php 且插件已启用时,插件列表显示「设置」。

访问:{后台入口}?act=plugin_set&plugin=tips
(默认入口为 admin.php,生产环境应重命名。)

必须定义:

<?php
defined('HOPE_ROOT') || exit('access denied!');

function plugin_setting_view() {
    // 输出后台 HTML(可沿用 content/admin 的 Bootstrap / card 样式)
}

保存配置推荐两种方式:

A. MetaStorage(键值,适合开关与小配置)

$storage = MetaStorage::getInstance('myplugin');
$storage->setValue('config', ['enable' => 1], 'array');
$config = $storage->getValue('config');

B. 自建表

HopeDb::table(...)->insert/update;设置页里处理 POST 时用 RequestInput::postStrVar 等过滤。

设置页由核心保证管理员登录;若另写 AJAX 接口,须自行校验:

if (!AuthSession::isLogin() || ROLE !== ROLE_ADMIN) {
    JsonOut::authError('权限不足');
}

7. 前台页面 {名}_show.php

放置该文件且插件已启用时,可通过插件路由访问:

$url = SiteUrl::plugin('tips');
$url = SiteUrl::plugin('tips', ['id' => 1]);
  • 未启用或文件不存在 → 404
  • 页面可自绘完整 HTML,也可 include 当前主题头尾保持站点风格
include PageComposer::themePath('header');
// ... 插件内容 ...
include PageComposer::themePath('footer');

静态资源:

function tips_asset_url($path) {
    return HOPE_PLUGINS_URL . 'tips/assets/' . ltrim($path, '/');
}
常量 说明
HOPE_PLUGINS_PATH content/plugin/ 物理路径
HOPE_PLUGINS_URL content/plugin/ URL 前缀

8. 数据库与配置

场景 推荐
开关、JSON 配置、计数 MetaStorage::getInstance('插件名')
列表、关联、订单等 自建表 + HopeDb::table
系统级选项 Settings::get / Settings::updateOption(慎用,避免污染核心键)
$rows = HopeDb::table('myplugin_log')
    ->where(['uid' => $uid])
    ->order('id DESC')
    ->limit(20)
    ->findAll();

禁止在业务里直接拼接不可信输入执行 SQL。详见 数据库与 SQL


9. 安全规范

  1. 每个 PHP 文件检查 HOPE_ROOT
  2. 读写请求用 RequestInput::getIntVar / postStrVar / postRawStr
  3. 输出 HTML 用 htmlspecialchars;JSON 用 JsonOut::ok / JsonOut::error
  4. CSRF:后台表单遵循现有 admin 习惯;前台写操作校验登录态与 token
  5. 不修改核心表结构语义;不覆盖 system/content/admin 核心文件
  6. SQL 表名、字段名白名单化,勿把用户输入拼进标识符

10. 调试

  1. system/config.php 增加 const ENVIRONMENT = 'develop';,或后台开启调试模式
  2. 错误日志:content/logs/content/cache/error.log
  3. 改钩子后:禁用再启用插件,确保 callback_init 重跑
  4. 确认 active_plugins 中路径为 目录/入口.php
  5. 前台 _show.php 404:检查是否启用、文件名是否 {名}_show.php、链接是否 SiteUrl::plugin

11. 与主题的分工

能力 放插件 放主题
跨主题可复用功能
仅当前皮肤的样式 / 布局
商业支付、OAuth、统计 主题只负责展示
CSF 外观选项 settings.php
文章保存后业务逻辑 save_log 主题 hooks 仅皮肤相关

Shop 等主题依赖的商业能力应做成普通插件,可启用 / 禁用 / 删除,而不是改核心。


12. 发布检查清单

  • [ ] 头信息完整,Version 可递增
  • [ ] callback_rm 清理 MetaStorage;有表则明确是否 dropTables
  • [ ] callback_up / *_upgrade_schema 可重复执行(IF NOT EXISTS / 判列)
  • [ ] 设置页、前台页在未启用时不可访问
  • [ ] 函数名、MetaStorage 名、表名带插件前缀,无全局污染
  • [ ] 附简短说明(README 或设置页文案)
  • [ ] 在 PHP 7.4+ / 8.x 各测一次启停与卸载

13. 最小插件骨架

<?php
/*
Plugin Name: 演示插件
Version: 1.0.0
Description: 最小可运行示例
Author: You
*/
!defined('HOPE_ROOT') && exit('error');

hope_listen('adm_head', function () {
    echo "<!-- myplugin loaded -->\n";
});

仅入口也可运行;正式发布请补全 _callback.php 与卸载清理。

伪静态与 URL 路由

Hope CMS 通过 链接模式(linkmode路由表 控制前台 URL 形态。后台在 设置 → 链接 中配置;路由表由 Settings::getEnhancedRoutingTable() 生成,由 Hope\Http\FrontRouter 匹配并分发到对应 *_Handler

相关:挂载点手册 · API 开发文档 · 插件开发指南


链接模式

linkmode 名称 URL 形态 说明
0 动态 ?article=1?category=2&page=3 无需服务器重写,兼容性最好
1 伪静态 /article/1.html/user 需将路径重写到 index.php
2 index.php 式 /index.php/article/1.html 依赖 PATH_INFO,部分主机更稳定
$linkmode = (string) Settings::get('linkmode');
$isRewrite = ($linkmode === '1' || $linkmode === '2');

保存链接设置后会刷新路由缓存。

后台 设置 → 更新缓存(全量 $SNAP->refresh())也会一并调用 Settings::resetRoutingTableCache(),清空进程内路由表缓存。单独刷新 options 缓存时同样会重置路由表。

首页分页规则 /page/{%page%}/ 与独立页 /page/{%alias%}.html 共用 page 前缀。路由引擎会保留尾斜杠,并将首页页码限制为数字,避免 /page/docs.html 被误判为分页。

后台 URL 规则

设置 → 链接 → 伪静态管理 中可配置(hope_option 键名):

配置项 动态模式默认 伪静态模式默认 用途
rule_index ?page={%page%} /page/{%page%}/ 首页列表
rule_article ?article={%id%} /article/{%id%}.html 文章详情
rule_page ?id={%id%} /page/{%alias%}.html 独立页面
rule_category ?category={%id%}&page={%page%} /category/{%alias%}/{%page%}/ 分类列表
rule_tag ?tags={%tag%}&page={%page%} /tags-{%tag%}_{%page%}.html 标签列表
rule_record ?record={%record%}&page={%page%} /date/{%record%}/{%page%}/ 日期归档

生成链接时由 SiteUrl 替换占位符。

常用占位符

占位符 说明
{%host%} 站点 URL(SITE_URL
{%id%} 数字 ID(含义由所在规则决定)
{%alias%} 按规则隔离:文章/分类/页面各自别名
{%category%} / {%category_alias%} 所属分类标识(文章规则用)
{%category_name%} 分类显示名
{%page%} 分页页码
{%tag%} 标签名
{%record%} 日期归档(YYYYMM / YYYYMMDD
{%year%} / {%month%} / {%day%} 文章发布日期
{%parent%} 父分类别名

变量隔离: 文章路径里的分类请写 {%category_alias%};分类列表自身写 {%alias%}

分页占位符 {%page%} 在生成非分页链接时会被自动剔除。推荐连接写法:/{%page%}/_{%page%}-{%page%}?page={%page%}

自定义首页(home_page_id > 0)时,文章列表分页由 SiteUrl::postPage() 生成,路径可能带 posts/ 前缀。

分类勿写成 {%alias%}/{%page%}.html 同时文章用 {%category_alias%}/{%alias%}.html(同形会抢匹配)。推荐:文章 article/{%id%}.html、分类 category/{%alias%}/{%page%}/、独立页 page/{%alias%}.html

内置活动路由

路径 / 参数 Handler 说明
?author=1 Author 作者页
?keyword=关键词 Search 搜索
/user?user User 个人中心
/login?login User::login 登录
/register?register User::register 注册
/auth_api?auth_api User::authApi 认证 API
?rest-api=方法名 Api / Pay REST API
/plugin/插件名?plugin=插件名 Plugin 插件前台页
?resource_alias=别名 Download 附件下载
POST ?action=addcom Comment 提交评论

伪静态示例:/user/login/register/plugin/video
动态示例:?user?login?plugin=video


请求匹配流程

浏览器请求
  → Web 服务器重写到 index.php(伪静态时)
  → FrontRouter 解析路径
  → Settings 路由表按优先级匹配
  → 校验 must_get / 方法
  → 写入 $_GET
  → *_Handler 执行

要点:

  1. 伪静态模式跳过纯 query 型内容路由;动态模式跳过纯 path 型 rewrite 路由
  2. 活动路由排在默认首页路由之前,避免 ?category=1 被首页抢走
  3. 插件可通过 HopeHooks::ROUTING_REGISTER 向路由表头部追加规则

Web 服务器配置

Apache(站点根目录 .htaccess

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
</IfModule>

子目录安装(如 /hope/)将 RewriteBase 改为 /hope/

Nginx

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

index.php 式(linkmode=2) 若无效可改用:

location / {
    if (!-e $request_filename) {
        rewrite ^/(.*)$ /index.php/$1 last;
    }
}

IIS

需安装 URL Rewrite,将请求重写到 index.php。系统兼容 HTTP_X_REWRITE_URL

改服务器配置后,先确认后台 linkmode 与规则已保存,再逐项测试文章、分类、用户中心。

生成链接(开发)

主题与插件应使用 SiteUrl,不要手写路径:

SiteUrl::post($gid);
SiteUrl::category($sid);
SiteUrl::tag($tagname);
SiteUrl::postPage();
SiteUrl::userCenter(['api' => 1]);
SiteUrl::plugin('video', ['vid' => 1]);
SiteUrl::login();
SiteUrl::register();

SiteUrl::plugin() 在伪静态下生成 /plugin/video?vid=1,在动态下生成 ?plugin=video&vid=1


插件扩展伪静态

站点 已开启 linkmode 1 或 2 时,可注册独立 path 规则:

  1. 新建 {插件名}_rewrite.php,实现注册函数
  2. 入口中 hope_listen(HopeHooks::ROUTING_REGISTER, 'xxx_register_rewrite_routes')
  3. 可选:提供 processor 回调,将路径参数写入 $_GET
hope_listen(HopeHooks::ROUTING_REGISTER, 'myplugin_register_routes');

function myplugin_register_routes($table, &$routes) {
    $linkmode = (string) Settings::get('linkmode');
    if ($linkmode !== '1' && $linkmode !== '2') {
        return;
    }

    $routes = array_merge([
        [
            'type'      => 'rewrite',
            'model'     => 'Plugin_Handler', // 以当前核心约定为准
            'method'    => 'loadPluginShow',
            'pattern'   => '/myplugin/{%id&type=num%}',
            'processor' => function ($params, $route) {
                $_GET['plugin'] = 'myplugin';
                $params['plugin'] = 'myplugin';
                return $params;
            },
        ],
    ], $routes);
}

路由项字段

字段 说明
type rewrite / query / active
model / method Handler 与方法
pattern 支持 {%param%}{%param&type=num%}
must_get 必须存在的 $_GET
processor 匹配成功后的参数处理
request_method 限制 GET / POST

Pattern 类型修饰:{%id&type=num%} 仅数字;{%slug&type=alnum%} 字母数字。

对照现成实现:content/plugin/video/video_rewrite.php(若存在)。


常见问题

开启伪静态后全部 404

  • 检查是否重写到 index.php
  • 子目录确认 RewriteBase / SITE_URL
  • 确认 linkmode12 且规则已保存

首页正常,文章/分类 404

  • 检查 rule_articlerule_category 是否与服务器兼容
  • 勿遗漏必要占位符;保存后「更新缓存」

插件伪静态不生效

  • 站点 linkmode 必须为 12
  • 确认 routing_register 已注册且插件已启用
  • 更具体的 pattern 应用 array_merge($newRoutes, $routes) 插到表头

动态模式下用户中心 API

  • ?user&api=1&action=profile
  • 认证专用:/auth_api?auth_api
  • 使用 SiteUrl::userCenter()SiteUrl::authApi(),勿硬编码

相关文件

文件 职责
system/Hope/Config/Settings.php 路由表、linkmode
system/Hope/Http/FrontRouter.php 路径解析与匹配
system/lib/http/site_url.php 按规则生成链接
system/lib/hooks.php ROUTING_REGISTER
content/admin/setting.php 后台链接配置界面

API 开发文档

Hope CMS 提供 REST 风格接口,通过 URL 参数 rest-api 指定方法名。响应均为 JSON。

相关:伪静态与路由 · 挂载点手册 · 插件开发指南


基础地址

http://www.hopecms.cn/?rest-api={方法名}

示例:

GET http://www.hopecms.cn/?rest-api=article_list&page=1&count=10

开关

除支付相关接口外,其余 API 需在后台开启 OpenAPI(Settings::get('is_openapi') !== 'n'),否则返回 api is closed

支付接口(pay_notifypay_createpay_cashierpay_status)不受此限制。


鉴权方式

需要鉴权的接口(如发文、上传)支持两种方式:

1. API Key 签名(服务端 / 第三方)

后台「设置 → API」获取 apikey,请求携带:

参数 说明
req_time 当前 Unix 时间戳(与服务器时差 ≤ 300 秒)
req_nonce 必填,16–64 位十六进制随机串,防重放
req_sign md5(req_time + req_nonce + apikey)
$req_time = time();
$req_nonce = bin2hex(random_bytes(16));
$apikey   = '你的apikey';
$req_sign = md5($req_time . $req_nonce . $apikey);
POST http://www.hopecms.cn/?rest-api=article_post&req_time=...&req_nonce=...&req_sign=...

缺少参数、签名错误或 nonce 重放时返回相应错误信息。

已登录用户携带站点认证 Cookie 时,可免 API Key,且 author_uid 可自动取当前用户。


响应格式

成功:

{ "code": 200, "msg": "ok", "data": { ... } }

失败:

{ "code": 0, "msg": "错误说明" }

认证失败:code 多为 401(以 JsonOut::authError 实际返回为准)。


文章接口

article_list — 文章列表

GET ?rest-api=article_list
参数 类型 说明
page int 页码,默认 1
count int 每页条数
category_id int 分类 ID
keyword string 标题关键词
tag string 标签名
order string views / comnum,默认按置顶与时间

返回 data.articles(含 idtitlecoverurldateauthor_nametags 等)。

article_detail — 文章详情

GET ?rest-api=article_detail&id=1

密码保护文章返回错误。成功返回 data.article

article_post — 发布文章

POST ?rest-api=article_post

需鉴权。主要字段:titlecontent(必填),以及 excerptcategory_idtagscoverdraftaliastopsortopallow_remarkpasswordtemplate 等。

article_update — 更新文章

POST ?rest-api=article_update

需鉴权。需传 id 及要更新的字段。


分类与微语

接口 方法 说明
category_list GET 分类列表
note_list GET 微语列表
note_post POST 发布微语(需鉴权)

评论与用户

接口 方法 说明
comment_list GET 文章评论,id 为文章 ID
userinfo GET 当前登录用户信息(需 Cookie)

个人中心 API

前台个人中心通过 ?user&api=1(或伪静态 /user?api=1)调用,需登录 Cookie。POST 须携带页面输出的 token

GET  http://www.hopecms.cn/?user&api=1&action=profile
POST http://www.hopecms.cn/?user&api=1
     Body: token=...&action=profile&nickname=...
action 方法 说明
profile GET / POST 读取或更新个人资料
avatar_upload POST 上传头像
avatar_qq POST 使用 QQ 头像
recharge POST 创建充值订单
recharge_records GET 充值记录
invite_info GET 邀请码与奖励统计
forum_posts / forum_get / forum_save / forum_delete 论坛相关(主题提供时)
forum_categories GET 可选论坛分类
my_comments GET 我的评论
comment_reply POST 回复评论
my_media / media_upload / media_delete 媒体库

业务实现位于 system/app/service/(如 UserHub / 用户中心模块)。主题可在 account/ 提供模板并对接前端 JS。

插件可通过 HopeHooks::USER_CENTER_APIhope_emit_once)扩展自定义 action


媒体上传

POST ?rest-api=upload

需 API Key 鉴权。multipart/form-data 字段:file、可选 sidauthor_uid

成功返回 media_idurlfile_info


支付接口

Pay_Handler 处理,不依赖 OpenAPI 开关:

接口 说明
pay_create 创建支付订单
pay_cashier 收银台页面数据
pay_status 查询订单状态
pay_notify 支付平台异步回调

网关密钥、回调 URL 在后台 支付设置 中配置。参数以 system/app/handler/pay_handler.php 及支付插件为准。

若后台开启 API 限流,超限请降低频率或调整限额。


调用示例(PHP)

$base = 'http://www.hopecms.cn/';
$req_time = time();
$req_nonce = bin2hex(random_bytes(16));
$apikey = 'your_apikey';
$sign = md5($req_time . $req_nonce . $apikey);

$url = $base . '?rest-api=article_list&page=1&count=5'
    . '&req_time=' . $req_time
    . '&req_nonce=' . $req_nonce
    . '&req_sign=' . $sign;

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($ch);
curl_close($ch);

$data = json_decode($body, true);

扩展 API

优先通过插件扩展,避免直接改核心 Api_Handler

  1. 个人中心类:挂载 HopeHooks::USER_CENTER_API 接管自定义 action
  2. 独立前台接口:插件 _show.php + 自建鉴权,或注册路由后由插件处理
  3. 拦截 rest-api:在 init 钩子里识别方法名并 JsonOut::ok 后结束(注意与核心方法名冲突)

若维护私有分支必须改核心:在 Api_Handler 增加私有方法,方法名即 rest-api 值;需鉴权则调用 Handler 内鉴权方法。

实现入口:system/app/handler/api_handler.php

联系我们

欢迎通过以下渠道获取帮助、反馈问题或参与社区交流。

联系方式

官方渠道

渠道 说明
官方网站 下载、应用中心与站内文档入口
用户论坛 使用讨论、开发问答与经验分享
开发文档 安装、升级与二次开发说明
应用中心 主题 / 插件扩展与用户反馈
下载中心 最新安装包

如何反馈问题

提交问题时请尽量提供:

  1. Hope CMS 版本(后台首页)
  2. PHP / MySQL(或 MariaDB)版本
  3. 当前主题与已启用插件
  4. 复现步骤与报错信息(可附 content/cache/error.log 相关片段)
安全漏洞请优先通过官方渠道私下反馈,勿在公开 QQ 群 / 论坛直接贴出可被滥用的细节。

获取程序

社区参与

  • 在用户论坛发帖互助
  • 分享自研主题与插件到应用中心
  • 对照官方示例主题 default、示例插件 tips 提交改进建议

文档与参考

站内文档按「入门 → 开发基础 → 主题 → 插件 → 接口」组织;还可参阅:

站内「主题生成器」可快速拼装主题 PHP 片段。

软件许可证

Hope CMS(希望CMS)核心代码按 Apache License 2.0 发布。部分捆绑的第三方库可能采用各自许可证,以其目录内说明为准。