子比主题开发文档
使用指南Codestar Framework主题扩展在线部署AI 功能推荐插件赞助打赏

消息通知

按子比主题源码梳理站内消息、私信、微信模板消息、业务通知、Ajax 动作和消息中心扩展点。

模块入口

消息模块入口在 inc/functions/message/functions.php。它加载消息类、私信类、用户消息页面、Ajax、后台页面和微信模板消息能力。

目录作用
inc/functions/message/class/message-class.php站内消息类 ZibMsg
inc/functions/message/class/private-class.php私信类 Zib_Private
inc/functions/message/functions/new.php新消息创建与业务封装
inc/functions/message/functions/ajax.php消息 Ajax 动作
inc/functions/message/functions/user.php用户消息相关展示
inc/functions/message/functions/wechat-template-msg.php微信模板消息
inc/functions/message/page/msg-center.php消息中心页面
inc/functions/message/functions/admin.php后台管理入口

消息中心是前台路由:

add_action('generate_rewrite_rules', 'zibmsg_rewrite_rules');
add_filter('query_vars', 'zibmsg_query_vars');
add_action('template_redirect', 'zibmsg_load_template', 5);
add_action('pre_get_posts', 'zibmsg_pre_get_posts');
add_action('ajax_get_current_user', 'zibmsg_auto_clear');

模板 inc/functions/message/page/msg-center.php 会触发:

do_action('locate_template_' . $page_type);
do_action($page_type . '_page_header');
do_action($page_type . '_page_content');
do_action($page_type . '_page_footer');

消息中心的 $page_typemsg_center,所以可用入口包括 locate_template_msg_centermsg_center_page_headermsg_center_page_contentmsg_center_page_footer

消息数据结构

站内消息类是 ZibMsg。创建或更新消息都走 ZibMsg::update($values),默认字段如下:

$defaults = array(
    'send_user'     => '',
    'receive_user'  => '',
    'type'          => '',
    'title'         => '',
    'content'       => '',
    'create_time'   => current_time('mysql'),
    'modified_time' => current_time('mysql'),
    'parent'        => '',
    'status'        => '',
    'meta'          => '',
    'other'         => '',
);

metaother 会用 maybe_serialize() 保存,读取单条消息时再反序列化。结构化数据优先放到 metaother,不要把数组拼进 content

新增系统消息示例:

function zib_docs_add_system_message($user_id, $post_id)
{
    if (!$user_id || !$post_id || !class_exists('ZibMsg')) {
        return false;
    }

    return ZibMsg::update(array(
        'send_user'    => 0,
        'receive_user' => $user_id,
        'type'         => 'system',
        'title'        => __('文章状态更新', 'zib_language'),
        'content'      => sprintf(__('你的文章《%s》状态已更新。', 'zib_language'), get_the_title($post_id)),
        'meta'         => array(
            'post_id' => $post_id,
        ),
    ));
}

ZibMsg::update() 提供这些 Hook:

$values = apply_filters('zib_add_message_values', $values);
do_action('zib_update_message', $values);
do_action('zib_add_message', $values);

状态变更和已读也有 Hook:

do_action('zib_message_set_status', $id, $values);
do_action('zib_message_set_status_batch', $where, $values);
do_action('zib_message_readed', $id, $_user_id);
do_action('zib_message_all_readed', $where, $user_id);

业务通知来源

源码里已有许多业务 Hook 会自动创建消息,集中在 inc/functions/message/functions/new.php

Hook消息场景
comment_unapproved_to_approved评论审核通过
comment_post新评论、回复父评论
new_posts_pending投稿待审核通知管理员
pending_to_publish投稿发布通知作者
bbs_posts_delete论坛帖子删除通知
bbs_add_posts论坛新帖待审核通知管理员、版块作者和版主
answer_adopted论坛回答被采纳通知回答用户
comment_is_hot论坛评论成为热评通知评论用户
posts_is_hot论坛帖子成为热门通知帖子作者
plate_is_hot论坛版块成为热门通知版块作者
bbs_posts_essence_set论坛帖子设为精华通知帖子作者
publish_to_pending文章退回待审核
zib_ajax_frontend_links_submit_success友情链接提交
like-posts文章被点赞
like-comment评论被点赞
favorite-posts文章被收藏
follow-user用户被关注
zib_user_bind_phone手机绑定成功
zib_user_bind_email邮箱绑定成功

如果只是给已有业务补一条通知,优先挂这些业务 Hook。不要在前端点击事件里直接发消息,否则容易绕过权限、重复发送或漏掉后台操作。

消息分类与 Tab

消息分类由 zib_get_msg_cat() 返回,并经过 message_cats 过滤:

return apply_filters('message_cats', $cat_type);

消息中心主区域来自 inc/functions/message/functions/user.php

