XIUNOX应用开发技能

Polar Sponsor
爱发电 赞助
.NET 9.0

XIUNOX 插件开发专家。 当用户要求写/改/调试 XIUNOX 插件、加 hook、加后台设置页、加路由、 加签到/标签/勋章/举报/收藏等新功能插件、创建 Service 类、写 install/uninstall 脚本、 调试插件不生效、做插件架构设计时触发。 也适用于检查现有插件是否符合规范、修复扫描器拦截的 fatal/warning、 将 jQuery/Alpine.js 旧插件迁移到 htmx 4 架构。

XIUNOX 插件开发 Skill

功能概述

XIUNOX 插件开发 Skill是一项面向实际任务的技能,主要用于配套完整手册 : plugindev/ 目录有 8 个分册的完整开发手册(架构/结构/hooks/API/前端/AI 协作/运行时安全/登录安全),本 Skill 是精简版, 深入细节查 plugindev , 写代码对照本文件;完整手册下载地址 :https://github.com/domidesign/xiunox/tree/main/。

核心要点

  • 它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
  • 从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。
  • 实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;

使用与执行

若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;

结果检查与注意事项

涉及批量任务时,还应保存进度,避免中断后重复操作。该技能适合用于一次性任务,也可以接入自动化工作流,与其他技能或上层代理配合完成更完整的业务链路;在组合使用时,应明确每一步的输入输出关系,并避免不同步骤之间出现参数冲突。

XIUNOX 插件开发 Skill

配套完整手册:plugindev/ 目录有 8 个分册的完整开发手册(架构/结构/hooks/API/前端/AI 协作/运行时安全/登录安全),本 Skill 是精简版,深入细节查 plugindev,写代码对照本文件。

完整手册下载地址:https://github.com/domidesign/xiunox/tree/main/docs/plugindev (本项目不自带 plugindev/ 目录时,从该 GitHub 仓库下载后放到 docs/plugindev/ 即可使用本 Skill 的全部交叉引用)

核心架构(必须先理解)

插件是编译时合并,不是运行时分发。 把 hook 文件放到 plugin/

/hook/ 就等于注册了 hook,没有 add_hook() 函数。_include() 编译时把 hook 内容物理拼进源文件,缓存到 tmp/。

hook 文件名(含扩展名)必须和源标记一模一样:

  • PHP 源码标记:// hook thread_create_thread_end.php
  • 模板标记:

模型三层命名: __ 原始层(纯DB)→ 单 _ 业务层(缓存/计数/通知)→ _format 装饰层。插件永远调单下划线业务层。

硬规则(不可违反)

