搜索全站
建站 12 分钟阅读

WordPress 投稿站权限与审核流程设计:角色、自定义状态与工作流

审一篇稿要走"待审—修改—待群发—已发布"四步,用 WordPress 默认的两个状态根本不够。本文讲如何用自定义文章状态搭工作流、如何用角色能力收紧权限、以及如何把通知做成闭环。

U
UFO_PF 2019-05-29 · 阅读 12 分钟
Wo 建站
阅读提示
本文约 4,610 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:编辑在钉钉里喊”这篇能发了吗”

现实里的审核从来不是”草稿 → 发布”两级。一篇投稿通常要经历:初审(格式与选题)→ 退修改 → 复审(事实核查)→ 排版 → 终审 → 发布。如果系统只有 draft 和 publish,这些信息只能靠群里对话传递,几个月后想查”上周谁退了三篇稿”,完全查不到。更糟的是权限:给投稿者太多能力,他会看到后台所有文章甚至能改别人的稿;给太少,连配图都传不了。结果是管理员包揽一切,规模化无从谈起。

原理分析:WordPress 的状态机其实可以扩展

WordPress 的文章状态存在数据库 post_status 字段里,默认给了几个值:auto-draft、draft、pending、private、publish、trash、future(定时)。而 register_post_status() 允许你无害地注册自己的状态,例如 pending_review、in_revision、ready_publish。注册后它会出现在 get_post_status()、WP_Query、以及 post_states 里,只要你再把它喂给 admin_init 时的下拉框,就能在列表页过滤。

真正驱动流程的是两个动作:transition_post_status(参数 $old_status, $new_status, $post,其中 $post 是 WP_Post 对象,函数名实际为 transition_post_status)和旧式但依然好用的 {$old_status}_to_{$new_status}、{$status}_{$post_type}。用它们发通知、写日志、改变责任人,流程就有了”记忆”。

角色 关键能力 说明
投稿作者 read, edit_posts, upload_files 无 publish_posts
初审编辑 + edit_others_posts, publish_posts 可处理他人稿件
主编 + edit_published_posts, delete_posts 可动已发布内容
管理员 全部 用于最终兜底

保姆级实操

步骤 1:注册三个自定义状态。 注意 public 相关参数——工作流状态必须是非公开的,否则前台可能被访问:

add_action( 'init', function () {
    $states = [
        'in_revision'   => '初审退回修改',
        'fact_check'    => '事实核查中',
        'ready_publish' => '待终审发布',
    ];
    foreach ( $states as $slug => $label ) {
        register_post_status( $slug, [
            'label'                     => $label,
            'public'                    => false,   // 工作流状态绝不能前台可访问
            'exclude_from_search'       => true,
            'show_in_admin_all_list'    => true,
            'show_in_admin_status_list' => true,
            'label_count'               => _n_noop( $label . ' <span class="count">(%s)</span>', $label . ' <span class="count">(%s)</span>' ),
        ] );
    }
} );

步骤 2:把它们加入后台文章列表的状态下拉:

add_action( 'admin_footer-post.php', function () {
    global $post;
    if ( 'post' !== $post->post_type ) {
        return;
    }
    echo '<script>
    jQuery(function($){
        $("#post_status option").filter(function(){
            return ["in_revision","fact_check","ready_publish"].indexOf(this.value) >= 0;
        }).detach().appendTo("#post_status");
    });
    </script>';
} );

步骤 3:给角色精确赋权。 用 Members 插件可视化处理,或者写一次性赋值脚本。注意能力的英文拼写,read_private_posts 这类能力决定是否能进入后台列表:

$role = get_role( 'editor' );
if ( $role ) {
    $role->add_cap( 'edit_others_posts', true );
    $role->add_cap( 'delete_others_posts', false ); // 明确关掉,防止误删
}

步骤 4:流程变化即通知。 用 transition_post_status 把状态变化推给相关人员,并写入审计日志:

add_action( 'transition_post_status', function ( $new_status, $old_status, $post ) {
    if ( 'post' !== $post->post_type || 'publish' === $new_status ) {
        return;
    }
    $map = [
        'in_revision'   => '稿件被退回修改,请查看编辑留言',
        'fact_check'    => '稿件已进入事实核查,请勿同时改动',
        'ready_publish' => '稿件已排版完成,等待终审',
    ];
    if ( ! isset( $map[ $new_status ] ) ) {
        return;
    }
    $author = get_userdata( $post->post_author );
    if ( $author ) {
        wp_mail(
            $author->user_email,
            '稿件状态更新:' . $post->post_title,
            $map[ $new_status ] . "\n\n稿件链接:" . get_edit_post_link( $post->ID, '' )
        );
    }
    add_post_meta( $post->ID, '_mf_status_log', sprintf(
        '%s | %s -> %s | by %d',
        current_time( 'mysql' ), $old_status, $new_status, get_current_user_id()
    ) );
}, 10, 3 );

步骤 5:让作者只看自己的稿。 在后台列表引入过滤,避免作者看到他人内容:

add_action( 'pre_get_posts', function ( $query ) {
    if ( ! is_admin() || ! $query->is_main_query() ) {
        return;
    }
    if ( current_user_can( 'mf_contributor' ) && ! current_user_can( 'edit_others_posts' ) ) {
        $query->set( 'author', get_current_user_id() );
        $query->set( 'post_status', [ 'draft', 'pending', 'in_revision', 'fact_check', 'ready_publish' ] );
    }
} );

步骤 6:限制媒体库归属。 与上面同理,用 ajax_query_attachments_args 把作者限定为自己的附件,避免误操作。WordPress 多作者投稿平台

常见踩坑

  1. register_post_status 忘了把 show_in_admin_status_list 设为 true,后台列表完全看不到该状态。
  2. 案例: 某站审稿人同时被赋予 edit_published_posts,误在编辑终审稿时直接按了”更新”,一篇错字稿上了首页,被读者截图传播。
  3. transition_post_status 回调只声明了两个参数,$post 传成 null,导致 null->post_title 致命错误。
  4. 自定义状态忘了加入 WP_Query 的 post_status 列表,”全部”里看不到,作者以为稿件丢了。
  5. pre_get_posts 里没有判断 is_main_query(),把后台的菜单、Widget 查询也一起限制了。
  6. 用 role->add_cap 写在 init 钩子里,每次请求都向数据库写一次;这类操作必须一次性执行(激活钩子或 WP-CLI)。
  7. 自定义状态的计数 “_noop” 函数缺失 label_count,后台出现 “Undefined index: label_count”。WordPress 编辑器协作与通知

总结

审核流的判断标准是:稿件状态是否自解释、每一步是否有人负责且自动通知、权限是否刚好够用。行动清单:注册 3 个自定义状态 → 后台可见 → 角色能力最小化 → 状态变化通知 → 审计日志。流程一旦可追溯,编辑团队协作效率会有肉眼可见的提升。

U
UFO_PF作者

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

留下你的想法

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