You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Local插件重写Moodle核心分类表单以添加更多字段?

解决方案:用Local插件扩展Moodle分类表单

完全可以通过Local插件实现分类表单的字段扩展,你之前的问题在于直接沿用核心表单的文件结构——Moodle会优先加载核心文件,因此需要通过表单继承+钩子拦截的方式替换系统默认表单。

具体操作步骤

1. 创建自定义表单类,继承核心表单

在Local插件目录下新建classes/form/editcategory_form.php,编写自定义表单类,继承核心的editcategory_form并添加字段:

defined('MOODLE_INTERNAL') || die();

// 加载核心分类表单文件
require_once($CFG->dirroot . '/course/editcategory_form.php');

class local_yourplugin_editcategory_form extends editcategory_form {

    protected function definition() {
        // 先加载核心表单的原有字段
        parent::definition();

        $mform = $this->_form;

        // 添加自定义字段(示例为文本框,可按需修改为下拉框、编辑器等)
        $mform->addElement('text', 'custom_category_field', '自定义分类字段');
        $mform->setType('custom_category_field', PARAM_TEXT);
        // 可选:添加帮助按钮,需在插件语言包中配置对应帮助文本
        $mform->addHelpButton('custom_category_field', 'custom_category_field', 'local_yourplugin');
    }

    protected function definition_after_data() {
        parent::definition_after_data();

        $mform = $this->_form;
        // 从自定义表中读取已有值,填充到表单
        $categoryid = $this->_customdata['category']->id ?? 0;
        if ($categoryid) {
            global $DB;
            $fielddata = $DB->get_record('local_yourplugin_category_fields', ['categoryid' => $categoryid]);
            if ($fielddata) {
                $mform->setDefault('custom_category_field', $fielddata->custom_field);
            }
        }
    }
}

2. 拦截核心表单加载,替换为自定义类

在插件的lib.php中通过before_http_headers钩子,在核心表单加载前替换类指向:

defined('MOODLE_INTERNAL') || die();

function local_yourplugin_before_http_headers() {
    global $PAGE;

    // 仅在分类编辑页面生效
    if ($PAGE->pagetype === 'course-editcategory') {
        // 加载自定义表单类
        require_once($CFG->dirroot . '/local/yourplugin/classes/form/editcategory_form.php');
        // 将核心表单类别名为自定义类,让系统实例化时调用我们的表单
        class_alias('local_yourplugin_editcategory_form', 'editcategory_form');
    }
}

3. 存储自定义字段数据

3.1 创建数据库表

在插件的db/install.xml中定义存储自定义字段的表:

<?xml version="1.0" encoding="UTF-8"?>
<XMLDB PATH="local/yourplugin/db" VERSION="2024010100" COMMENT="Custom category fields storage">
    <TABLE NAME="local_yourplugin_category_fields" COMMENT="Stores custom fields for course categories">
        <FIELDS>
            <FIELD NAME="categoryid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Linked course category ID"/>
            <FIELD NAME="custom_field" TYPE="text" NOTNULL="false" COMMENT="Value of the custom field"/>
        </FIELDS>
        <KEYS>
            <KEY NAME="primary" TYPE="primary" FIELDS="categoryid"/>
            <KEY NAME="categoryid" TYPE="foreign" FIELDS="categoryid" REFTABLE="course_categories" REFFIELDS="id"/>
        </KEYS>
    </TABLE>
</XMLDB>

3.2 监听分类保存事件,存储字段值

在插件的db/events.php中注册事件监听:

<?xml version="1.0" encoding="UTF-8"?>
<EVENTS>
    <EVENT NAME="core_course_category_created">
        <HANDLER FUNCTION="local_yourplugin_save_custom_field" METHOD="standard"/>
    </EVENT>
    <EVENT NAME="core_course_category_updated">
        <HANDLER FUNCTION="local_yourplugin_save_custom_field" METHOD="standard"/>
    </EVENT>
</EVENTS>

然后在lib.php中实现保存逻辑:

function local_yourplugin_save_custom_field($event) {
    global $DB;

    $categoryid = $event->objectid;
    $customvalue = optional_param('custom_category_field', '', PARAM_TEXT);

    // 更新或插入记录
    $record = $DB->get_record('local_yourplugin_category_fields', ['categoryid' => $categoryid]);
    if ($record) {
        $record->custom_field = $customvalue;
        $DB->update_record('local_yourplugin_category_fields', $record);
    } else {
        $newrecord = new stdClass();
        $newrecord->categoryid = $categoryid;
        $newrecord->custom_field = $customvalue;
        $DB->insert_record('local_yourplugin_category_fields', $newrecord);
    }
}

4. 升级插件并测试

  • 进入Moodle站点管理的「插件升级」页面,完成插件升级
  • 打开分类编辑页面,即可看到新增的自定义字段,提交后数据会自动存储到自定义表中

额外提示

  • 若使用Moodle 3.7及以上版本,也可以直接利用核心的自定义字段功能(无需编写插件):进入「站点管理 -> 自定义字段 -> 课程分类」即可添加字段,这种方式更轻量化
  • 如需添加复杂字段类型(如文件上传、多选框),直接在definition()方法中调用对应表单元素API即可

内容的提问来源于stack exchange,提问作者Hussam Aj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 12:35:25