WordPress开发笔记

实时统计WordPress自定义文章类型已发布文章数量,与获取自定义文章类型名称集

我们已将实时统计WordPress自定义文章类型已发布文章数量,与获取自定义文章类型名称集两部分合并到一起。

即便是你用到插件后,记录的自定义文章类型已发布文章数量会跟着你新发布或删除文章自动增减,自定义文章类型名称集也会讲新创建的自定义文章类型统计在内,代码实现了系统实时获取。

代码


//=================================第一部分===========================================
// 1.先挂好钩子
//获取posttype频道的已发布文章的总数量方法
// 在 init 钩子中处理统计:处理自定义文章类型的文章总数量
add_action('init', 'zzw_static_count_custom_post_types', 99); // 优先级99确保最后执行
function zzw_static_count_custom_post_types() {
    if (!get_option('zzw_static_needs_cpt_count')) return;

    $args = array(
        'public'   => true,
        '_builtin' => false
    );
    $post_types = get_post_types($args, 'names', 'and');
    
    foreach ($post_types as $post_type) {
        $count = (string) wp_count_posts($post_type)->publish;
        update_option( 'DIY name1', $count);

    }
    $post_types_string = implode(",", $post_types);
    $post_types_string = $post_types_string.',post';
    $post_types_string = $post_types_string.',page';
    update_option( 'DIY name2', $post_types_string);;//全部posttype名称以“,”分隔的字符串

    
    delete_option('zzw_static_needs_cpt_count'); // 清除标记
}

// 2.在你的目标函数或其他位置,定义激活标记
// update_option('zzw_static_needs_cpt_count', true);


//=================================第二部分===========================================

// 新建自定义文章类型实时响应文章总数量
add_action('registered_post_type', function($post_type, $args) {

    //过滤掉非公开或为内置的posttype类型
    if (!$args->public || $args->_builtin) return;
    
    //为新建posttype增设_{$post_type}_zongshu字段,并赋值文章总数
    $count = (string) wp_count_posts($post_type)->publish;
    update_option( 'DIY name1', $count);

    //调整_pts_string字段值,将符合条件并未被列入的posttype加入到该字段值中
    $s_pts_string = get_option('DIY name');
    if ( strpos($s_pts_string, $post_type) === false ) {
        $s_pts_string = $post_type.','.$s_pts_string;
    }
    update_option( 'DIY name2', $s_pts_string);

}, 10, 2);




//=================================第三部分===========================================

// 文章变更(发布已发布/变更状态为非已发布)增量更新
// 在文章保存前捕获旧状态
add_action('pre_post_update', function($post_id) {
    if ($post = get_post($post_id)) {
        $GLOBALS['zzw_old_post_status'] = $post->post_status;
    }
});

// 主处理逻辑
add_action('save_post', function($post_id, $post) {
    // 排除修订版和自动保存
    if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
        return;
    }
    
    // 获取变更前的状态
    $old_status = $GLOBALS['zzw_old_post_status'] ?? '';
    $new_status = $post->post_status;
    
    // 调试日志(生产环境可移除)
    // error_log("Post {$post_id} status change: {$old_status} => {$new_status}");
    
    // 只处理实际状态变更
    if ($old_status === $new_status) {
        return;
    }
    
    $current_count = (int) get_option('DIY name1');
    
    // 发布文章(从非发布状态变为发布状态)
    if ('publish' === $new_status && 'publish' !== $old_status) {
        update_option( 'DIY name1', ($current_count+1) );
        // error_log("ID为 {$post_id} 的文章发布或更改为了发布状态,该频道文章总数记录字段 {$log_name} 加1成功");
    }
    // 取消发布(从发布状态变为非发布状态)
    elseif ('publish' !== $new_status && 'publish' === $old_status) {
        update_option( 'DIY name1', ($current_count-1) );
        // error_log("ID为 {$post_id} 的文章状态变更为了非发布状态,该频道文章总数记录字段 {$log_name} 减1成功");
    }
}, 10, 2);

使用:

代码使用重点注意:将代码中的 “DIY name” 替换为你的自定义字段名。因为这段代码的实现目的是存储目标数据,方便使用时调取。

在你的目标函数或其他位置,定义激活标记

// 2.在你的目标函数或其他位置,定义激活标记
update_option('zzw_static_needs_cpt_count', true);

详解

以下是对您提供的代码的详细解析,分为三个主要部分:

第一部分:初始化统计(批量更新)

// 1. 在 init 钩子中处理统计
add_action('init', 'zzw_static_count_custom_post_types', 99);
function zzw_static_count_custom_post_types() {
    // 检查是否需要执行统计
    if (!get_option('zzw_static_needs_cpt_count')) return;

    // 获取所有公开的非内置文章类型
    $args = array(
        'public'   => true,
        '_builtin' => false
    );
    $post_types = get_post_types($args, 'names', 'and');

    // 遍历处理每个文章类型
    foreach ($post_types as $post_type) {
        // 获取已发布文章数量
        $count = (string) wp_count_posts($post_type)->publish;
        // 更新文章总数选项(⚠️ 注意:这里会覆盖前值)
        update_option( 'DIY name1', $count);
    }

    // 构建文章类型名称字符串
    $post_types_string = implode(",", $post_types);
    $post_types_string = $post_types_string.',post'; // 添加文章类型
    $post_types_string = $post_types_string.',page'; // 添加页面类型
    // 存储文章类型列表
    update_option( 'DIY name2', $post_types_string);

    // 清除执行标记
    delete_option('zzw_static_needs_cpt_count');
}

