搜索全站
报错排查 13 分钟阅读

WordPress 后台文章列表异常:不显示、数量不对、报错的修复

后台明明有 500 篇文章,列表只显示 12 篇;或者点开就是报错。本文讲清文章列表的查询逻辑、六类常见异常(数量不对、筛选失效、列缺失、报错、搜索无结果、分页错乱)的成因与逐一修复方法。

U
UFO_PF 2019-02-10 · 阅读 13 分钟
Wo 报错排查
阅读提示
本文约 5,159 字,预计阅读 13 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:文章”消失”了,其实还在

后台”所有文章”页面显示 12 篇,但站点前台明明有 500 篇。或者搜索某篇文章,搜不到。或者点”已发布”筛选,数字对不上。

这类问题几乎不会真的丢数据——wp_posts 里的记录都在,出问题的是后台列表的查询构造过程。理解这个过程,六类异常都有明确解法。

原理分析:后台列表是怎么查出来的

后台文章列表由 WP_List_Table 的子类 WP_Posts_List_Table 渲染,数据来自一次 WP_Query:

$query = new WP_Query( array(
    'post_type'      => 'post',
    'post_status'    => 'any',      // 或 all
    'posts_per_page' => 20,         // 来自用户"显示选项"
    'paged'          => $paged,
    's'              => $search,    // 搜索关键词
    'cat'            => $cat,       // 分类筛选
    'orderby'        => 'date',
    'order'          => 'DESC',
) );

这条查询会被四个东西修改:

  1. 用户偏好:wp_usermeta 里的 edit_post_per_page 和 manageedit-postcolumnshidden(每页条数和隐藏列);
  2. pre_get_posts 钩子:主题或插件可能在这里偷偷加了条件;
  3. posts_where / posts_join 等过滤器:插件做权限控制、语言过滤时常用;
  4. 数据库状态:post_status、post_type、post_parent 的值是否干净。

所以异常基本都能归到这四类的某一类。

保姆级实操

异常一:数量明显不对(有 500 篇只显示 12 篇)

原因 A:每页条数被改小了

右上角”显示选项” → 每页条数。也可能被代码改过:

wp user meta get 1 edit_post_per_page
wp user meta update 1 edit_post_per_page 20

原因 B:某个插件用 pre_get_posts 加了限制

这是最常见的根因。排查方法——临时把插件全停了看是否恢复:

wp plugin list --status=active --field=name
# 逐个停用测试,或者一次性停掉全部
wp plugin deactivate --all
wp plugin activate 某插件

找到元凶后查它的代码:

grep -rn "pre_get_posts" wp-content/plugins/某插件/

典型的有问题的写法(忘了判断 is_main_query 和 is_admin):

// 错误写法:把前台的筛选条件也应用到了后台
add_action( 'pre_get_posts', function( $q ) {
    $q->set( 'posts_per_page', 12 );   // 后台也被限制了!
} );

// 正确写法
add_action( 'pre_get_posts', function( $q ) {
    if ( is_admin() || ! $q->is_main_query() ) {
        return;
    }
    $q->set( 'posts_per_page', 12 );
} );

原因 C:多语言插件按语言过滤

WPML/Polylang 在后台只显示当前语言的文章。切换语言选择器(后台顶栏)就能看到全部。

异常二:筛选”已发布”的数量对不上

顶部的”全部 / 已发布 / 草稿 / 回收站”数字来自独立统计:

SELECT post_status, COUNT(*) FROM wp_posts
WHERE post_type = 'post' GROUP BY post_status;

对比后台显示的数字。如果对不上,通常是数据库里有脏状态值(比如 post_status 是 inherit 的附件混进来了,或者被插件写成了奇怪的值)。

修复:

-- 查看所有状态
SELECT DISTINCT post_status FROM wp_posts;

-- 把异常状态改回来(示例)
UPDATE wp_posts SET post_status = 'publish'
WHERE post_status = 'some-weird-status';

异常三:某些列不显示(比如没有”分类””标签”列)

这是用户偏好,不是故障。右上角”显示选项”勾选即可。如果是所有用户都不显示,检查代码:

// 强制显示某些列
add_filter( 'manage_edit-post_columns', function( $columns ) {
    $columns['categories'] = '分类';
    $columns['tags']       = '标签';
    return $columns;
} );

异常四:点开列表直接报错

常见报错及原因:

报错 1:Fatal error: Allowed memory size exhausted

文章太多 + 插件吃内存。临时提高限制:

// wp-config.php
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );

但根治要减少每页条数(改成 10 或 20)和找出吃内存的插件。

报错 2:WordPress database error ... Table 'wp_xxx.wp_posts' doesn't exist

表前缀不匹配。检查 wp-config.php 的 $table_prefix:

wp config get table_prefix
# 看实际表
wp db query "SHOW TABLES;"

报错 3:500 错误

看日志:

tail -50 wp-content/debug.log
tail -50 /var/log/php8.2-fpm.log

异常五:搜索不到明明存在的文章

后台搜索只搜 post_title、post_content、post_excerpt,不搜自定义字段和分类名。

另外两个常见原因:

  • 文章状态是草稿/待审,而搜索时默认筛选的是”全部”——这个通常没问题;
  • 搜索插件改写了搜索逻辑(比如装了 Relevanssi 或 SearchWP),把后台搜索也接管了。检查:

bash
grep -rn "is_search" wp-content/plugins/ | grep -i "admin"

要让后台搜索支持自定义字段:

add_filter( 'posts_search', function( $search, $q ) {
    global $wpdb;
    if ( ! is_admin() || ! $q->is_main_query() || empty( $q->get('s') ) ) {
        return $search;
    }
    $term = '%' . $wpdb->esc_like( $q->get('s') ) . '%';
    $search .= $wpdb->prepare(
        " OR EXISTS (SELECT 1 FROM {$wpdb->postmeta} pm
           WHERE pm.post_id = {$wpdb->posts}.ID
             AND pm.meta_value LIKE %s) ",
        $term
    );
    return $search;
}, 10, 2 );

异常六:分页错乱 / 点第二页是空

通常是 posts_per_page 和分页参数冲突,或者插件修改了 offset。

// 检查当前查询参数
add_action( 'admin_notices', function() {
    if ( ! isset($_GET['post_type']) || 'post' !== $_GET['post_type'] ) return;
    global $wp_query;
    echo '<pre>per_page=' . $wp_query->get('posts_per_page') . ' paged=' . $wp_query->get('paged') . ' found=' . $wp_query->found_posts . '</pre>';
} );

注意:offset 参数会让 paged 失效,这是 WordPress 的已知行为。插件里如果用了 offset,分页就会错乱。

通用修复:重置后台列表偏好

用户的列表设置存在 wp_usermeta 里,删掉就能恢复默认:

wp user meta delete 1 manageedit-postcolumnshidden
wp user meta delete 1 edit_post_per_page
wp user meta list 1 --keys=manageedit-postcolumnshidden

常见踩坑与失败案例

  1. 案例一:某站后台文章列表只显示 12 篇,翻遍了设置找不到原因,最后发现是主题的作者为了首页”最新文章”模块写了 pre_get_posts,没有判断 is_admin(),把后台列表也限制成 12 篇了。这是教科书级的错误。
  2. 案例二:迁移后后台列表报错 Table doesn't exist。原因是新站的 $table_prefix 是 wp_mm_,而 wp-config.php 里还写着 wp_。用 wp config get table_prefix 一查就出来了。
  3. 内存耗尽:文章 2000 篇 + 每页 999 条 + 多个 SEO 插件同时跑,后台列表必崩。把每页条数改成 20。
  4. 多语言站”少了一半文章”:这是正常的,Polylang 默认按语言过滤。切换语言或开启”显示所有语言”。
  5. post_status 脏数据:某插件把状态写成了 Publish(大写 P),导致统计和筛选都找不到它。SQL 里统一大小写:

sql
UPDATE wp_posts SET post_status = LOWER(post_status)
WHERE post_status <> LOWER(post_status);

  1. 回收站文章占用计数:后台”全部”数量包含回收站。30 天后自动清空,或手工 wp post delete $(wp post list --post_status=trash --format=ids) --force。
  2. 列表页加载极慢:参见 WordPress 后台卡顿排查,根因通常是同一个插件。

总结

后台文章列表异常几乎不会真的丢数据,问题都在查询构造环节。排查顺序:先看 SELECT post_status, COUNT(*) 确认数据库真实数量 → 再查 edit_post_per_page 用户偏好 → 然后停插件排查 pre_get_posts 误伤(这是最高频根因,写法上必须判断 is_admin() 和 is_main_query())→ 最后看表前缀和内存限制。开发者请务必记住那条铁律:任何 pre_get_posts 修改都要先判断 is_admin() 和 is_main_query(),否则一定会在某个时刻把后台搞乱。

U
UFO_PF作者

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

留下你的想法

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