wp-performance-review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

WordPress Performance Review Skill

WordPress性能审查技能

Overview

概述

Systematic performance code review for WordPress themes, plugins, and custom code. Core principle: Scan critical issues first (OOM, unbounded queries, cache bypass), then warnings, then optimizations. Report with line numbers and severity levels.
针对WordPress主题、插件及自定义代码的系统性性能代码审查。核心原则: 优先扫描关键问题(内存不足OOM、无界查询、缓存绕过),其次是警告,最后是优化建议。报告需包含行号和严重等级。

When to Use

适用场景

Use when:
  • Reviewing PR/code for WordPress theme or plugin
  • User reports slow page loads, timeouts, or 500 errors
  • Auditing before high-traffic event (launch, sale, viral moment)
  • Optimizing WP_Query or database operations
  • Investigating memory exhaustion or DB locks
Don't use for:
  • Security-only audits (use wp-security-review when available)
  • Gutenberg block development patterns (use wp-gutenberg-blocks when available)
  • General PHP code review not specific to WordPress
适用情况:
  • 审查WordPress主题或插件的PR/代码
  • 用户反馈页面加载缓慢、超时或500错误
  • 高流量事件(上线、促销、病毒式传播)前的审计
  • 优化WP_Query或数据库操作
  • 排查内存耗尽或数据库锁问题
不适用情况:
  • 仅安全审计(若有wp-security-review则使用该工具)
  • Gutenberg区块开发模式审查(若有wp-gutenberg-blocks则使用该工具)
  • 非WordPress专属的通用PHP代码审查

Code Review Workflow

代码审查流程

  1. Identify file type and apply relevant checks below
  2. Scan for critical patterns first (OOM, unbounded queries, cache bypass)
  3. Check warnings (inefficient but not catastrophic)
  4. Note optimizations (nice-to-have improvements)
  5. Report with line numbers using output format below
  1. 识别文件类型并应用下方对应的检查项
  2. 优先扫描关键模式(OOM、无界查询、缓存绕过)
  3. 检查警告项(效率低下但不致命)
  4. 记录优化建议(锦上添花的改进)
  5. 按以下输出格式附带行号生成报告

File-Type Specific Checks

按文件类型的专项检查

Plugin/Theme PHP Files (
functions.php
,
plugin.php
,
*.php
)