$tabs_array = apply_filters('mag_ctnter_main_tabs_array', $tabs_array);
add_filter('main_msg_tab_content_news', 'zibmsg_page_main_tab_content_news');
add_filter('main_msg_tab_content_posts', 'zibmsg_main_msg_tab_content_posts');
add_filter('main_msg_tab_content_like', 'zibmsg_main_msg_tab_content_like');
add_filter('main_msg_tab_content_system', 'zibmsg_main_msg_tab_content_system');
add_filter('main_msg_tab_content_private', 'zibmsg_main_msg_tab_content_private');

注意源码里的主 Tab filter 名是 mag_ctnter_main_tabs_array

新增消息分类时要同时补分类、Tab 和内容:

function zib_docs_message_cats($cat_type)
{
    $cat_type['docs'] = __('开发通知', 'zib_language');
    return $cat_type;
}
add_filter('message_cats', 'zib_docs_message_cats');

function zib_docs_msg_tabs($tabs_array)
{
    $tabs_array['docs'] = array(
        'title' => __('开发通知', 'zib_language'),
        'icon'  => 'fa fa-code',
    );

    return $tabs_array;
}
add_filter('mag_ctnter_main_tabs_array', 'zib_docs_msg_tabs');

function zib_docs_main_msg_tab_content_docs()
{
    return zib_get_user_cat_msg('docs');
}
add_filter('main_msg_tab_content_docs', 'zib_docs_main_msg_tab_content_docs');

消息 Ajax 动作

消息 Ajax 在 inc/functions/message/functions/ajax.php

Ajax action函数用途
user_news_msgzib_ajax_user_news_msg()顶部新消息列表
newmsg_drop匿名回调新消息下拉
user_msgzib_ajax_user_msg()消息列表
message_shieldzib_ajax_user_message_shield()消息屏蔽设置
user_msg_contentzib_ajax_user_msg_content()消息详情
msg_all_readedzib_ajax_user_msg_all_readed()全部标记已读
send_privatezib_ajax_send_private()发送私信
private_window_modalzib_ajax_private_window_modal()私信窗口弹窗
user_private_listszib_ajax_user_private_lists()私信会话列表
private_windowzib_ajax_private_window()私信窗口内容
private_blacklistzib_ajax_private_blacklist()私信黑名单
clear_user_privatezib_ajax_clear_user_private()清空私信

私信类是 Zib_Private。它负责会话列表、消息列表、输入框、私信按钮和窗口内容。扩展私信时要区分“站内消息”和“私信消息”:站内消息走 ZibMsg,私信对话走 Zib_Private

微信模板消息

微信模板消息依赖公众号配置、用户绑定状态和模板配置。发送入口:

zib_wechat_template_send($user_id, $type, $data, $url = '');
zib_send_wechat_template_msg_to_admin($type, $data, $url = '');
zib_get_user_wechat_open_id($user_id);
zib_get_wechat_template_id($type);

扩展前先确认:

  1. 公众号配置是否完整。
  2. 用户是否有 openid。
  3. 模板 ID 是否正确。
  4. 发送频率和失败日志是否可控。
  5. 是否需要与站内消息同时发送。

微信模板消息应该作为站内消息的补充,而不是替代。模板消息失败不应中断订单、评论、绑定邮箱等主流程。

后台入口在“用户互动 -> 微信通知”。字段结构是:

字段说明
wechat_template_msg_s总开关,关闭后 zib_wechat_template_send() 直接返回错误
wechat_template_ids模板消息配置集合
{type}_s某一种模板消息是否启用
{type}该类型对应的公众号模板 ID
{type}_keys主题业务字段到公众号模板字段名的映射

后台说明里有三个重要前提:微信公众号登录必须正常;公众号必须开通模板消息能力;只有绑定了本站微信公众号登录且已关注的用户才能收到通知。主题读取用户 openid 的方式是:

function zib_get_user_wechat_open_id($user_id)
{
    return get_user_meta($user_id, 'oauth_weixingzh_openid', true);
}

所以微信模板消息和“微信公众号登录”不是两套独立配置。用户没有 oauth_weixingzh_openid 时,即使站内消息和邮件能发送,微信模板消息也会返回“用户未绑定微信”。

模板类型和默认参数来自 CFS_Module::wechat_template_msg_args()

类型场景
shop_notify_shipping_to_author通知商家发货
shop_express_shipping快递发货通知用户
shop_after_sale_to_author用户申请售后通知商家
shop_after_sale_wait_user_return售后等待用户发货
shop_after_sale_end售后订单处理完成
payment_order新订单通知用户
payment_order_admin新订单通知管理员
payment_order_to_income创作分成通知作者
payment_order_to_referrer推荐佣金通知推荐人
apply_withdraw_admin用户申请提现通知管理员
withdraw_process提现处理后通知用户
auth_apply_admin用户提交身份认证通知管理员
auth_apply_process身份认证处理后通知用户
report_user_admin收到举报后通知管理员
report_process处理用户举报后通知举报人
bind_phone绑定或修改手机号通知用户
bind_email绑定或修改邮箱通知用户
comment_to_postauthor新评论通知文章作者
comment_to_parent评论有新回复通知用户

