主题和插件加载后,可以直接使用纸鱼博客提供的全局函数和核心类。本文只介绍适合扩展开发的公共接口;未在本文列出的内部方法不保证版本兼容。
输出与安全
e() HTML 转义
将用户输入、文章标题、设置值和 URL 输出到 HTML 前,使用 e():
<h1><?= e($title) ?></h1>
<a href="<?= e($url) ?>">查看</a>只有系统已经渲染过的 $contentHtml 可以直接输出。不要对用户输入使用 echo,也不要把未经校验的内容拼接到 <script> 中。
md() Markdown 渲染
$html = md($markdown);返回 HTML。是否允许原始 HTML 由后台“站点设置 → 文章与内容”控制。
URL 和资源
url_to() 站内链接
$postUrl = url_to('/post/hello-world');
$loginUrl = url_to('/login');函数会自动适配伪静态开关和子目录部署。不要手动拼接 index.php。
api_url() API 地址
$url = api_url('/posts?page=1');根据站点是否启用伪静态,生成 /api/posts?... 或 /index.php?p=api/posts&...。
absolute_url() 绝对地址
$url = absolute_url('/post/hello-world');根据 config.php 中的 site_url 生成绝对 URL,适合 RSS、邮件、Open Graph 和 Webhook。传入完整的 http:// 或 https:// 地址时会原样返回。
asset_url() 和 theme_asset_url()
<link rel="stylesheet" href="<?= e(asset_url('/css/app.css')) ?>">
<script src="<?= e(theme_asset_url('example', 'assets/app.js')) ?>" defer></script>asset_url() 用于 public/ 下的系统资源,theme_asset_url() 用于主题目录资源。资源路径不能包含 ..。
模板渲染
render()
渲染主题模板,主题文件优先,系统模板兜底:
echo render('notice', ['message' => '你好']);对应文件为当前主题的 notice.php。传入的数据会合并到当前模板上下文。
render_partial()
用于渲染局部模板:
<?= render_partial('post-card', ['post' => $post]) ?>get_header() 和 get_footer()
主题页面通常使用这两个函数加载公共头部和页脚:
<?php get_header(); ?>
<main>页面内容</main>
<?php get_footer(); ?>站点和主题设置
settings()
读取后台“站点设置”:
$siteName = settings('site_name', '纸鱼博客');
$all = settings();传入键名时返回单个值,不传参数时返回全部设置。返回值可能是字符串、数字或数组,请根据实际类型处理。
theme_value()
读取当前主题的设置值,未保存时使用 theme.json 中的默认值:
$color = theme_value('accent_color', '#2563eb');site_name()
读取站点名称:
echo e(site_name());nav_items()、widget_items() 和 friend_links()
分别读取前台可见的导航、组件和友情链接:
foreach (nav_items() as $item) {
echo '<a href="' . e($item['url']) . '">' . e($item['label']) . '</a>';
}widget_items($area) 的默认区域是 sidebar,自定义区域名只能使用小写字母、数字、下划线和连字符。
用户和权限
current_user()
获取当前登录用户,未登录时返回 null:
$user = current_user();
if ($user !== null) {
echo e($user['username'] ?? '');
}用户数组包含数据库字段,可能包含敏感信息。只输出明确需要的字段,不要把整个数组发送到前台或写入日志。
is_logged_in() 和 is_admin()
if (is_logged_in()) {
// 已登录
}
if (is_admin()) {
// 当前用户是管理员
}这两个函数适合控制模板展示。插件后台接口仍必须使用后台权限中间件或 Auth::requireCapability() 做服务端校验。
日期和表单
format_date()
把日期或时间字符串格式化为站点时区下的日期:
echo e(format_date($post['published_at'] ?? null));
echo e(format_date($post['published_at'] ?? null, 'yyyy-MM-dd HH:mm'));csrf_field() 和 csrf_token()
用于站内表单和带状态变更的请求:
<form method="post">
<?= csrf_field() ?>
<button type="submit">保存</button>
</form>自定义 POST 操作必须验证 CSRF token,不能只依赖登录状态。
Action 和 Filter
Action
Action 用于在某个事件发生后执行代码,不改变原始数据:
add_action('after_post_published', function (array $post): void {
error_log('已发布:' . ($post['title'] ?? ''));
}, 10);Filter
Filter 接收当前值并返回修改后的值:
add_filter('frontend_meta', function (array $meta, array $context): array {
$meta['robots'] = 'noindex';
return $meta;
}, 10);插件开发优先使用插件上下文的 $ctx->on() 和 $ctx->filter(),系统会在停用插件时自动移除这些钩子。完整事件列表请参阅插件开发。
数据库访问
Pafish 通过 PDO 提供 DB 类,模板和插件可以使用以下方法:
$posts = DB::fetchAll(
'SELECT id, title FROM posts WHERE status = ? ORDER BY id DESC LIMIT 10',
['PUBLISHED']
);
$post = DB::fetchOne('SELECT * FROM posts WHERE id = ?', [$id]);
$count = DB::value('SELECT COUNT(*) FROM posts WHERE status = ?', ['PUBLISHED']);常用方法:
方法 | 返回值 |
|---|---|
|
|
| 多行数组 |
| 单行数组或 |
| 第一列的值 |
| 受影响行数 |
| 最近插入 ID |
| 事务回调结果 |
始终使用参数绑定,禁止把用户输入直接拼接进 SQL。插件自己的数据优先使用 $ctx->getData() 和 $ctx->setData(),避免依赖 Pafish 内部表结构。
核心类别名
以下类可以直接使用短类名,也可以使用完整命名空间:
别名 | 对应类 | 常用用途 |
|---|---|---|
|
| 数据库访问 |
|
| URL 生成 |
|
| 读取 |
|
| 查询主题、模板和主题设置 |
|
| 底层钩子管理 |
通常不需要直接调用 Hooks,使用 add_action()、add_filter() 或插件上下文即可。
缓存
需要缓存只读数据时可以使用 Pafish\Core\Cache:
use Pafish\Core\Cache;
$value = Cache::get('example:key');
Cache::set('example:key', ['ready' => true], 300);
Cache::delete('example:key');缓存键只能使用字母、数字、冒号、下划线、连字符和 /,不能包含 ..。缓存不是持久数据,不能用来保存订单、设置或用户信息。
开发原则
不要直接读取或修改
$_POST后拼接 SQL;使用参数绑定和严格校验。不要输出完整用户对象、配置数组或插件设置中的密钥。
不要直接修改系统模板和核心文件,优先使用主题覆盖与插件钩子。
自定义前台 HTML、脚本和外部请求都要考虑转义、CORS、超时和权限。