搜索全站
插件 12 分钟阅读

WordPress 表单数据存储与导出:条目留存策略与 GDPR 合规做法

表单里的姓名、电话、邮箱属于个人信息。本文讲清主流表单插件的数据存放在哪张表、如何自动清理过期条目、如何用 WordPress 内置工具完成个人数据导出与擦除。

U
UFO_PF 2022-01-02 · 阅读 12 分钟
Wo 插件
阅读提示
本文约 4,674 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:表单数据是最容易被忽略的「个人信息仓库」

一个跑了两年的站点,表单条目里可能躺着几千条真实姓名、手机号、邮箱,甚至身份证照片和营业执照。它们通常散落在插件自建的数据表、媒体库的上传目录、以及若干封邮件通知里。很少有站长能完整回答三个问题:这些数据存在哪、保存多久、客户要求删除时能不能删干净。

这在过去只是运维习惯问题,现在则是合规问题。面向欧洲用户的站点要满足 GDPR 的「访问权、可携带权、被遗忘权」;面向国内用户的站点,个人信息保护相关法规同样要求「最小必要」与「限期留存」。好消息是,WordPress 内置了个人数据导出与擦除的工具框架,插件也可以通过钩子接入——你要做的只是把它用起来。

原理分析:数据散在四个地方

存放位置 典型来源 清理难点
插件自建数据表 WPForms、Fluent Forms、FluentCRM 等 不在文章表里,容易被备份遗漏
自定义文章类型 Flamingo(CF7 的条目存储扩展,使用 flamingo_inbound 等文章类型) 走回收站机制,需强制删除
上传目录 表单的文件上传字段 数据库删了文件还在
邮件通知 通知邮件副本 分散在多个邮箱

WordPress 的隐私工具位于后台「工具 → 导出个人数据」与「工具 → 擦除个人数据」。它们的工作方式是:管理员输入邮箱发起请求 → 站点收集所有「导出器 / 擦除器」登记的数据 → 生成导出文件或执行删除 → 管理员确认。插件通过 wp_privacy_personal_data_exporters 和 wp_privacy_personal_data_erasers 两个过滤器把自己的数据登记进去。很多表单插件已经登记过,但自建的条目表或自定义开发的表单往往没有登记,这正是本文要补上的部分。

保姆级实操:留存策略 + 自动清理 + 合规导出

步骤1:先盘点数据在哪。 用 SQL 看看各条目表的规模,不要凭感觉。

-- 盘点常见表单插件的条目表规模(表名按实际安装调整)
SELECT 'flamingo_inbound' AS src, COUNT(*) AS cnt FROM wp_posts WHERE post_type = 'flamingo_inbound'
UNION ALL
SELECT 'wpforms_entries', COUNT(*) FROM wp_wpforms_entries
UNION ALL
SELECT 'fluentform_submissions', COUNT(*) FROM wp_fluentform_submissions;

步骤2:制定留存周期并写进隐私政策。 常见做法是:销售线索保留 12 个月,未转化线索 6 个月后删除,含身份证等敏感文件的条目 3 个月内删除。把具体周期写进隐私政策页面,这是合规的基本要求,也是回答客户询问的依据。

步骤3:配置自动清理。 用 WP-CLI 加系统计划任务是最稳的做法,避免依赖 WP-Cron。

# 每周清理一次:删除 180 天前的 Flamingo 条目(含回收站中的)
0 4 * * 1 wp post delete $(wp post list --post_type=flamingo_inbound \
  --date_query='before:180 days ago' --format=ids) --force > /dev/null 2>&1

或者用 WordPress 的计划任务在站内执行:

<?php
// 每日清理过期条目(示例:删除 180 天前的 Flamingo 收件)
if ( ! wp_next_scheduled( 'mf_purge_old_entries' ) ) {
    wp_schedule_event( time(), 'daily', 'mf_purge_old_entries' );
}
add_action( 'mf_purge_old_entries', function () {
    $ids = get_posts( array(
        'post_type'      => 'flamingo_inbound',
        'posts_per_page' => 200,
        'fields'         => 'ids',
        'date_query'     => array( array( 'before' => '180 days ago' ) ),
    ) );
    foreach ( $ids as $id ) {
        wp_delete_post( $id, true ); // 第二个参数为 true 表示强制删除
    }
} );

步骤4:登记自定义数据的导出器。 若表单数据存在自建表里,用 wp_privacy_personal_data_exporters 登记,这样客户提交导出请求时,数据会自动包含在导出文件中。