发送流程由 zib_wechat_template_send() 统一处理:

  1. 检查 wechat_template_msg_s
  2. 读取 get_oauth_config('weixingzh'),要求 appidappkey 存在。
  3. 通过 zib_get_wechat_template_id($type) 检查该类型开关和模板 ID。
  4. 通过 zib_get_user_wechat_open_id($user_id) 获取接收用户 openid。
  5. zib_wechat_template_data_handle($type, $data) 做参数映射和长度处理。
  6. 加载 oauth/sdk/weixingzh.php,调用公众号 SDK 的 sendTemplateMsg()

参数映射有一个容易忽略的细节:如果后台给某个业务字段配置了模板字段名,就按配置写入;如果没有配置,则按 keyword1keyword2 顺序补齐。模板字段名包含 thing 时,主题会把超过 19 个字符的内容截断为前 16 个字符加省略号:

function zib_docs_wechat_template_data($order)
{
    return array(
        'name'  => get_the_title($order->post_id),
        'price' => zibpay_format_local_price_text($order->price),
        'time'  => current_time('Y-m-d H:i:s'),
        'num'   => $order->order_num,
    );
}

后台配置里如果把 name 映射到 thing1,长商品名会被主题截断,避免公众号模板接口拒绝过长 thing 字段。

给所有管理员发送模板消息使用:

function zib_docs_notice_admins($post_id, $user_id)
{
    $data = array(
        'name' => get_the_title($post_id),
        'time' => current_time('Y-m-d H:i:s'),
        'user' => get_the_author_meta('display_name', $user_id),
    );

    zib_send_wechat_template_msg_to_admin('auth_apply_admin', $data, admin_url('users.php'));
}

zib_send_wechat_template_msg_to_admin() 会遍历 zib_get_admin_user_ids(),对每个管理员调用 zib_wechat_template_send()。这意味着管理员也必须绑定公众号 openid,否则不会收到微信通知。

后台测试入口是 Ajax action:

add_action('wp_ajax_test_wechat_template_test', 'zib_ajax_test_wechat_template_test');

测试只允许超级管理员执行,会检查模板消息总开关、单个类型开关、模板 ID、微信公众号登录配置,然后按测试类型构造一组示例数据发给当前登录管理员。排查模板消息时优先用后台测试确认“公众号配置、模板 ID、参数名、当前管理员 openid”四件事,再回到具体业务 Hook。

主题内置调用点分布较广:

模块典型类型
评论通知comment_to_postauthorcomment_to_parent
账号安全bind_phonebind_email
用户认证auth_apply_adminauth_apply_process
举报与禁封report_user_adminreport_process
商城订单payment_orderpayment_order_adminpayment_order_to_incomepayment_order_to_referrer
商城发货售后shop_notify_shipping_to_authorshop_express_shippingshop_after_sale_to_authorshop_after_sale_wait_user_returnshop_after_sale_end

商城用户中心订单展示、联系商家、收货地址修改申请,以及商城邮件、站内信和微信模板通知矩阵见 商城用户中心与消息通知

新增业务通知时,不建议直接在任意模板里远程请求公众号接口。更稳的方式是先完成站内消息或业务状态写入,再在同一个业务完成 Hook 中调用 zib_wechat_template_send(),并忽略失败返回或记录日志:

function zib_docs_send_task_wechat_notice($user_id, $task_title)
{
    if (!$user_id || !$task_title) {
        return;
    }

    $data = array(
        'name' => $task_title,
        'time' => current_time('Y-m-d H:i:s'),
        'desc' => __('任务状态已更新', 'zib_language'),
    );

    $send = zib_wechat_template_send($user_id, 'report_process', $data, zib_get_user_center_url('msg'));

    if (!empty($send['error'])) {
        error_log('docs task wechat notice failed: ' . $send['msg']);
    }
}

新增模板类型需要改后台类型表,属于主题能力扩展,不只是调用发送函数。要补齐类型 key、后台开关、模板 ID、参数 key 配置和业务调用,否则后台不会出现该模板,也无法通过 zib_get_wechat_template_id($type)

注意事项

  • 不要把敏感订单信息、隐私资料直接放进公开可见消息。
  • 不要在高频 Hook 中同步远程消息,必要时写队列。
  • 消息发送失败要有日志,不要影响主流程。
  • 批量通知要限制频率,避免拖慢请求。
  • 私信和系统通知要区分权限和可见范围。
  • 新增消息分类时,要同时补 message_cats、消息中心 Tab 和读取条件。
  • content 会经过表情、图片、代码格式化,原始用户输入仍然要在写入前控制长度和格式。

On this page