Hope CMS 文档

Hope CMS(希望CMS)是一款面向中文站长的轻量开源 CMS:博客写作、主题与插件扩展、支付能力开箱可用,适合个人站、工作室站与付费资源站。

命名说明

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

功能简介

  • Markdown 写作(Editor.md;分类 / 标签 / 封面 / 别名 / 置顶 / 阅读密码)
  • 多用户角色(管理员 / 编辑 / 作者 / 访客)与后台模块权限
  • SEO(站点 / 文章 / 分类 / 标签 TDK)与动态 / 伪静态链接
  • REST API(API Key、访问限流)
  • 主题切换、插件挂载点
  • 媒体附件、个人媒体库与前台资源下载
  • 评论审核、验证码、邮件通知
  • 个人中心、余额充值、邀请奖励与在线支付(微信 / 支付宝等)
  • AI 工作台与后台助手
  • 备份导入、更新缓存、SMTP、多语言后台
  • 统一数据库层(链式查询;插件在 callback_init 建表)
  • 示例主题 default示例插件 tips 可直接对照学习

官方官网主题还可提供:用户论坛、站内开发文档等。

适合做什么

  • 个人博客 / 内容站
  • 付费下载 / 会员资源站(配合 Shop 等主题)

环境一览

项目 要求
PHP 7.0+(推荐 8.0+)
数据库 MySQL 5.6+ / MariaDB 10.3+(需 mysqlipdo_mysql
Web Apache / Nginx

安装与配置细节见 安装指南

文档导航

章节 内容
安装指南 环境、安装步骤、安全加固、常见问题
升级与更新 插件/主题升级、字段迁移、更新缓存
开发准备工作 目录结构、常量、挂载点速查
挂载点手册 HopeHooks 全量常量与用法
插件开发指南 结构、生命周期、钩子、设置页、前台页、安全与发布清单
数据库与 SQL 查询 API、callback 建表、字段升级
主题开发指南 从零创建、模板变量、options/CSF、hooks、检查清单
侧边栏开发说明 widgets 注册与渲染
伪静态与路由 链接模式、URL 规则、服务器配置
API 开发文档 REST、个人中心 API、鉴权

官方域名

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

软件许可证

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

安装指南

Hope CMS(希望CMS)安装流程:上传程序包 → 配置数据库 → 创建管理员 → 加固安全 → 更新缓存。

环境要求

项目 要求
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. 上传到网站根目录,或子目录(子目录须正确配置 SITE_URL / 伪静态 RewriteBase
  3. 确认上述目录可写
  4. 访问 http://你的域名/install.php 进入安装向导
  5. 填写数据库信息与管理员账号,完成安装
  6. 立即删除或重命名 install.php
    成功安装会写入 content/cache/install.lock,并尝试将 install.php 重命名为 install.php.disabled(仓库备份常为 install.php.bak

重装

  1. 删除 content/cache/install.lock
  2. 设置环境变量 HOPE_ALLOW_REINSTALL=1(若程序要求)
  3. 必要时从 install.php.bak 恢复 install.php
  4. 重新访问安装向导

重装会覆盖库表数据,生产环境请先备份数据库与 content/upload/

安装后必做

  1. 登录后台(默认入口 admin.php
  2. 重命名后台入口:将根目录 admin.php 改为不易猜测的文件名(如 manage_x8k2.php),并更新收藏夹
    仍使用 admin.php 时,示例插件「小贴士」会在后台首页提示安全风险
  3. 外观 → 主题:启用所需主题;有 options.php 时可配置品牌等
  4. 设置:站点名称、链接模式(动态 / 伪静态)等
  5. 插件 → 插件管理:按需启用(如支付、OAuth 等)
  6. 若使用伪静态:配置服务器重写,见 伪静态与路由
  7. 按需配置 SMTP、支付网关等
  8. 执行一次 设置 → 更新缓存

常见问题

打开 install.php 空白 / 报错

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

提示目录不可写

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

安装完成仍可访问 install.php

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

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

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

后台无法登录

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

从旧版本升级

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

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

升级与更新

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

适用场景速查

场景 推荐做法 详见
插件版本迭代加字段 callback_up() + 幂等 schema 升级 插件更新
主题启用时建表 主题 callback_init() 内执行 主题更新
改菜单/标签/分类名后前台未变 后台「设置 → 更新缓存」 更新缓存
仅刷新某一类缓存 $CACHE->updateCache('menu') 更新缓存

覆盖更新核心目录时可能改写 system/。业务扩展请写在 content/plugin/content/theme/,勿直接改核心后指望下次升级保留。

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

插件更新

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

生命周期

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

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

推荐写法

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

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

字段升级原则

  1. 建表用 CREATE TABLE IF NOT EXISTS
  2. 新字段先 SHOW COLUMNSALTER(可重复执行)
  3. callback_initcallback_up 调用同一函数,避免「只更新未重装」漏跑
  4. 禁止改核心表结构(articleuseroption 等)

主题更新

  • 建表 / 初始化:主题根目录 callback.phpcallback_init()(删除时 callback_rm()
  • CSF options.php 增删字段后,模板读取必须带默认值:hope_option('key', 'default') / _hope()
  • 新增 page/*.php 页面模板后:后台新建页面并选择该模板;若主题有「页面入口」类设置,再填写 URL 或页面 ID
  • $prefix(如 default_options不要随意改名,否则已保存配置会失效

主题结构与模板变量见 主题开发指南

更新缓存

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

会做什么

全量 Cache::updateCache(),重建包括但不限于:

optionsuserstacommenttagssortlinkmenunewlogrecordlogaliaslogsortlogtags

并尽量重置路由相关缓存(若存在 Option::resetRoutingTableCache())。

菜单标题同步

刷新 menu 时会先 Menu_Model::syncLinkedMenuTitles()

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

改了标签名、分类名或文章标题后,点一次「更新缓存」即可让导航跟上。标签保存/删除时也会自动刷新 tags + menu

代码中局部刷新

global $CACHE;
$CACHE = Cache::getInstance();

$CACHE->updateCache();                      // 全量
$CACHE->updateCache(['tags', 'menu', 'sort']); // 指定
$CACHE->updateArticleCache();               // 文章相关常用组合(含 menu)

缓存文件在 content/cache/*.php;写入后会尝试 opcache_invalidate。请确保目录可写。

开发自检清单

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

相关文档

开发准备工作

Hope CMS(希望CMS)支持主题与插件扩展。本文说明本地环境、目录约定、常用 API 与挂载点,便于二次开发。

开发环境

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

本地调试时,将站点根目录(含 index.php)配置为 Web 根目录,并确保 content/upload/content/cache/ 可写。

目录结构

hopecms/                              # 站点根目录(HOPE_ROOT)
├── index.php                     # 前台入口
├── admin.php                     # 后台入口
├── system/                       # 系统核心(升级会覆盖,勿直接改业务)
│   ├── config.php                # 数据库、AUTH_KEY 等配置
│   ├── base.php                  # 引导:插件加载、doAction('init')
│   ├── app/
│   │   ├── controller/           # 前台控制器(Log_Controller、Api_Controller 等)
│   │   ├── model/                # 数据模型
│   │   └── service/              # 业务服务(user_center.php 等)
│   ├── admin/                    # 后台业务逻辑(与 content/admin 视图配对)
│   └── lib/
│       ├── common.php            # 全局函数、钩子 API、hope_option()
│       ├── hooks.php             # HopeHooks 挂载点常量
│       └── database/             # Database、SqlRunner、Storage
└── content/                      # ★ 开发者主要工作区
    ├── plugin/                   # 插件目录
    ├── theme/                    # 主题目录
    ├── admin/                    # 后台 HTML 视图(可覆盖 system/admin 输出)
    ├── upload/                   # 用户上传文件
    ├── cache/                    # 运行时缓存 PHP 错误日志

开发者主要工作在 content/plugin/content/theme/ 新业务类如需放入核心层,应放在 system/app/modelcontrollerservice;目录与请求流程见本文上文。

快速上手:从示例插件起步

官方示例插件:content/plugin/tips/

  1. 对照或复制 tips 目录,改名后修改 Plugin Name 与钩子函数
  2. 后台 插件 → 插件管理 中启用
  3. 启用时核心加载 {插件}_callback.php 并调用 callback_init()
// tips.php
addAction('adm_main_top', 'tips_render_admin_banner');
addAction('adm_head', 'tips_enqueue_admin_css');

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

启用后打开后台首页即可看到小贴士横幅。完整说明(生命周期、设置页、前台页、建表、安全清单)见 插件开发指南

快速上手:从示例主题扩展页面

官方示例主题:content/theme/default/

  1. content/theme/default/page/ 下新建页面模板,或复制整套主题再改名
  2. 文件首行写 /*@name 关于我们*/,供后台选择模板时显示中文名
  3. 后台 页面 → 新建页面,模板选择对应文件
  4. 布局参考同主题 header.php / footer.php
<?php
/*@name 关于我们*/
defined('HOPE_ROOT') || exit('access denied!');
?>
<section class="about">
    <h1><?= htmlspecialchars(hope_option('site_brand', 'Hope CMS')) ?></h1>
</section>
<?php include View::getView('footer'); ?>

主题文件清单、CSF 设置、模板变量、module.php / plugins.php / callback.php 约定见 主题开发指南

请求流程(简要)

入口 流程
前台 index.php base.php → 加载已启用插件 → include 主题 plugins.php(若有)→ doAction('init')Dispatcher 匹配路由 → Controller → 主题模板
后台 admin.php(或重命名后的入口) base.phpsystem/admin/globals.phpact 分发 → system/admin/{act}.phpcontent/admin/{act}.php 渲染
REST API ?rest-api=方法名Api_ControllerOutput::ok() / Output::error()
插件设置页 {后台入口}?act=plugin_set&plugin=插件名{插件}_setting.phpplugin_setting_view()

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

常用常量

在已加载 Hope CMS 环境的 PHP 文件中可直接使用:

常量 说明 示例 / 来源
HOPE_ROOT 站点根目录绝对路径 F:/linzichen/hopecms/
DB_PREFIX 数据库表前缀 hope_(定义于 system/config.php
DB_NAME 数据库名
SITE_URL 站点 URL(含末尾 / http://localhost/cms/
THEME_PATH 当前主题目录 .../content/theme/default/
THEME_URL 当前主题 URL http://localhost/cms/content/theme/default/
PLUGIN_PATH 插件根目录 .../content/plugin/
PLUGIN_URL 插件 URL 前缀 http://localhost/cms/content/plugin/
ADMIN_TEMPLATE_PATH 后台视图目录 .../content/admin/
ISLOGIN 是否已登录 true / false
UID 当前用户 ID 未登录为 0
ROLE 当前用户角色 admin / editor / writer / visitor

路径常量(system/bootstrap/paths.php):HOPE_PATH_APPHOPE_PATH_MODELHOPE_PATH_CONTROLLERHOPE_PATH_SERVICEHOPE_PATH_ADMINHOPE_PATH_LIBRARY

用户角色

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

插件后台页由核心路由保障管理员权限;若插件提供独立 AJAX 接口,需自行校验:

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

开发规范

  • PHP 编码遵循 PSR-1PSR-12
  • 插件/主题 PHP 文件开头应校验常量:
defined('HOPE_ROOT') || exit('access denied!');
  • 主题配置统一用 hope_option('字段名', '默认值')_hope()
  • 数据库访问统一用 Database 类,禁止在业务代码中调用 Database::getInstance()->query()
  • 输出用户内容到 HTML 时使用 htmlspecialchars()htmlClean()

开启开发者模式

方式一(推荐):system/config.php 末尾添加:

const ENVIRONMENT = 'develop';

方式二: 后台 设置 → 基本 中开启「调试模式」(写入 hope_optiondebug = y)。

开发模式下 display_errors 开启,错误信息更完整。上线前请删除 ENVIRONMENT 常量或改回 production,并关闭后台调试模式。 错误日志默认写入 content/cache/error.log

挂载点机制

Hope CMS 通过挂载点(Hook)实现扩展,核心 API 位于 system/lib/common.php,常量定义于 system/lib/hooks.phpHopeHooks 类)。

// 注册(推荐使用 HopeHooks 常量;对照 tips 插件)
addAction(HopeHooks::ADM_HEAD, 'tips_enqueue_admin_css');
addAction(HopeHooks::ADM_MAIN_TOP, 'tips_render_admin_banner');

三种执行方式:

函数 行为 典型场景
doAction($hook, ...$args) 执行该挂载点上所有回调 输出 CSS/JS、记录日志
doOnceAction($hook, $input, &$ret) 仅执行第一个回调,可修改 $ret 接管上传(UPLOAD_MEDIA
doMultiAction($hook, $input, &$ret) 链式执行所有回调,逐级变换 $ret 正文过滤(ARTICLE_CONTENT_ECHO

辅助 API:removeAction($hook, $callback)hasAction($hook, $callback)

完整挂载点说明(含参数与示例)见 挂载点手册 常量源码:system/lib/hooks.php

常用挂载点速查

挂载点常量 字符串值 位置 / 用途
HopeHooks::INIT init 插件与主题 hooks 加载完成后
HopeHooks::INDEX_HEAD index_head 前台 <head>
HopeHooks::INDEX_FOOTER index_footer 前台页脚脚本前
HopeHooks::INDEX_BODY_START index_body_start 前台 <body> 开始后
HopeHooks::INDEX_BODY_END index_body_end 前台 </body>
HopeHooks::ADM_HEAD adm_head 后台 <head>
HopeHooks::ADM_FOOTER adm_footer 后台页脚
HopeHooks::ADM_MENU adm_menu 后台侧栏菜单
HopeHooks::ADM_MENU_EXT adm_menu_ext 后台侧栏菜单末尾
HopeHooks::ADM_WRITELOG_BAR adm_writelog_bar 后台编辑器工具栏
HopeHooks::USER_MENU user_menu 用户中心侧栏
HopeHooks::USER_CENTER_API user_center_api 个人中心 API 扩展
HopeHooks::SAVE_LOG save_log 文章/页面保存后
HopeHooks::DEL_LOG del_log 文章/页面删除后
HopeHooks::LOG_RELATED log_related 文章页相关推荐区
HopeHooks::LOG_VIEW log_view 文章页渲染前
HopeHooks::UPLOAD_MEDIA upload_media 媒体上传(doOnceAction 接管)
HopeHooks::SAVE_SETTING save_setting 系统设置保存后
HopeHooks::ROUTING_REGISTER routing_register 扩展前台路由表
HopeHooks::PLUGIN_ACTIVE plugin_active 插件启用
HopeHooks::PLUGIN_INACTIVE plugin_inactive 插件停用

配置与选项

系统级配置

后台「设置」写入 hope_option 表,通过 Option 类读写:

$blogname = Option::get('blogname');
Option::updateOption('apikey', $key);
Option::updateOption('is_openapi', 'y');  // 开启 REST API

主题配置(CSF)

主题 options.php 中定义的字段,保存后通过 hope_option() 读取(带缓存):

$brand = hope_option('site_brand', 'Hope CMS');
$logo  = hope_option('site_logo');

插件私有配置

推荐 Storage,数据写入 hope_storage 表,按插件名隔离:

$storage = Storage::getInstance('tips');
$storage->setValue('config', ['foo' => 'bar'], 'array');
$config = $storage->getValue('config');

// 卸载时清理(见 tips_callback.php)
$storage->deleteAllName('YES');

简单开关、计数等无需单独建表;大量结构化数据见 数据库与 SQL

输入输出

读取请求

$id       = Input::getIntVar('id');           // GET 整数
$page     = Input::getIntVar('page', 1, 1);     // 默认 1,最小 1
$name     = Input::postStrVar('name');          // POST 字符串(addslashes)
$password = Input::postRawStr('password');      // POST 原始字符串(密码等)
$ids      = Input::postIntArray('ids', []);     // POST 整数数组
$keyword  = Input::getStrVar('keyword', '');

API 统一输出

Output::ok(['list' => $rows]);           // { "code": 200, "msg": "ok", "data": ... }
Output::error('参数错误');               // { "code": 0, "msg": "..." }
Output::authError('未登录');             // 鉴权失败

// 等价于 Response 类
Response::success($data);
Response::fail('错误信息');
Response::authFail('未登录');

错误出口

hope_abort('权限不足', './');  // API 请求自动 JSON;页面请求自动 hpMsg 跳转

模板与 URL

加载主题模板

include View::getView('header');           // THEME_PATH/header.php
include View::getView('page/page_docs');   // 自定义页面
include View::getUserView('index');        // THEME_PATH/user/index.php(个人中心)

生成链接

Url::log($gid);              // 文章/页面 URL
Url::sort($sid);             // 分类 URL
Url::tag($tagname);          // 标签 URL

URL 规则受后台「设置 → 链接」中 rule_articlerule_page 等影响,支持伪静态占位符 {%id%}{%alias%} 等。完整说明见 伪静态与路由

参考示例

类型 路径 说明
示例插件 content/plugin/tips/ 入口、钩子、callback、设置页、assets
示例主题 content/theme/default/ 列表/详情、侧边栏、用户中心、options
有表插件 content/plugin/oauth/video/music/ schema 升级、Storage、伪静态扩展

下一步

挂载点手册

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

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


API 一览

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

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

约定:

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

启动与路由

常量 字符串 说明
HopeHooks::INIT init 插件与主题 plugins.php 加载完成后(base.php 末尾)
HopeHooks::ROUTE_DISPATCH route_dispatch 路由分发前(model, method, params)
HopeHooks::ROUTING_REGISTER routing_register 路由表构建后扩展(doMultiAction,可追加规则)
HopeHooks::PAGE_NOT_FOUND page_not_found 404 页
addAction(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>

主题模板负责 doAction(...),插件负责 addAction(...)


文章与评论

常量 字符串 参数 / 说明
LOG_VIEW log_view 文章页渲染前(logid, logData)
ARTICLE_CONTENT_ECHO article_content_echo 正文输出前过滤(doMultiAction
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 微语/笔记发布
addAction(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(doOnceAction,可接管 action)
LOGIN_HEAD login_head 登录页 head
LOGIN_EXT login_ext 登录表单扩展
LOGIN_SUCCESS login_success 登录成功
SIGNUP_EXT signup_ext 注册表单扩展
addAction(HopeHooks::USER_MENU, function () {
    echo '<a href="' . htmlspecialchars(Url::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_COMMENT_DISPLAY adm_comment_display 评论列表扩展
ADM_LINK_DISPLAY adm_link_display 链接列表扩展
ADM_USER_DISPLAY adm_user_display 用户列表行($user
ADM_USER_FORM adm_user_form 用户编辑表单
addAction(HopeHooks::ADM_MENU_EXT, function () {
    echo '<li><a href="./plugin.php?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 附件上传(常配合 doOnceAction 接管)
DEL_MEDIA del_media 附件删除
ATTACH_UPLOAD attach_upload 编辑器附件上传
DOWNLOAD_RESOURCE download_resource 资源下载

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

常量 字符串 说明
SAVE_SORT / DEL_SORT save_sort / del_sort 分类保存 / 删除后
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 地址(doOnceAction

示例:最小可用

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

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

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

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

数据库与 SQL

Hope CMS 使用 MySQL / MariaDB 存储数据。数据库操作统一通过 Database 类与 SqlRunner 执行器完成。

  • 生命周期 / Storage:对照示例插件 tips
  • 自建表tips 无表;有表时对照 oauthvideomusic*_upgrade_schema() / callback_init(),卸载时 dropTables

核心类与文件

类 / 文件 路径 说明
Database system/lib/database/database.php 数据库入口,提供链式查询与快捷方法
DatabaseQueryBuilder system/lib/database/databasequerybuilder.php 链式查询构建器
SqlRunner system/lib/database/sqlrunner.php SQL 文件读取与批量执行
Storage system/lib/database/storage.php 插件键值存储(写入 hope_storage 表)

表前缀

系统安装时在 system/config.php 中定义表前缀常量:

const DB_PREFIX = 'hope_';

约定:

  • 使用 Database::table('article') 时,不要手动加前缀,框架会自动拼接为 hope_article
  • 编写原生 SQL 时,可拼接 DB_PREFIX,或在 SqlRunner::executeLines / executeFile 中使用占位符 {db_prefix}
  • 少数场景需手动拼接:DB_PREFIX . 'myplugin_log'

链式查询(推荐)

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

// 查询单条
$row = Database::table('myplugin_log')->where(['id' => $id])->find();

// 统计
$total = Database::table('myplugin_log')->where(['status' => 1])->count();

// JOIN 查询(带表别名)
$list = Database::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) 条件,支持数组 ['id'=>1] 或字符串 "id=1 AND status=1"
whereRaw($sql) 原生 WHERE 片段
whereIn($field, $values) IN 查询,空数组自动变为 1=0
whereLike($field, $value) 模糊搜索,自动转义 %_
join / leftJoin 表关联
order($order) 排序,如 'id DESC'
limit($limit, $offset) 分页
group($group) GROUP BY
findAll() 返回多行数组
find() 返回单行或 null
insert($data) 插入,返回自增 ID
update($data) 更新(需先 where
delete() 删除(需先 where
count() 计数

快捷方法

适合简单 CRUD,无需链式调用:

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

原生 SQL

复杂统计、聚合或 ON DUPLICATE KEY 等场景可使用原生 SQL:

// 读:多行
$rows = Database::fetchAll(
    'SELECT * FROM `' . DB_PREFIX . 'myplugin_log` WHERE uid = ' . (int)$uid
);

// 读:单行
$row = Database::fetchOne('SELECT COUNT(*) AS cnt FROM `' . DB_PREFIX . 'myplugin_log`');

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

// 字符串转义(仅用于少量 whereRaw / 原生 SQL)
$safe = Database::escape($keyword);
优先使用链式 where / whereLike;原生 SQL 中数值请 (int) 强转,字符串务必 Database::escape()

插件/主题建表(callback_init)

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

无表插件对照 tips

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

有表时在升级函数中建表(对照 oauth_upgrade_schema()):

function oauth_upgrade_schema() {
    $table = DB_PREFIX . 'oauth_bind';
    if (Database::fetchOne("SHOW TABLES LIKE '{$table}'")) {
        return;
    }
    Database::execute("CREATE TABLE IF NOT EXISTS `{$table}` ( ... )", true);
}

function callback_init() {
    require_once HOPE_ROOT . 'content/plugin/oauth/oauth_lib.php';
    oauth_upgrade_schema();
}

function callback_rm() {
    Storage::getInstance('oauth')->deleteAllName('YES');
    SqlRunner::dropTables(['oauth_bind']);
}

何时执行

时机 调用链
插件启用 Plugin_Model::activePlugin()callback_init()
主题启用 Theme_Model::initCallback()callback_init()
插件升级 callback_up()(通常再调同一 upgrade 函数)
手动 SQL 文件 Database::executeFile($path, $options) / SqlRunner::executeFile()(备份恢复等)

SqlRunner 高级选项

SqlRunner::executeFile(HOPE_ROOT . 'path/to/custom.sql', [
    'replace_prefix' => true,   // 替换 {db_prefix}
    'ignore_error'   => false,  // 遇错是否继续
    'charset_setup'  => false,  // 是否调整库字符集
    'version_gate'   => false,  // 是否解析 # pro x.x 版本门禁行
]);

SqlRunner::dropTables(['table_a', 'table_b']) 用于卸载时按逻辑表名(不含前缀)批量 DROP。

version_gate 示例(升级包 SQL 中可用):

# 2.0.0
ALTER TABLE `{db_prefix}option` ADD COLUMN ...

当当前版本高于指定版本时,后续 SQL 不再执行。

插件升级时机与缓存刷新见 升级与更新

字段升级(Schema Migration)

建表用 CREATE TABLE IF NOT EXISTS;给已有表加字段应在升级函数中检测后 ALTER

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

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

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

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

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

Storage 插件存储

插件配置、缓存类数据可存入 hope_storage,无需自建表:

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

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

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

// 删除插件全部数据(callback_rm 中常用,见 tips)
$storage->deleteAllName('YES');

系统核心表(只读参考)

开发插件时不得修改以下核心表结构,仅可通过 Model / API 读写:

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

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

开发建议

  1. 生命周期 → 先对照 tips 写好 callback_* 与 Storage
  2. 新建表 → 写在 callback_init / *_upgrade_schema()(可参考 oauth
  3. 加字段 → 同一升级函数内 SHOW COLUMNS + ALTER TABLE
  4. 日常查询 → 优先 Database::table() 链式
  5. 复杂 SQLfetchAll / fetchOne / execute,注意转义
  6. 卸载清理callback_rm() 必须清 Storage;有表则 dropTables,不留痕

插件开发指南

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

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

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

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


1. 从 tips 起步

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

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

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


2. 目录结构

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

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


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';

addAction('adm_main_top', 'tips_render_admin_banner');
addAction('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() 启用 建表、写默认 Storage、注册一次性数据
callback_up() 更新插件后 通常再调 callback_init()*_upgrade_schema()
callback_rm() 删除 删 Storage、SqlRunner::dropTables([...])

tips(无表)

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

function callback_init() {
}

function callback_up() {
    callback_init();
}

function callback_rm() {
    Storage::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 = Storage::getInstance('oauth');
    if (!$storage->getValue('config')) {
        $storage->setValue('config', oauth_default_config(), 'array');
    }
}

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

要点:

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

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


5. 挂载点(Hook)

addAction('adm_main_top', 'tips_render_admin_banner');
addAction(HopeHooks::ADM_HEAD, 'tips_enqueue_admin_css'); // 推荐常量
API 行为
doAction($hook, ...) 执行该点全部回调
doOnceAction($hook, $input, &$ret) 只跑第一个,可改 $ret
doMultiAction($hook, $input, &$ret) 链式变换 $ret
removeAction / hasAction 移除 / 判断

常用挂载点

常量 / 字符串 用途
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 媒体上传(常配合 doOnceAction)
plugin_active / plugin_inactive 启停插件时
routing_register 注册前台路由(见伪静态文档)

完整参数与示例见 挂载点手册开发准备工作 速查表。

约定: 钩子回调里输出 HTML 时对用户数据做 htmlspecialchars;需要中断请求时用 Output::* / hope_abort(),勿随意 die 半截页面。


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. Storage(键值,适合开关与小配置)

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

B. 自建表

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

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

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

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

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

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

静态资源:

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

8. 数据库与配置

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

禁止在业务里直接 Database::getInstance()->query() 拼接不可信输入。详见 数据库与 SQL


9. 安全规范

  1. 每个 PHP 文件检查 HOPE_ROOT(或等价 !defined('HOPE_ROOT') && exit
  2. 读写请求用 Input::getIntVar / postStrVar / postRawStr(密码等)
  3. 输出 HTML 用 htmlspecialchars;JSON 用 Output::ok / Output::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、链接是否 Url::plugin

11. 与主题的分工

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

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


12. 发布检查清单

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

13. 最小插件骨架

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

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

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

主题开发指南

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

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

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


1. 从零创建主题

  1. 复制 content/theme/default/content/theme/你的主题/
  2. 修改 header.php 顶部 Theme Name / Version / Description
  3. 修改 options.php$prefix(如 yourtheme_options)与标题文案
  4. module.php 中函数前缀(如 nova_*)改为自己的命名空间,避免与其它主题冲突
  5. 后台 外观 → 主题 启用;如有 callback.php,启用时会执行 callback_init()
  6. 建议执行一次 设置 → 更新缓存

不要直接改正在线上使用的主题;复制一份再改,便于回滚。


2. 目录结构

content/theme/default/
├── header.php            # 必需:主题元信息 + HTML 头部
├── footer.php            # 必需:页脚与闭合标签
├── log_list.php          # 必需:首页 / 分类 / 标签 / 搜索 / 归档列表
├── echo_log.php          # 必需:文章详情
├── 404.php               # 推荐:404 页
├── module.php            # 推荐:主题函数库(模板中 require)
├── options.php           # 可选:CSF 主题设置
├── plugins.php           # 可选:主题级钩子(每请求自动 include)
├── callback.php          # 可选:启用 / 删除 / 升级回调
├── preview.png           # 推荐:后台主题列表预览图
├── widgets/              # 可选:侧边栏(无侧栏可不建)
│   ├── sidebar.php
│   ├── side_config.php
│   └── side_*.php
├── page/                 # 可选:独立页面模板
│   └── page.php
├── user/                 # 可选:登录 / 注册 / 用户中心(缺则回退 default)
│   ├── index.php
│   ├── login.php
│   ├── register.php
│   ├── user_auth_lib.php
│   └── user_center_lib.php
├── partials/             # 可选:可复用片段
├── css/
└── js/

3. 主题元信息

写在 header.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 View::getView('module');
字段 说明
Theme Name 后台显示名称(必需)
Version 版本号
Description 简介
Theme Type 可选分类标签,如 cms
Author / Theme Url 作者与主题主页

4. 核心模板与变量

控制器先 include View::getView('header'),再 include 列表或详情模板,最后模板内再 include footer

4.1 列表页 log_list.php

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

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

4.2 详情页 echo_log.php

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

列表与详情中均可:

<?php include View::getView('sidebar'); ?>
<?php include View::getView('footer'); ?>
变量 说明
$site_title 当前页 <title>
$site_key / $site_description SEO keywords / description
$sitename 站点名(系统设置)

头部应输出挂载点,供插件插入 CSS/统计代码:

<?php doAction('index_head'); ?>

页脚:

<?php doAction('index_footer'); ?>

5. 自定义页面

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

<?php
/*@name 关于我们*/
defined('HOPE_ROOT') || exit('access denied!');
?>
<main>
    <h1>关于我们</h1>
    <div><?= $log_content ?></div>
</main>
<?php include View::getView('footer'); ?>
  • @name 后的文字会出现在后台模板下拉里
  • 页面同样会先加载 header.php,模板内记得闭合 footer
  • 复杂站点(如本主题 hopecms)可有多个:page_docs.phppage_download.phppage_generator.php
  • 前台「模板生成器」页可按数据源与条件本地生成文章循环、分类/标签、评论、挂载点等 PHP 片段(交互类似 Sndow 模板工具,输出适配 Hope CMS API)

6. module.php

建议所有主题辅助函数集中在此,并在 header.phprequire_once View::getView('module')

function your_asset($path) {
    return THEME_URL . ltrim($path, '/');
}

function your_brand() {
    $name = trim((string) hope_option('site_brand', ''));
    return $name !== '' ? $name : (string) Option::get('sitename');
}
常量 说明
THEME_PATH 当前主题物理路径
THEME_URL 当前主题 URL(末尾一般无 /,拼接时自行处理)
SITE_URL 站点根 URL(含末尾 /
<link rel="stylesheet" href="<?= your_asset('css/style.css') ?>">
<a href="<?= SITE_URL ?>">首页</a>

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

Url::log($gid);       // 文章
Url::sort($sid);      // 分类
Url::tag($tagname);   // 标签

7. options.php(主题设置)

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

文件 用途
default/options.php 可运行起点(精简实用)
content/theme/options完整的.php CSF 字段大全(不会自动加载,仅对照拷贝)

约定

说明
$prefix 唯一,推荐 {主题目录}_options设定后勿改,否则已存配置失效
读取 hope_option('字段id', '默认值')_hope()
无文件 无主题设置页,主题仍可正常启用
<?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' => [
        [
            'id'      => 'site_brand',
            'type'    => 'text',
            'title'   => '站点品牌名',
            'default' => 'Hope CMS',
        ],
        [
            '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 等。按需拷贝字段到自己的 options.php

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


8. plugins.php(主题钩子)

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

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

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

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

defaultplugins.php 为空壳,可按需扩展。


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

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

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

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

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

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

10. 侧边栏与用户中心

  • 侧边栏widgets/ + side_config.php,详见 侧边栏开发说明
  • 用户中心:优先使用主题 user/;若主题未提供,系统可能回退到 default/user/
  • 登录 / 注册页同理,建议主题内自备完整 user/ 目录,避免混用样式

用户中心模板中可用:

include View::getUserView('index');

11. 挂载点(主题侧)

主题模板负责 埋点,插件负责 注册回调default 的 header/footer 已含常用前台钩子。

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

完整列表见 挂载点手册


12. 检查清单与注意事项

  1. 不硬编码域名,用 SITE_URLTHEME_URLUrl::*
  2. 输出用户内容用 htmlspecialchars
  3. 勿修改 system/;业务扩展用主题 plugins.php 或独立插件
  4. $prefix 与函数名前缀全局唯一
  5. hope_option / _hope 始终带默认值
  6. SITE_URL 已有尾斜杠,拼接路径时避免写成 SITE_URL . '/xxx' 变成双斜杠(可用 rtrim(SITE_URL,'/').'/xxx'
  7. 启用新主题后更新缓存;换主题后检查侧边栏组件是否仍注册

侧边栏开发说明

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

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

目录约定

content/theme/default/
├── module.php              # 其它模板函数(nova_* 等)
└── widgets/                # 有侧边栏时才需要
    ├── sidebar.php         # 默认侧边栏容器
    ├── side_config.php     # $sidebar 组件注册表(后台读取)
    ├── side_search.php     # 组件
    ├── side_newlog.php
    └── ...
文件 作用
widgets/sidebar.php / sidebarN.php 侧边栏外壳;文件名决定后台「侧边栏组」
widgets/side_config.php 中的 $sidebar 向后台声明可用组件类型与默认字段
widgets/{key}.php 单个组件渲染逻辑({key}$sidebar 键一致)

列表页、文章页中引入侧边栏(View::getView 会优先从 widgets/ 解析):

<?php include View::getView('sidebar'); ?>

第二组示例:

<?php include View::getView('sidebar1'); ?>

容器模板

<?php
defined('HOPE_ROOT') || exit('access denied!');
?>
<aside class="sidebar">
    <?php doAction('index_sidebar'); ?>
    <?php if (!hope_render_sidebar_widgets('sidebar')): ?>
        <?php
        // 后台未配置时的兜底:直接 include 组件
        hope_include_sidebar_widget('side_newlog', '最新文章', ['显示数量' => '5']);
        ?>
    <?php endif; ?>
</aside>

要点:

  1. doAction('index_sidebar'):插件可在此插入内容。
  2. hope_render_sidebar_widgets($slot):按组输出;$slot 与文件名一致(sidebar / sidebar1)。
  3. 核心 API 在 system/lib/sidebar.php,主题无需再复制一套。

注册组件(widgets/side_config.php

对照示例主题 content/theme/default/widgets/side_config.php

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

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

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

编写组件文件

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

$limit = (int)hope_widget_field($fields, '显示数量', $widget_config['default']['显示数量'] ?? 5);
$Log_Model = new Log_Model();
$logs = $Log_Model->getHotLog(max(1, $limit));
?>
<div class="widget widget-hotlog">
    <h3 class="widget-title"><?= htmlspecialchars($widget_title ?: '热门文章') ?></h3>
    <!-- ... -->
</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, '输入提示', '搜索…');

hope_widget_field($fields, $name, $fallback):优先取后台已存值,否则用 $fallback

自定义 HTML 组件

无需在 side_config.php 注册。后台添加侧边栏项时类型选「自定义组件」,直接填 HTML;或主题提供 widgets/side_custom.php 统一包装。

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

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

多侧边栏组

  1. widgets/ 增加 sidebar1.phpsidebar2.php…(内容里调用 hope_render_sidebar_widgets('sidebar1')
  2. 后台「菜单 → 侧边栏」会出现组切换 Tab
  3. 添加的组件会写入对应组(菜单项 url 字段存 sidebar / sidebar1…)
  4. 旧数据(url 为空、sideside1 或主题名)自动归入对应 sidebar / sidebar1

渲染流程

后台菜单(type=sidebar, url=slot)
    → Cache menu
    → hope_menu_sidebar_widgets(slot)
    → hope_render_sidebar_widget()
         ├─ typeId 对应 widgets/{typeId}.php → include
         └─ 否则输出自定义 content(或 widgets/side_custom.php)

检查清单

  1. widgets/side_config.php$sidebar 键名与同目录组件文件名一致

  2. 容器已调用 hope_render_sidebar_widgets('sidebar')(或对应组名)

  3. 后台能看到已注册组件,多组时能切换

  4. 未配置组件时有合理兜底

  5. 无侧边栏主题不创建 widgets/,后台侧边栏面板会提示不可用

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

伪静态与 URL 路由

Hope CMS 通过 链接模式(linkmode路由表 控制前台 URL 形态。后台在 设置 → 链接 中配置;核心路由定义于 system/lib/core/option.phpgetEnhancedRoutingTable(),由 Dispatcher 匹配并分发到对应 Controller。

链接模式

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

判断伪静态是否生效:

$linkmode = (string) Option::get('linkmode');
$isRewrite = ($linkmode === '1' || $linkmode === '2');

保存链接设置后,系统会调用 Option::resetRoutingTableCache() 刷新路由缓存。

后台 URL 规则

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

配置项 动态模式默认 伪静态模式默认 控制器
rule_index ?page={%page%} /page/{%page%}/ 首页列表
rule_article ?article={%id%} /article/{%id%}.html 文章详情
rule_page ?id={%id%} /{%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%}/ 微语/归档

规则中可使用占位符,生成链接时由 Url 类替换(system/lib/http/url.php)。

常用占位符

占位符 说明
{%host%} 站点 URL(SITE_URL
{%id%} 数字 ID
{%alias%} 别名(无别名时回退为 ID)
{%page%} 分页页码
{%tag%} 标签名
{%category%} / {%sortname%} / {%sort_alias%} 分类相关
{%year%} / {%month%} / {%day%} 文章发布日期

分页占位符 {%page%} 在生成非分页链接时会被 Url::buildFromRule() 自动剔除。

内置路由一览

除可配置的内容路由外,系统还内置 活动路由type = active),在三种 linkmode 下均参与匹配:

路径 / 参数 控制器 说明
?author=1 Author_Controller 作者页
?keyword=关键词 Search_Controller 搜索
/user?user User_Controller::index 个人中心
/login?login User_Controller::login 登录
/register?register User_Controller::register 注册
/auth_api?auth_api User_Controller::authApi 认证 API
?rest-api=方法名 Api_Controller REST API
/plugin/插件名?plugin=插件名 Plugin_Controller 插件前台页
?resource_alias=别名 Download_Controller 附件下载
POST ?action=addcom Comment_Controller 提交评论
POST ?action=... Like_Controller 点赞

伪静态模式下用户相关路径示例:

/user
/login
/register
/auth_api
/plugin/video

动态模式下对应为:

?user
?login
?register
?auth_api
?plugin=video

请求匹配流程

flowchart TD
    A[浏览器请求] --> B[Web 服务器重写到 index.php]
    B --> C[Dispatcher::setPath 解析路径]
    C --> D[Option::getRoutingTable 获取路由表]
    D --> E[按优先级匹配 pattern]
    E --> F[校验 must_get / GET 参数]
    F --> G[setMatchedRoute 写入 $_GET]
    G --> H[Controller 方法执行]

要点:

  1. Dispatcher::setPath()REQUEST_URI 取 path,并去掉 SITE_URL 中的子目录前缀
  2. 伪静态模式跳过纯 query 型内容路由;动态模式跳过纯 path 型 rewrite 路由
  3. 活动路由排在默认首页路由之前,避免 ?category=1 被首页抢走
  4. 插件可通过 HopeHooks::ROUTING_REGISTER 向路由表头部追加规则

Web 服务器配置

使用 伪静态(linkmode=1)index.php 式(linkmode=2) 时,需将不存在的文件/目录请求转发到 index.php

Apache(站点根目录)

index.php 同级创建或编辑 .htaccess

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

若安装在子目录(如 /hopecms/),将 RewriteBase 改为 /hopecms/

Nginx

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

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

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

IIS

需安装 URL Rewrite 模块,将请求重写到 index.php。Hope CMS 已兼容 HTTP_X_REWRITE_URL 头。

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

生成链接(开发)

主题与插件应使用 Url 类或 hope_resolve_user_url(),不要手写路径:

Url::log($gid);              // 文章/页面
Url::sort($sid);             // 分类
Url::tag($tagname);          // 标签
Url::logPage();              // 首页分页
Url::userCenter(['api' => 1]); // 个人中心 API
Url::plugin('video', ['vid' => 1]); // 插件页(动态模式带 query)

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

插件扩展伪静态

插件在站点 已开启 linkmode 1 或 2 时,可注册独立 path 规则。标准步骤:

  1. 新建 {插件名}_rewrite.php,实现 xxx_register_rewrite_routes($table, &$routes)
  2. 在插件入口 addAction(HopeHooks::ROUTING_REGISTER, 'xxx_register_rewrite_routes')
  3. 可选:提供 processor 回调,将路径参数写入 $_GET

视频扩展插件 为例(content/plugin/video/video_rewrite.php):

URL 示例 含义
/video 视频列表
/video/12 视频详情(ID)
/video/slug/别名 按别名访问
/video/cat/1 分类列表
/video/cat/1/page/2 分类分页

核心注册代码:

function video_register_rewrite_routes($table, &$routes) {
    if (!video_is_active() || !video_use_rewrite_urls()) {
        return;
    }

    $p = preg_quote(video_rewrite_prefix(), '#');
    $newRoutes = [
        [
            'type'           => 'rewrite',
            'model'          => 'Plugin_Controller',
            'method'         => 'loadPluginShow',
            'pattern'        => "/{$p}/{%vid&type=num%}",
            'processor'      => 'video_route_processor',
            'route_key'      => 'vid',
            'request_method' => '',
        ],
        // ... 其余列表、分类、slug 规则
    ];

    // 插入到路由表前部,优先于内容路由匹配
    $routes = array_merge($newRoutes, $routes);
}

video_use_rewrite_urls() 典型判断:

function video_use_rewrite_urls() {
    $cfg = video_get_config();
    if (($cfg['rewrite'] ?? 'y') !== 'y') {
        return false;
    }
    $linkmode = (string) Option::get('linkmode');
    return $linkmode === '1' || $linkmode === '2';
}

路由项字段说明

字段 说明
type rewrite(path)、query(动态 query)、active(活动路由)
model / method 控制器类名(不含 _Controller 后缀)与方法
pattern 匹配模式,支持 {%param%}{%param&type=num%}
must_get 必须存在的 $_GET
args 捕获组到参数名的映射,如 category@alias
processor 匹配成功后的参数处理回调
request_method 限制 GET / POST,空表示不限制
prefix 路由前缀,命中时自动设置 $_GET[prefix]

路由 pattern 中的类型修饰:

写法 含义
{%id%} 任意非 / 字符
{%id&type=num%} 仅数字
{%slug&type=alnum%} 字母数字

钩子扩展

addAction(HopeHooks::ROUTING_REGISTER, 'myplugin_register_routes');

function myplugin_register_routes($table, &$routes) {
    $routes = array_merge([
        [
            'type'    => 'rewrite',
            'model'   => 'Plugin_Controller',
            'method'  => 'loadPluginShow',
            'pattern' => '/myplugin/{%id&type=num%}',
            'processor' => function ($params, $route) {
                $_GET['plugin'] = 'myplugin';
                $params['plugin'] = 'myplugin';
                return $params;
            },
        ],
    ], $routes);
}

完整挂载点说明见 挂载点手册

常见问题

开启伪静态后全部 404

  • 检查 Web 服务器是否将请求重写到 index.php
  • 子目录安装时确认 RewriteBaseSITE_URL 配置正确
  • 确认 linkmode12 且规则已保存

首页正常,文章/分类 404

  • 检查 rule_articlerule_category 等是否与服务器重写兼容
  • 自定义规则勿遗漏必要占位符(如 {%id%}{%alias%}
  • 清除 content/cache/ 下缓存后重试

插件伪静态不生效

  • 站点 linkmode 必须为 12
  • 插件设置中需开启「启用伪静态 URL」
  • 确认 routing_register 钩子已注册且插件已启用
  • 路由 pattern 比系统路由更具体时,应通过 array_merge($newRoutes, $routes) 插到表头

动态模式下用户中心 API 异常

  • 个人中心 API:?user&api=1&action=profile
  • 认证 API 专用路由 /auth_api(或 ?auth_api),无需依赖 ?api=1 也可进入处理逻辑
  • 生成链接时使用 Url::userCenter()Url::authApi(),不要硬编码

相关文件

文件 职责
system/lib/core/option.php 路由表生成、linkmode 切换
system/lib/http/dispatcher.php 路径解析与路由匹配
system/lib/http/url.php 按规则生成前台链接
system/lib/hooks.php HopeHooks::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(Option::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=1710000000&req_nonce=abc...&req_sign=xxxx

缺少参数、签名错误或 nonce 重放时返回 auth param error / sign error / nonce required / replay detected

已登录管理员/用户携带站点认证 Cookie(AUTH_COOKIE_NAME)时,可免 API Key,且 author_uid 自动取当前用户。

响应格式

成功:

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

失败:

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

认证失败:code401
鉴权失败使用 Output::authError,HTTP 状态码与 code 字段以实际返回为准。

文章接口

article_list — 文章列表

GET ?rest-api=article_list
参数 类型 说明
page int 页码,默认 1
count int 每页条数,默认跟随首页设置
sort_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

需鉴权。主要 POST 字段:

字段 说明
title 标题(必填)
content 正文(必填)
excerpt 摘要
sort_id 分类 ID
tags 标签,逗号分隔
cover 封面 URL
draft y 草稿 / n 发布
alias 别名
top / sortop 置顶 / 分类置顶
allow_remark 是否允许评论
password 阅读密码
template 自定义模板

article_update — 更新文章

POST ?rest-api=article_update

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

分类与微语

接口 方法 说明
sort_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 参数(与 Session 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 文件字段
avatar_qq POST 使用 QQ 头像,字段 qq
recharge POST 创建充值订单
recharge_records GET 充值记录,支持 pageper_page
invite_info GET 邀请码与奖励统计
forum_posts GET 我的论坛文章,返回含 url
forum_get GET 单篇论坛文章,id
forum_save POST 发布或更新论坛文章
forum_delete POST 删除论坛文章,id
forum_sorts GET 可选论坛分类
my_comments GET 我的评论,含 comment_url 锚点
comment_reply POST 回复评论,pidcontent
my_media GET 我的媒体库
media_upload POST 上传媒体
media_delete POST 删除媒体,id

业务实现位于 system/app/service/user_center.php。主题可在 user/ 目录下提供个人中心模板,并通过 js/user_center.js 对接 API。

插件可通过挂载点 HopeHooks::USER_CENTER_API 扩展自定义 action

媒体上传

POST ?rest-api=upload

需 API Key 鉴权。multipart/form-data 字段:

字段 说明
file 文件
sid 分类 ID(可选)
author_uid 作者 UID,默认 1

成功返回 media_idurlfile_info

支付接口

Pay_Controller 处理,不依赖 OpenAPI 开关。常用于收银台与异步通知:

接口 说明
pay_create 创建支付订单
pay_cashier 收银台页面数据
pay_status 查询订单状态
pay_notify 支付平台异步回调(由网关服务器调用)

网关密钥、回调 URL 等在后台 支付设置 中配置;主题/插件只负责创建业务订单并跳转收银台。参数与返回值以 system/app/controller/pay_controller.php 及当前支付插件为准,接入前请对照源码与后台说明。

限流:若后台开启了 API 访问限流(设置 → 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);

$ch = curl_init($base . '?rest-api=article_list&page=1&count=5&req_time=' . $req_time . '&req_nonce=' . $req_nonce . '&req_sign=' . $sign);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($ch);
curl_close($ch);

$data = json_decode($body, true);

扩展 API

优先通过插件扩展,避免直接改核心 Api_Controller(升级会被覆盖):

  1. 个人中心类:挂载 HopeHooks::USER_CENTER_APIdoOnceAction)接管自定义 action
  2. 独立前台接口:插件 _show.php + 自建鉴权,或注册路由后由插件处理
  3. 确需 REST 风格:可在插件中于 init 钩子里拦截 rest-api 参数并 Output::okexit(注意与核心方法名冲突)

若维护私有分支必须改核心:在 Api_Controller 增加 private function your_api(),方法名即 rest-api 值;需鉴权则开头调用 $this->auth() / $this->checkApiKey()

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