插件/主题PHP文件(
functions.php
plugin.php
*.php

Scan for:
  • query_posts()
    → CRITICAL: Never use - breaks main query
  • posts_per_page.*-1
    or
    numberposts.*-1
    → CRITICAL: Unbounded query
  • session_start()
    → CRITICAL: Bypasses page cache
  • add_action.*init.*
    or
    add_action.*wp_loaded
    → Check if expensive code runs every request
  • update_option
    or
    add_option
    in non-admin context → WARNING: DB writes on page load
  • wp_remote_get
    or
    wp_remote_post
    without caching → WARNING: Blocking HTTP
扫描以下内容:
  • query_posts()
    → 严重问题:绝对禁止使用 - 会破坏主查询
  • posts_per_page.*-1
    numberposts.*-1
    → 严重问题:无界查询
  • session_start()
    → 严重问题:绕过页面缓存
  • add_action.*init.*
    add_action.*wp_loaded
    → 检查是否有高开销代码在每次请求时运行
  • 非管理后台上下文的
    update_option
    add_option
    → 警告:页面加载时写入数据库
  • 未缓存的
    wp_remote_get
    wp_remote_post
    → 警告:阻塞式HTTP请求

WP_Query / Database Code

WP_Query / 数据库代码

Scan for:
  • Missing
    posts_per_page
    argument → WARNING: Defaults to blog setting
  • 'meta_query'
    with
    'value'
    comparisons → WARNING: Unindexed column scan
  • post__not_in
    with large arrays → WARNING: Slow exclusion
  • LIKE '%term%'
    (leading wildcard) → WARNING: Full table scan
  • Missing
    no_found_rows => true
    when not paginating → INFO: Unnecessary count
扫描以下内容:
  • 缺失
    posts_per_page
    参数 → 警告:默认使用博客设置
  • 'value'
    比较的
    'meta_query'
    → 警告:未索引列扫描
  • 包含大数组的
    post__not_in
    → 警告:缓慢的排除操作
  • LIKE '%term%'
    (前导通配符)→ 警告:全表扫描
  • 非分页查询时缺失
    no_found_rows => true
    → 提示:不必要的计数操作

AJAX Handlers (
wp_ajax_*
, REST endpoints)

AJAX处理器(
wp_ajax_*
、REST端点)

Scan for:
  • admin-ajax.php
    usage → INFO: Consider REST API instead
  • POST method for read operations → WARNING: Bypasses cache
  • setInterval
    or polling patterns → CRITICAL: Self-DDoS risk
  • Missing nonce verification → Security issue (not performance, but flag it)
扫描以下内容:
  • admin-ajax.php
    的使用 → 提示:考虑改用REST API
  • 读取操作使用POST方法 → 警告:绕过缓存
  • setInterval
    或轮询模式 → 严重问题:自DDoS风险
  • 缺失随机数验证 → 安全问题(非性能问题,但需标记)

Template Files (
*.php
in theme)

模板文件(主题中的
*.php

Scan for:
  • get_template_part
    in loops → WARNING: Consider caching output
  • Database queries inside loops (N+1) → CRITICAL: Query multiplication
  • wp_remote_get
    in templates → WARNING: Blocks rendering
扫描以下内容:
  • 循环中的
    get_template_part
    → 警告:考虑缓存输出
  • 循环内的数据库查询(N+1问题)→ 严重问题:查询次数倍增
  • 模板中的
    wp_remote_get
    → 警告:阻塞渲染

JavaScript Files

JavaScript文件

Scan for:
  • $.post(
    for read operations → WARNING: Use GET for cacheability
  • setInterval.*fetch\|ajax
    → CRITICAL: Polling pattern
  • import _ from 'lodash'
    → WARNING: Full library import bloats bundle
  • Inline
    <script>
    making AJAX calls on load → Check necessity
扫描以下内容:
  • 读取操作使用
    $.post(
    → 警告:使用GET以支持缓存
  • setInterval.*fetch\|ajax
    → 严重问题:轮询模式
  • import _ from 'lodash'
    → 警告:全库导入会增大包体积
  • 内联
    <script>
    在加载时发起AJAX请求 → 检查必要性

Block Editor / Gutenberg Files (
block.json
,
*.js
in blocks/)

区块编辑器/Gutenberg文件(
block.json
、blocks/目录下的
*.js

Scan for:
  • Many
    registerBlockStyle()
    calls → WARNING: Each creates preview iframe
  • wp_kses_post($content)
    in render callbacks → WARNING: Breaks InnerBlocks
  • Static blocks without
    render_callback
    → INFO: Consider dynamic for maintainability
扫描以下内容:
  • 大量
    registerBlockStyle()
    调用 → 警告:每个调用都会创建预览iframe
  • 渲染回调中的
    wp_kses_post($content)
    → 警告:破坏InnerBlocks
  • render_callback
    的静态区块 → 提示:考虑改为动态区块以提升可维护性

Asset Registration (
functions.php
,
*.php
)

资源注册(
functions.php
*.php

Scan for:
  • wp_enqueue_script
    without version → INFO: Cache busting issues
  • wp_enqueue_script
    without
    defer
    /
    async
    strategy → INFO: Blocks rendering
  • Missing
    THEME_VERSION
    constant → INFO: Version management
  • wp_enqueue_script
    without conditional check → WARNING: Assets load globally when only needed on specific pages
扫描以下内容:
  • 无版本号的
    wp_enqueue_script
    → 提示:缓存更新问题
  • defer
    /
    async
    策略的
    wp_enqueue_script
    → 提示:阻塞渲染
  • 缺失
    THEME_VERSION
    常量 → 提示:版本管理问题
  • 无条件判断的
    wp_enqueue_script
    → 警告:资源全局加载,但仅在特定页面需要

Transients & Options

临时数据(Transients)与选项

Scan for:
  • set_transient
    with dynamic keys (e.g.,
    user_{$id}
    ) → WARNING: Table bloat without object cache
  • set_transient
    for frequently-changing data → WARNING: Defeats caching purpose
  • Large data in transients on shared hosting → WARNING: DB bloat without object cache
扫描以下内容:
  • 带动态键的
    set_transient
    (如
    user_{$id}
    )→ 警告:无对象缓存时会导致表膨胀
  • 频繁变化的数据使用
    set_transient
    → 警告:违背缓存目的
  • 共享主机上临时数据存储大量数据 → 警告:无对象缓存时会导致数据库膨胀

WP-Cron

WP-Cron

Scan for:
  • Missing
    DISABLE_WP_CRON
    constant → INFO: Cron runs on page requests
  • Long-running cron callbacks (loops over all users/posts) → CRITICAL: Blocks cron queue
  • wp_schedule_event
    without checking if already scheduled → WARNING: Duplicate schedules
扫描以下内容:
  • 缺失
    DISABLE_WP_CRON
    常量 → 提示:Cron在页面请求时运行
  • 长时间运行的Cron回调(遍历所有用户/文章的循环)→ 严重问题:阻塞Cron队列
  • 未检查是否已调度就调用
    wp_schedule_event
    → 警告:重复调度

Search Patterns for Quick Detection

快速检测的搜索模式

bash
undefined
bash
undefined

Critical issues - scan these first

严重问题 - 优先扫描这些

grep -rn "posts_per_page.-1|numberposts.-1" . grep -rn "query_posts\s*(" . grep -rn "session_start\s*(" . grep -rn "setInterval.*fetch|setInterval.ajax|setInterval.\$." .
grep -rn "posts_per_page.-1|numberposts.-1" . grep -rn "query_posts\s*(" . grep -rn "session_start\s*(" . grep -rn "setInterval.*fetch|setInterval.ajax|setInterval.\$." .

Database writes on frontend

前端数据库写入

grep -rn "update_option|add_option" . | grep -v "admin|activate|install"
grep -rn "update_option|add_option" . | grep -v "admin|activate|install"

Uncached expensive functions

未缓存的高开销函数

grep -rn "url_to_postid|attachment_url_to_postid|count_user_posts" .
grep -rn "url_to_postid|attachment_url_to_postid|count_user_posts" .

External HTTP without caching

未缓存的外部HTTP请求

grep -rn "wp_remote_get|wp_remote_post|file_get_contents.*http" .
grep -rn "wp_remote_get|wp_remote_post|file_get_contents.*http" .

Cache bypass risks

缓存绕过风险

grep -rn "setcookie|session_start" .
grep -rn "setcookie|session_start" .

PHP code anti-patterns

PHP代码反模式

grep -rn "in_array\s*(" . | grep -v "true\s*)" # Missing strict comparison grep -rn "<<<" . # Heredoc/nowdoc syntax grep -rn "cache_results.*false" .
grep -rn "in_array\s*(" . | grep -v "true\s*)" # 缺失严格比较 grep -rn "<<<" . # Heredoc/nowdoc语法 grep -rn "cache_results.*false" .

JavaScript bundle issues

JavaScript包问题

grep -rn "import.*from.*lodash['"]" . # Full lodash import grep -rn "registerBlockStyle" . # Many block styles = performance issue
grep -rn "import.*from.*lodash['"]" . # 全Lodash导入 grep -rn "registerBlockStyle" . # 大量区块样式会导致性能问题

Asset loading issues

资源加载问题

grep -rn "wp_enqueue_script|wp_enqueue_style" . | grep -v "is_page|is_singular|is_admin"
grep -rn "wp_enqueue_script|wp_enqueue_style" . | grep -v "is_page|is_singular|is_admin"

Transient misuse

临时数据滥用

grep -rn "set_transient.*\$" . # Dynamic transient keys grep -rn "set_transient" . | grep -v "get_transient" # Set without checking first
grep -rn "set_transient.*\$" . # 动态临时数据键 grep -rn "set_transient" . | grep -v "get_transient" # 未检查就设置

WP-Cron issues

WP-Cron问题

grep -rn "wp_schedule_event" . | grep -v "wp_next_scheduled" # Missing schedule check
undefined
grep -rn "wp_schedule_event" . | grep -v "wp_next_scheduled" # 缺失调度检查
undefined

Platform Context

平台环境适配

Different hosting environments require different approaches:
Managed WordPress Hosts (WP Engine, Pantheon, Pressable, WordPress VIP, etc.):
  • Often provide object caching out of the box
  • May have platform-specific helper functions (e.g.,
    wpcom_vip_*
    on VIP)
  • Check host documentation for recommended patterns
Self-Hosted / Standard Hosting:
  • Implement object caching wrappers manually for expensive functions
  • Consider Redis or Memcached plugins for persistent object cache
  • More responsibility for caching layer configuration
Shared Hosting:
  • Be extra cautious about unbounded queries and external HTTP
  • Limited resources mean performance issues surface faster
  • May lack persistent object cache entirely
不同的托管环境需要不同的处理方式:
托管WordPress主机(WP Engine、Pantheon、Pressable、WordPress VIP等):
  • 通常默认提供对象缓存
  • 可能有平台专属的辅助函数(如VIP平台的
    wpcom_vip_*
  • 查阅主机文档获取推荐模式
自托管/标准主机
  • 为高开销函数手动实现对象缓存包装器
  • 考虑使用Redis或Memcached插件实现持久化对象缓存
  • 需自行负责缓存层配置
共享主机
  • 对无界查询和外部HTTP请求格外谨慎
  • 资源有限,性能问题会更快显现
  • 可能完全没有持久化对象缓存

Quick Reference: Critical Anti-Patterns

快速参考:关键反模式

Database Queries

数据库查询

php
// ❌ CRITICAL: Unbounded query.
'posts_per_page' => -1

// ✅ GOOD: Set reasonable limit, paginate if needed.
'posts_per_page' => 100,
'no_found_rows'  => true, // Skip count if not paginating.

// ❌ CRITICAL: Never use query_posts().
query_posts( 'cat=1' ); // Breaks pagination, conditionals.

// ✅ GOOD: Use WP_Query or pre_get_posts filter.
$query = new WP_Query( array( 'cat' => 1 ) );
// Or modify main query:
add_action( 'pre_get_posts', function( $query ) {
    if ( $query->is_main_query() && ! is_admin() ) {
        $query->set( 'cat', 1 );
    }
} );

// ❌ CRITICAL: Missing WHERE clause (falsy ID becomes 0).
$query = new WP_Query( array( 'p' => intval( $maybe_false_id ) ) );

// ✅ GOOD: Validate ID before querying.
if ( ! empty( $maybe_false_id ) ) {
    $query = new WP_Query( array( 'p' => intval( $maybe_false_id ) ) );
}

// ❌ WARNING: LIKE with leading wildcard (full table scan).
$wpdb->get_results( "SELECT * FROM wp_posts WHERE post_title LIKE '%term%'" );

// ✅ GOOD: Use trailing wildcard only, or use WP_Query 's' parameter.
$wpdb->get_results( $wpdb->prepare(
    "SELECT * FROM wp_posts WHERE post_title LIKE %s",
    $wpdb->esc_like( $term ) . '%'
) );

// ❌ WARNING: NOT IN queries (filter in PHP instead).
'post__not_in' => $excluded_ids

// ✅ GOOD: Fetch all, filter in PHP (faster for large exclusion lists).
$posts = get_posts( array( 'posts_per_page' => 100 ) );
$posts = array_filter( $posts, function( $post ) use ( $excluded_ids ) {
    return ! in_array( $post->ID, $excluded_ids, true );
} );
php
// ❌ 严重问题:无界查询。
'posts_per_page' => -1

// ✅ 正确做法:设置合理限制,必要时分页。
'posts_per_page' => 100,
'no_found_rows'  => true, // 非分页查询时跳过计数。

// ❌ 严重问题:绝对禁止使用query_posts()。
query_posts( 'cat=1' ); // 破坏分页和条件判断。

// ✅ 正确做法:使用WP_Query或pre_get_posts过滤器。
$query = new WP_Query( array( 'cat' => 1 ) );
// 或修改主查询:
add_action( 'pre_get_posts', function( $query ) {
    if ( $query->is_main_query() && ! is_admin() ) {
        $query->set( 'cat', 1 );
    }
} );

// ❌ 严重问题:缺失WHERE子句(假ID会变为0)。
$query = new WP_Query( array( 'p' => intval( $maybe_false_id ) ) );

// ✅ 正确做法:查询前验证ID。
if ( ! empty( $maybe_false_id ) ) {
    $query = new WP_Query( array( 'p' => intval( $maybe_false_id ) ) );
}

// ❌ 警告:带前导通配符的LIKE(全表扫描)。
$wpdb->get_results( "SELECT * FROM wp_posts WHERE post_title LIKE '%term%'" );

// ✅ 正确做法:仅使用后导通配符,或使用WP_Query的's'参数。
$wpdb->get_results( $wpdb->prepare(
    "SELECT * FROM wp_posts WHERE post_title LIKE %s",
    $wpdb->esc_like( $term ) . '%'
) );

// ❌ 警告:NOT IN查询(改用PHP过滤)。
'post__not_in' => $excluded_ids

// ✅ 正确做法:获取全部数据后在PHP中过滤(大排除列表时更快)。
$posts = get_posts( array( 'posts_per_page' => 100 ) );
$posts = array_filter( $posts, function( $post ) use ( $excluded_ids ) {
    return ! in_array( $post->ID, $excluded_ids, true );
} );

Hooks & Actions

钩子与动作

php
// ❌ WARNING: Code runs on every request via init.
add_action( 'init', 'expensive_function' );

// ✅ GOOD: Check context before running expensive code.
add_action( 'init', function() {
    if ( is_admin() || wp_doing_cron() ) {
        return;
    }
    // Frontend-only code here.
} );

// ❌ CRITICAL: Database writes on every page load.
add_action( 'wp_head', 'prefix_bad_tracking' );
function prefix_bad_tracking() {
    update_option( 'last_visit', time() );
}

// ✅ GOOD: Use object cache buffer, flush via cron.
add_action( 'shutdown', function() {
    wp_cache_incr( 'page_views_buffer', 1, 'counters' );
} );

// ❌ WARNING: Using admin-ajax.php instead of REST API.
// Prefer: register_rest_route() - leaner bootstrap.
php
// ❌ 警告:代码通过init在每次请求时运行。
add_action( 'init', 'expensive_function' );

// ✅ 正确做法:运行高开销代码前检查上下文。
add_action( 'init', function() {
    if ( is_admin() || wp_doing_cron() ) {
        return;
    }
    // 此处放置仅前端运行的代码。
} );

// ❌ 严重问题:每次页面加载时写入数据库。
add_action( 'wp_head', 'prefix_bad_tracking' );
function prefix_bad_tracking() {
    update_option( 'last_visit', time() );
}

// ✅ 正确做法:使用对象缓存缓冲,通过Cron刷新。
add_action( 'shutdown', function() {
    wp_cache_incr( 'page_views_buffer', 1, 'counters' );
} );

// ❌ 警告:使用admin-ajax.php而非REST API。
// 推荐:register_rest_route() - 更轻量的引导流程。

PHP Code

PHP代码

php
// ❌ WARNING: O(n) lookup - use isset() with associative array.
in_array( $value, $array ); // Also missing strict = true.

// ✅ GOOD: O(1) lookup with isset().
$allowed = array( 'foo' => true, 'bar' => true );
if ( isset( $allowed[ $value ] ) ) {
    // Process.
}

// ❌ WARNING: Heredoc prevents late escaping.
$html = <<<HTML
<div>$unescaped_content</div>
HTML;

// ✅ GOOD: Escape at output.
printf( '<div>%s</div>', esc_html( $content ) );
php
// ❌ 警告:O(n)查找 - 使用关联数组的isset()。
in_array( $value, $array ); // 还缺失strict = true。

// ✅ 正确做法:使用isset()实现O(1)查找。
$allowed = array( 'foo' => true, 'bar' => true );
if ( isset( $allowed[ $value ] ) ) {
    // 处理逻辑。
}

// ❌ 警告:Heredoc语法会延迟转义。
$html = <<<HTML
<div>$unescaped_content</div>
HTML;

// ✅ 正确做法:输出时转义。
printf( '<div>%s</div>', esc_html( $content ) );

Caching Issues

缓存问题

php
// ❌ WARNING: Uncached expensive function calls.
url_to_postid( $url );
attachment_url_to_postid( $attachment_url );
count_user_posts( $user_id );
wp_oembed_get( $url );

// ✅ GOOD: Wrap with object cache (works on any host).
function prefix_cached_url_to_postid( $url ) {
    $cache_key = 'url_to_postid_' . md5( $url );
    $post_id   = wp_cache_get( $cache_key, 'url_lookups' );

    if ( false === $post_id ) {
        $post_id = url_to_postid( $url );
        wp_cache_set( $cache_key, $post_id, 'url_lookups', HOUR_IN_SECONDS );
    }

    return $post_id;
}

// ✅ GOOD: On WordPress VIP, use platform helpers instead.
// wpcom_vip_url_to_postid(), wpcom_vip_attachment_url_to_postid(), etc.

// ❌ WARNING: Large autoloaded options.
add_option( 'prefix_large_data', $data ); // Add: , '', 'no' for autoload.

// ❌ INFO: Missing wp_cache_get_multiple for batch lookups.
foreach ( $ids as $id ) {
    wp_cache_get( "key_{$id}" );
}
php
// ❌ 警告:未缓存的高开销函数调用。
url_to_postid( $url );
attachment_url_to_postid( $attachment_url );
count_user_posts( $user_id );
wp_oembed_get( $url );

// ✅ 正确做法:用对象缓存包装(适用于所有主机)。
function prefix_cached_url_to_postid( $url ) {
    $cache_key = 'url_to_postid_' . md5( $url );
    $post_id   = wp_cache_get( $cache_key, 'url_lookups' );

    if ( false === $post_id ) {
        $post_id = url_to_postid( $url );
        wp_cache_set( $cache_key, $post_id, 'url_lookups', HOUR_IN_SECONDS );
    }

    return $post_id;
}

// ✅ 正确做法:在WordPress VIP平台,改用平台辅助函数。
// wpcom_vip_url_to_postid(), wpcom_vip_attachment_url_to_postid(), 等。

// ❌ 警告:大型自动加载选项。
add_option( 'prefix_large_data', $data ); // 添加: , '', 'no' 禁用自动加载。

// ❌ 提示:批量查找时缺失wp_cache_get_multiple。
foreach ( $ids as $id ) {
    wp_cache_get( "key_{$id}" );
}

AJAX & External Requests

AJAX与外部请求

javascript
// ❌ WARNING: AJAX POST request (bypasses cache).
$.post( ajaxurl, data ); // Prefer: $.get() for read operations.

// ❌ CRITICAL: Polling pattern (self-DDoS).
setInterval( () => fetch( '/wp-json/...' ), 5000 );
php
// ❌ WARNING: Synchronous external HTTP in page load.
wp_remote_get( $url ); // Cache result or move to cron.

// ✅ GOOD: Set timeout and handle errors.
$response = wp_remote_get( $url, array( 'timeout' => 2 ) );
if ( is_wp_error( $response ) ) {
    return get_fallback_data();
}
javascript
// ❌ 警告:AJAX POST请求(绕过缓存)。
$.post( ajaxurl, data ); // 推荐:读取操作使用$.get()。

// ❌ 严重问题:轮询模式(自DDoS)。
setInterval( () => fetch( '/wp-json/...' ), 5000 );
php
// ❌ 警告:页面加载时发起同步外部HTTP请求。
wp_remote_get( $url ); // 缓存结果或移至Cron。

// ✅ 正确做法:设置超时并处理错误。
$response = wp_remote_get( $url, array( 'timeout' => 2 ) );
if ( is_wp_error( $response ) ) {
    return get_fallback_data();
}

WP Cron

WP Cron

php
// ❌ WARNING: WP Cron runs on page requests.
// Add to wp-config.php:
define( 'DISABLE_WP_CRON', true );
// Run via server cron: * * * * * wp cron event run --due-now

// ❌ CRITICAL: Long-running cron blocks entire queue.
add_action( 'my_daily_sync', function() {
    foreach ( get_users() as $user ) { // 50k users = hours.
        sync_user_data( $user );
    }
} );

// ✅ GOOD: Batch processing with rescheduling.
add_action( 'my_batch_sync', function() {
    $offset = (int) get_option( 'sync_offset', 0 );
    $users  = get_users( array( 'number' => 100, 'offset' => $offset ) );

    if ( empty( $users ) ) {
        delete_option( 'sync_offset' );
        return;
    }

    foreach ( $users as $user ) {
        sync_user_data( $user );
    }

    update_option( 'sync_offset', $offset + 100 );
    wp_schedule_single_event( time() + 60, 'my_batch_sync' );
} );

// ❌ WARNING: Scheduling without checking if already scheduled.
wp_schedule_event( time(), 'hourly', 'my_task' ); // Creates duplicates!

// ✅ GOOD: Check before scheduling.
if ( ! wp_next_scheduled( 'my_task' ) ) {
    wp_schedule_event( time(), 'hourly', 'my_task' );
}
php
// ❌ 警告:WP Cron在页面请求时运行。
// 添加到wp-config.php:
define( 'DISABLE_WP_CRON', true );
// 通过服务器Cron运行:* * * * * wp cron event run --due-now

// ❌ 严重问题:长时间运行的Cron阻塞整个队列。
add_action( 'my_daily_sync', function() {
    foreach ( get_users() as $user ) { // 5万用户需耗时数小时。
        sync_user_data( $user );
    }
} );

// ✅ 正确做法:批量处理并重新调度。
add_action( 'my_batch_sync', function() {
    $offset = (int) get_option( 'sync_offset', 0 );
    $users  = get_users( array( 'number' => 100, 'offset' => $offset ) );

    if ( empty( $users ) ) {
        delete_option( 'sync_offset' );
        return;
    }

    foreach ( $users as $user ) {
        sync_user_data( $user );
    }

    update_option( 'sync_offset', $offset + 100 );
    wp_schedule_single_event( time() + 60, 'my_batch_sync' );
} );

// ❌ 警告:未检查是否已调度就调用wp_schedule_event。
wp_schedule_event( time(), 'hourly', 'my_task' ); // 会创建重复调度!

// ✅ 正确做法:调度前检查。
if ( ! wp_next_scheduled( 'my_task' ) ) {
    wp_schedule_event( time(), 'hourly', 'my_task' );
}

Cache Bypass Issues

缓存绕过问题

php
// ❌ CRITICAL: Plugin starts PHP session on frontend (bypasses ALL page cache).
session_start(); // Check plugins for this - entire site becomes uncacheable!

// ❌ WARNING: Unique query params create cache misses.
// https://example.com/?utm_source=fb&utm_campaign=123&fbclid=abc
// Each unique URL = separate cache entry = cache miss.
// Solution: Strip marketing params at CDN/edge level.

// ❌ WARNING: Setting cookies on public pages.
setcookie( 'visitor_id', $id ); // Prevents caching for that user.
php
// ❌ 严重问题:插件在前端启动PHP会话(绕过所有页面缓存)。
session_start(); // 检查所有代码中的session_start - 会导致整个网站无法缓存!

// ❌ 警告:唯一查询参数导致缓存未命中。
// https://example.com/?utm_source=fb&utm_campaign=123&fbclid=abc
// 每个唯一URL都会生成单独的缓存条目 = 缓存未命中。
// 解决方案:在CDN/边缘层剥离营销参数。

// ❌ 警告:在公共页面设置Cookie。
setcookie( 'visitor_id', $id ); // 会阻止该用户的缓存。

Transients Misuse

临时数据(Transients)滥用

php
// ❌ WARNING: Dynamic transient keys create table bloat (without object cache).
set_transient( "user_{$user_id}_cart", $data, HOUR_IN_SECONDS );
// 10,000 users = 10,000 rows in wp_options!

// ✅ GOOD: Use object cache for user-specific data.
wp_cache_set( "cart_{$user_id}", $data, 'user_carts', HOUR_IN_SECONDS );

// ❌ WARNING: Transients for frequently-changing data defeats purpose.
set_transient( 'visitor_count', $count, 60 ); // Changes every minute.

// ✅ GOOD: Use object cache for volatile data.
wp_cache_set( 'visitor_count', $count, 'stats' );

// ❌ WARNING: Large data in transients on shared hosting.
set_transient( 'api_response', $megabytes_of_json, DAY_IN_SECONDS );
// Without object cache = serialized blob in wp_options.

// ✅ GOOD: Check hosting before using transients for large data.
if ( wp_using_ext_object_cache() ) {
    set_transient( 'api_response', $data, DAY_IN_SECONDS );
} else {
    // Store in files or skip caching on shared hosting.
}
php
// ❌ 警告:动态临时数据键会导致表膨胀(无对象缓存时)。
set_transient( "user_{$user_id}_cart", $data, HOUR_IN_SECONDS );
// 1万用户会在wp_options表中产生1万行记录!

// ✅ 正确做法:使用对象缓存存储用户专属数据。
wp_cache_set( "cart_{$user_id}", $data, 'user_carts', HOUR_IN_SECONDS );

// ❌ 警告:频繁变化的数据使用临时数据会违背缓存目的。
set_transient( 'visitor_count', $count, 60 ); // 每分钟变化一次。

// ✅ 正确做法:使用对象缓存存储易变数据。
wp_cache_set( 'visitor_count', $count, 'stats' );

// ❌ 警告:共享主机上临时数据存储大量数据。
set_transient( 'api_response', $megabytes_of_json, DAY_IN_SECONDS );
// 无对象缓存时 = wp_options表中的序列化大对象。

// ✅ 正确做法:使用临时数据存储大量数据前检查主机环境。
if ( wp_using_ext_object_cache() ) {
    set_transient( 'api_response', $data, DAY_IN_SECONDS );
} else {
    // 存储到文件或在共享主机上跳过缓存。
}

Asset Loading

资源加载

php
// ❌ WARNING: Assets load globally when only needed on specific pages.
add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_script( 'contact-form-js', ... );
    wp_enqueue_style( 'contact-form-css', ... );
} );

// ✅ GOOD: Conditional enqueue based on page/template.
add_action( 'wp_enqueue_scripts', function() {
    if ( is_page( 'contact' ) || is_page_template( 'contact-template.php' ) ) {
        wp_enqueue_script( 'contact-form-js', ... );
        wp_enqueue_style( 'contact-form-css', ... );
    }
} );

// ✅ GOOD: Only load WooCommerce assets on shop pages.
add_action( 'wp_enqueue_scripts', function() {
    if ( ! is_woocommerce() && ! is_cart() && ! is_checkout() ) {
        wp_dequeue_style( 'woocommerce-general' );
        wp_dequeue_script( 'wc-cart-fragments' );
    }
} );
php
// ❌ 警告:资源全局加载,但仅在特定页面需要。
add_action( 'wp_enqueue_scripts', function() {
    wp_enqueue_script( 'contact-form-js', ... );
    wp_enqueue_style( 'contact-form-css', ... );
} );

// ✅ 正确做法:根据页面/模板条件加载资源。
add_action( 'wp_enqueue_scripts', function() {
    if ( is_page( 'contact' ) || is_page_template( 'contact-template.php' ) ) {
        wp_enqueue_script( 'contact-form-js', ... );
        wp_enqueue_style( 'contact-form-css', ... );
    }
} );

// ✅ 正确做法:仅在电商页面加载WooCommerce资源。
add_action( 'wp_enqueue_scripts', function() {
    if ( ! is_woocommerce() && ! is_cart() && ! is_checkout() ) {
        wp_dequeue_style( 'woocommerce-general' );
        wp_dequeue_script( 'wc-cart-fragments' );
    }
} );

External API Requests

外部API请求

php
// ❌ WARNING: No timeout set (default is 5 seconds).
wp_remote_get( $url ); // Set timeout: array( 'timeout' => 2 ).

// ❌ WARNING: Missing error handling for API failures.
$response = wp_remote_get( $url );
echo $response['body']; // Check is_wp_error() first!
php
// ❌ 警告:未设置超时(默认5秒)。
wp_remote_get( $url ); // 设置超时:array( 'timeout' => 2 )。

// ❌ 警告:API失败时缺失错误处理。
$response = wp_remote_get( $url );
echo $response['body']; // 先检查is_wp_error()!

Sitemaps & Redirects

站点地图与重定向

php
// ❌ WARNING: Generating sitemaps for deep archives (crawlers hammer these).
// Solution: Exclude old post types, cache generated sitemaps.

// ❌ CRITICAL: Redirect loops consuming CPU.
// Debug with: x-redirect-by header, wp_debug_backtrace_summary().
php
// ❌ 警告:为深层归档生成站点地图(爬虫会频繁请求)。
// 解决方案:排除旧文章类型,缓存生成的站点地图。

// ❌ 严重问题:重定向循环消耗CPU。
// 使用x-redirect-by头、wp_debug_backtrace_summary()调试。

Post Meta Queries

文章元查询

php
// ❌ WARNING: Searching meta_value without index.
'meta_query' => array(
    array(
        'key'   => 'color',
        'value' => 'red',
    ),
)
// Better: Use taxonomy or encode value in meta_key name.

// ❌ WARNING: Binary meta values requiring value scan.
'meta_key'   => 'featured',
'meta_value' => 'true',
// Better: Presence of 'is_featured' key = true, absence = false.
For deeper context on any pattern: Load
references/anti-patterns.md
php
// ❌ 警告:无索引时搜索meta_value。
'meta_query' => array(
    array(
        'key'   => 'color',
        'value' => 'red',
    ),
)
// 更好的做法:使用分类法或在meta_key名称中编码值。

// ❌ 警告:需要值扫描的二进制元值。
'meta_key'   => 'featured',
'meta_value' => 'true',
// 更好的做法:存在'is_featured'键表示true,不存在表示false。
如需了解任何模式的深层背景: 加载
references/anti-patterns.md

Severity Definitions

严重程度定义

SeverityDescription
CriticalWill cause failures at scale (OOM, 500 errors, DB locks)
WarningDegrades performance under load
InfoOptimization opportunity
严重程度描述
Critical(严重)高并发时会导致故障(OOM、500错误、数据库锁)
Warning(警告)高负载时会降低性能
Info(提示)优化机会

Output Format

输出格式

Structure findings as:
markdown
undefined
按以下结构整理发现的问题:
markdown
undefined

Performance Review: [filename/component]

性能审查:[文件名/组件]

Critical Issues

严重问题

  • Line X: [Issue] - [Explanation] - [Fix]
  • 第X行:[问题] - [说明] - [修复方案]

Warnings

警告

  • Line X: [Issue] - [Explanation] - [Fix]
  • 第X行:[问题] - [说明] - [修复方案]

Recommendations

推荐优化

  • [Optimization opportunities]
  • [优化机会]

Summary

总结

  • Total issues: X Critical, Y Warnings, Z Info
  • Estimated impact: [High/Medium/Low]
undefined
  • 问题总数:X个严重问题,Y个警告,Z个提示
  • 预估影响:[高/中/低]
undefined

Common Mistakes

常见错误

When performing performance reviews, avoid these errors:
MistakeWhy It's WrongFix
Flagging
posts_per_page => -1
in admin-only code
Admin queries don't face public scaleCheck context - admin, CLI, cron are lower risk
Missing the
session_start()
buried in a plugin
Cache bypass affects entire siteAlways grep for
session_start
across all code
Ignoring
no_found_rows
for non-paginated queries
Small optimization but adds upFlag as INFO, not WARNING
Recommending object cache on shared hostingMany shared hosts lack persistent cacheCheck hosting environment first
Only reviewing PHP, missing JS pollingJS
setInterval
+ fetch = self-DDoS
Review
.js
files for polling patterns
执行性能审查时,避免以下错误:
错误原因修复方案
标记仅管理后台代码中的
posts_per_page => -1
管理后台查询无需面对公共高并发检查上下文 - 管理后台、CLI、Cron的风险更低
遗漏插件中隐藏的
session_start()
缓存绕会影响整个网站始终在所有代码中搜索
session_start
忽略非分页查询的
no_found_rows
虽小但累积影响大标记为提示,而非警告
在共享主机上推荐使用对象缓存许多共享主机无持久化缓存先检查主机环境
仅审查PHP代码,忽略JS轮询JS的
setInterval
+fetch会导致自DDoS
审查
.js
文件中的轮询模式

Deep-Dive References

深度参考

Load these references based on the task:
TaskReference to Load
Reviewing PHP code for issues
references/anti-patterns.md
Optimizing WP_Query calls
references/wp-query-guide.md
Implementing caching
references/caching-guide.md
High-traffic event prep
references/measurement-guide.md
Note: For standard code reviews,
anti-patterns.md
contains all patterns needed. Other references provide deeper context when specifically optimizing queries, implementing caching strategies, or preparing for traffic events.
根据任务加载以下参考文档:
任务参考文档
审查PHP代码问题
references/anti-patterns.md
优化WP_Query调用
references/wp-query-guide.md
实现缓存策略
references/caching-guide.md
高流量事件准备
references/measurement-guide.md
注意:标准代码审查仅需
anti-patterns.md
中的所有模式。在专门优化查询、实现缓存策略或准备高流量事件时,其他参考文档可提供更深入的内容。