禁止

  • ❌ jQuery($()、.on()、.ajax())
    • 07-17 起项目内置 jQuery 兼容 shim(view/js/xiuno-modern.js 暴露 window.jQuery = $),让 20 个存量插件 JS 和 .htm 模板内联 $ 代码继续工作。新插件/新代码强制用 XN API(XN.toast() / XN.ajax() / XN.confirm() / XN.$()),存量 $ 代码暂不强制重写、留待后续阶段逐个迁移
    • shim 已覆盖(存量代码可继续用):$() 选择器链式、$.fn.*(BS5 桥接 modal/dropdown/tooltip/tab/collapse + loading/checked/serializeObject 等 17 个扩展)、$.ajax/$.get/$.post/$.getJSON、$.alert/$.confirm/$.ajax_modal、$.Event、xn.* PHP 函数库(intval/json_encode/url 等 30+)
    • shim 不支持(写了会静默失败或报错,必须改用 XN.ajax() + async/await 或原生 fetch):jqXHR.done/.fail/.always 链式回调、同步 xhr(async: false)、jsonp/script dataType、$.when() 多请求编排、.animate() 队列动画
  • ❌ Alpine.js(x-data、x-show、x-bind、x-model 等)
  • ❌ idiomorph / alpine-morph 扩展
  • ❌ htmlspecialchars 裸写 → 用 esc_html() / esc_attr() / esc_js()
  • ❌ POST 表单不带 CsrfService::input() + CsrfService::check()
  • ❌ 裸 include → 用 _include()
  • ❌ window.__xxxData → 状态放 DOM(data-*、hidden input)
  • ❌ 后台(admin/)用 htmx
  • ❌ htmx 4 的 htmx:config:request 事件中修改 DOM 元素 → 该事件触发时 FormData 已构建完成,修改 DOM(如动态添加 input)不会影响请求体。必须直接修改 evt.detail.ctx.request.body(FormData 对象)来追加参数。
    • ❌ 错误写法:在 htmx:config:request 中 document.createElement('input') + appendChild
    • ✅ 正确写法:evt.detail.ctx.request.body.append('key', 'value')
  • ❌ 用 APP_PATH 生成 '; echo '';
    // static/js/poll_post.js(纯静态)
    var I18N = window.XNX_POLL_I18N_POST || { options: '选项', min_options: '至少需要 2 个选项' };
    XN.toast(I18N.min_options, 'warning');
    
  • 💡 判断规则:只要文件扩展名是 .js(非 .htm/.php),就当作纯静态文件,禁止写任何 代码
  • ❌ 后台插件设置页/管理页模板(view/htm/setting.htm、view/htm/xxx_admin.htm)不 include 后台 header/footer → 这些模板是独立页面,必须首尾分别 include _include(ADMIN_PATH . 'view/htm/header.inc.htm') 和 footer.inc.htm,否则页面没有后台顶部导航栏和侧边栏(光秃秃只有表单)。前台插件页面则应 include APP_PATH . 'view/htm/header.inc.htm'(非 ADMIN_PATH)。⚠️ 已违反 1 次(xnx_poll setting.htm + poll_admin.htm 两个模板都漏 include)
    • ✅ 正确范式:
      
      
      ...
    • 💡 参考:xnx_related/view/htm/setting.htm、xnx_appcenter/view/htm/setting.htm 已有正确 include
  • ❌ .htm 模板 hook 文件以 开头(会白屏!只能用 )
  • ❌ .htm 模板 hook 文件用 .php 扩展名(文件名必须和源码标记一模一样)
  • ❌ 数据库表用 utf8(必须 utf8mb4 支持 emoji)
  • ❌ 后台 setting.php 缺少 $gid != 1 && $gid != 2 AND message(-1, '无权限'); 权限检查
  • ❌ SQL 拼接用户输入(必须 intval() 转义)
  • ❌ 裸用 db_sql_find / db_sql_find_one / db_exec 做普通查询 → 优先用 db_find / db_find_one / db_count / db_find_group / db_find_one_group(防 SQL 注入)
  • ❌ 保留复杂 SQL(JOIN/系统表/复杂 DML)时不加注释 → 必须加包含 保留 db_sql_find 或 保留 db_exec 关键字的注释(扫描器据此跳过报告)
  • ❌ 帖子列表页 hook 中 new Service() + 查库 N 次(用静态缓存)
  • ❌ db_insert 后不检查返回值就 message(0, '成功')(字段不存在会静默失败)
  • ❌ 卸载脚本用 unstall.php(旧拼写) → 必须用 uninstall.php(标准拼写),核心已兼容回退但新插件禁止用旧拼写
  • ❌ 数据库结构变更在 install.php/setting.php 加字段自愈代码 → 必须走 upgrade.php 幂等迁移 + 递增 conf.json.version
  • ❌ esc_attr(json_encode(array(...))) 嵌套括号写一行(易出错,先存变量再转义)
  • ❌ 硬编码 URL 后缀(如 /thread-{tid}.htm、/forum-{fid}.htm)→ 必须用 url() 函数适配伪静态格式(url_rewrite_on 支持 0~5 六种模式)
  • ❌ 拼接 $site_url . '/xxx.htm' 做缓存刷新/跳转等 → 必须用 $site_url . url("xxx") 适配伪静态
  • ❌ 单行注释 // 和 # 中包含 ?>:PHP 会把单行注释中的 ?> 当作 PHP 代码块结束标签,导致后续代码被当作纯文本输出,触发「headers already sent」错误,页面直接显示代码
    • 错误示例:// 模板中调用:
    • 正确写法:// 模板中调用示例:echo thread_url($tid);(去掉 和 ?>)
    • 块注释 /* */ 中可以包含 ?>,不受影响
  • ❌ 模板里硬编码 url("thread-$tid") 字符串拼接 → 必须用命名快捷函数(thread_url($tid))或 route_url('thread', ['tid'=>$tid])
  • ❌ 插件自定义路由直接写 url("myplugin-$id") → 必须通过 hook/model_route_table_end.php 注册到路由表
  • ❌ 插件直接调用 route_table() 修改返回值(会破坏静态缓存)→ 只能通过 model_route_table_end.php hook 修改局部 $routes 变量
  • ❌ 跨插件共享配置时,保存和读取用不同的存储键(如存到 setting_set('xnx_checkin', ...) 但从 setting_get('plugin_discover_items') 读取)→ 保存和读取必须用同一个 key
  • ❌ setting_set('key', xn_json_encode($arr)) 然后 setting_get() 后 xn_json_decode() → setting_set/get 原生支持数组存取,不需要 JSON 中转
  • ❌ 模板中
  • 热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    秒哒创建应用手册
    秒哒创建应用手册

    共0课时 | 0人学习

    MyEclipse学习中心
    MyEclipse学习中心

    共0课时 | 0人学习

    Dify零基础教程
    Dify零基础教程

    共0课时 | 160人学习