// 2. 触发统计的激活方式(示例)
// update_option('zzw_static_needs_cpt_count', true);

功能说明:

  1. 通过 zzw_static_needs_cpt_count 选项控制执行
  2. 获取所有 自定义文章类型(非内置+公开)
  3. 遍历更新文章总数到 DIY name1(⚠️ 循环内会覆盖前值)
  4. 构建包含所有文章类型的字符串(自定义+post+page)存到 DIY name2
  5. 需要手动激活:update_option('zzw_static_needs_cpt_count', true)

存在问题:

  • DIY name1 在循环中被多次覆盖,最终只存储最后一种文章类型的数量
  • 未统计内置的 post/page 文章数量
  • 每次激活会完全重置数据

第二部分:新建文章类型实时响应

add_action('registered_post_type', function($post_type, $args) {
    // 只处理公开的非内置类型
    if (!$args->public || $args->_builtin) return;

    // 获取新类型的文章数量
    $count = (string) wp_count_posts($post_type)->publish;
    // 更新总数(⚠️ 覆盖现有值)
    update_option( 'DIY name1', $count);

    // 获取现有类型字符串
    $s_pts_string = get_option('DIY name2');
    // 添加新类型(如果不存在)
    if ( strpos($s_pts_string, $post_type) === false ) {
        $s_pts_string = $post_type.','.$s_pts_string;
    }
    // 更新类型列表
    update_option( 'DIY name2', $s_pts_string);
}, 10, 2);

功能说明:

  1. 在文章类型注册时触发(registered_post_type
  2. 更新 DIY name1 为新类型的文章数量(⚠️ 覆盖旧值)
  3. 将新类型添加到 DIY name2 字符串开头

存在问题:

  • DIY name1 被覆盖,丢失之前存储的统计
  • 未考虑新类型可能已有文章的情况
  • 添加逻辑会使类型列表顺序混乱(新类型加在开头)

第三部分:文章状态变更处理

// 捕获更新前的状态
add_action('pre_post_update', function($post_id) {
    if ($post = get_post($post_id)) {
        $GLOBALS['zzw_old_post_status'] = $post->post_status;
    }
});

// 主处理逻辑
add_action('save_post', function($post_id, $post) {
    // 排除无效保存
    if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) return;

    // 获取状态变化
    $old_status = $GLOBALS['zzw_old_post_status'] ?? '';
    $new_status = $post->post_status;

    // 忽略未变化的状态
    if ($old_status === $new_status) return;

    // 获取当前总数
    $current_count = (int) get_option('DIY name1');

    // 发布文章:非发布 → 发布
    if ('publish' === $new_status && 'publish' !== $old_status) {
        update_option( 'DIY name1', ($current_count+1) );
    }
    // 取消发布:发布 → 非发布
    elseif ('publish' !== $new_status && 'publish' === $old_status) {
        update_option( 'DIY name1', ($current_count-1) );
    }
}, 10, 2);

功能说明:

  1. 使用 pre_post_update 捕获旧状态
  2. 通过 save_post 处理实际状态变更
  3. 精确识别两种变化:
  • 新发布:非发布 → 发布(总数+1)
  • 取消发布:发布 → 非发布(总数-1)
  1. 排除修订版和自动保存

优势:

  • 增量更新效率高
  • 状态变化判断精准
  • 避免重复计数

修改或改进方向

  1. 数据覆盖问题
  • 第一部分和第二部分都会覆盖 DIY name1 的值
  • 导致最终只存储最后处理的文章类型数量
  1. 统计不完整
  • 未统计内置的 post/page 文章数量(第一部分)
  • 循环内覆盖值导致自定义类型统计不全
  1. 设计逻辑冲突
  • 第一部分:批量统计所有类型
  • 第二部分:按类型单独存储
  • 第三部分:假设存储全局总数
  1. 类型列表管理
  • 添加新类型时直接修改字符串
  • 缺乏唯一性检查和格式控制

改进建议

  1. 数据结构优化
    使用数组存储数据:
   // 总数存储
   update_option('zzw_total_count', [
       'post' => 120,
       'product' => 85,
       'total' => 205
   ]);

   // 类型列表存储
   update_option('zzw_post_types', ['post', 'page', 'product']);
  1. 第一部分修正
   $total_count = 0;
   $all_types = [];

   // 统计自定义类型
   foreach ($custom_types as $type) {
       $count = wp_count_posts($type)->publish;
       $total_count += $count;
       $all_types[] = $type;
   }

   // 添加内置类型
   $post_count = wp_count_posts('post')->publish;
   $page_count = wp_count_posts('page')->publish;
   $total_count += $post_count + $page_count;

   $all_types = array_merge($all_types, ['post', 'page']);
  1. 第二部分修正
   // 获取现有数据
   $total_data = get_option('zzw_total_count');
   $type_list = get_option('zzw_post_types');

   // 添加新类型
   if (!in_array($post_type, $type_list)) {
       $count = wp_count_posts($post_type)->publish;
       $total_data[$post_type] = $count;
       $total_data['total'] += $count;
       $type_list[] = $post_type;
   }
  1. 第三部分增强
   // 在状态变更处理中
   $post_type = $post->post_type;
   $total_data = get_option('zzw_total_count');

   if ($status_change === 'published') {
       $total_data[$post_type]++;
       $total_data['total']++;
   }

关键改进方向:使用结构化数据存储、区分类型统计、维护全局总数、增加缓存机制提高性能。