<?php
// 让自建表单表接入 WordPress 的个人数据导出
add_filter( 'wp_privacy_personal_data_exporters', function ( $exporters ) {
    $exporters['mf-custom-form'] = array(
        'exporter_friendly_name' => '自定义表单条目',
        'callback'               => 'mf_custom_form_exporter',
    );
    return $exporters;
} );

function mf_custom_form_exporter( $email_address, $page = 1 ) {
    global $wpdb;
    $items = array();
    $rows  = $wpdb->get_results( $wpdb->prepare(
        "SELECT * FROM {$wpdb->prefix}mf_form_entries WHERE email = %s",
        $email_address
    ) );
    foreach ( $rows as $row ) {
        $items[] = array(
            'group_id'    => 'mf-custom-form',
            'group_label' => '自定义表单条目',
            'item_id'     => 'mf-entry-' . $row->id,
            'data'        => array(
                array( 'name' => '姓名', 'value' => $row->name ),
                array( 'name' => '电话', 'value' => $row->phone ),
                array( 'name' => '提交时间', 'value' => $row->created_at ),
            ),
        );
    }
    return array( 'data' => $items, 'done' => true );
}

步骤5:同步处理上传的文件。 数据库条目删了,上传目录里的文件还在,这是最常被漏掉的一环。删除条目时要一并清理对应附件。

# 找出 uploads 中疑似表单上传的目录并统计体积(确认后再删)
du -sh wp-content/uploads/*/ 2>/dev/null | sort -hr | head -10

步骤6:走一遍内置的导出与擦除流程。 用测试邮箱发起一次导出请求,确认生成的 JSON / HTML 文件里包含了表单数据;再发起一次擦除请求,确认条目被删除。

# 清理过期的个人数据导出文件(WordPress 自带计划任务会自动执行)
wp cron event list | grep -i privacy
wp cron event run wp_privacy_delete_old_export_files

步骤7:把通知邮件也纳入管理。 通知邮件里的个人信息同样属于个人数据。要么缩短邮件的保留期,要么把通知改成「只包含必要字段 + 后台查看链接」,减少数据扩散面。

步骤8:记录处理日志。 每次执行导出或擦除,留下时间、操作人、范围记录。合规检查时,这份日志就是证据。

常见踩坑

  1. 只删数据库不删文件。条目删了,wp-content/uploads 里的身份证照片还能通过 URL 直接访问,风险更大。
  2. 回收站没清空。wp_delete_post() 默认进回收站,数据依然存在,必须传第二个参数 true 强制删除;或者像Advanced Database Cleaner 清理冗余数据那样定期清理。
  3. 导出文件本身成了泄露源。导出链接通过邮件发送,链接在有效期内被转发就会泄露数据。WordPress 生成的导出文件会定期清理,别把它挪到公开目录。
  4. 备份里还留着已删除的数据。客户要求删除后,历史备份里依然存着旧数据。要在隐私政策里说明备份的保留周期,并确保备份加密存储。
  5. 擦除请求被忽略。管理员没及时处理后台的擦除请求,超期即构成违规。指定责任人并设提醒。
  6. 案例:某欧洲客户的 WordPress 站点收到数据删除请求,运营同学在后台删了表单插件里看到的条目就回复「已删除」。半年后对方做合规审计,发现 wp-content/uploads 里仍可访问其上传的身份证明扫描件,且历史备份里也有完整记录,最终被要求出具整改说明。教训是:删除动作必须覆盖数据库、文件、备份三个层面,缺一不可。
  7. 留存周期没有写在任何地方。客户问「你们保存我多久的数据」,客服答不上来。写进隐私政策,并且真的按它执行。
  8. 多个表单插件数据分散。站点换了表单插件后,旧插件的数据表还留在数据库里无人管理,成了「影子数据仓库」。

总结

表单数据的合规可以拆成四件事:知道数据在哪(盘点)→ 规定存多久(留存策略)→ 到期自动删(清理任务)→ 客户要时能导出能删除(接入隐私工具)。其中最容易缺的是第二项和第四项:留存周期要么没定,要么定了不执行;隐私工具要么没用,要么没把自建表登记进去。把这几件事补齐,成本不高,但能避免最麻烦的那类问题。表单本身的字段与通知配置,可参考WPForms / Fluent Forms 拖拽表单配置教程与Contact Form 7 常见配置问题与扩展。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。