wp-performance-review
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWordPress 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
代码审查流程
- Identify file type and apply relevant checks below
- Scan for critical patterns first (OOM, unbounded queries, cache bypass)
- Check warnings (inefficient but not catastrophic)
- Note optimizations (nice-to-have improvements)
- Report with line numbers using output format below
- 识别文件类型并应用下方对应的检查项
- 优先扫描关键模式(OOM、无界查询、缓存绕过)
- 检查警告项(效率低下但不致命)
- 记录优化建议(锦上添花的改进)
- 按以下输出格式附带行号生成报告
File-Type Specific Checks
按文件类型的专项检查
Plugin/Theme PHP Files (functions.php
, plugin.php
, *.php
)
functions.phpplugin.php*.php插件/主题PHP文件(functions.php
、plugin.php
、*.php
)
functions.phpplugin.php*.phpScan for:
- → CRITICAL: Never use - breaks main query
query_posts() - or
posts_per_page.*-1→ CRITICAL: Unbounded querynumberposts.*-1 - → CRITICAL: Bypasses page cache
session_start() - or
add_action.*init.*→ Check if expensive code runs every requestadd_action.*wp_loaded - or
update_optionin non-admin context → WARNING: DB writes on page loadadd_option - or
wp_remote_getwithout caching → WARNING: Blocking HTTPwp_remote_post
扫描以下内容:
- → 严重问题:绝对禁止使用 - 会破坏主查询
query_posts() - 或
posts_per_page.*-1→ 严重问题:无界查询numberposts.*-1 - → 严重问题:绕过页面缓存
session_start() - 或
add_action.*init.*→ 检查是否有高开销代码在每次请求时运行add_action.*wp_loaded - 非管理后台上下文的或
update_option→ 警告:页面加载时写入数据库add_option - 未缓存的或
wp_remote_get→ 警告:阻塞式HTTP请求wp_remote_post
WP_Query / Database Code
WP_Query / 数据库代码
Scan for:
- Missing argument → WARNING: Defaults to blog setting
posts_per_page - with
'meta_query'comparisons → WARNING: Unindexed column scan'value' - with large arrays → WARNING: Slow exclusion
post__not_in - (leading wildcard) → WARNING: Full table scan
LIKE '%term%' - Missing when not paginating → INFO: Unnecessary count
no_found_rows => true
扫描以下内容:
- 缺失参数 → 警告:默认使用博客设置
posts_per_page - 带比较的
'value'→ 警告:未索引列扫描'meta_query' - 包含大数组的→ 警告:缓慢的排除操作
post__not_in - (前导通配符)→ 警告:全表扫描
LIKE '%term%' - 非分页查询时缺失→ 提示:不必要的计数操作
no_found_rows => true
AJAX Handlers (wp_ajax_*
, REST endpoints)
wp_ajax_*AJAX处理器(wp_ajax_*
、REST端点)
wp_ajax_*Scan for:
- usage → INFO: Consider REST API instead
admin-ajax.php - POST method for read operations → WARNING: Bypasses cache
- or polling patterns → CRITICAL: Self-DDoS risk
setInterval - Missing nonce verification → Security issue (not performance, but flag it)
扫描以下内容:
- 的使用 → 提示:考虑改用REST API
admin-ajax.php - 读取操作使用POST方法 → 警告:绕过缓存
- 或轮询模式 → 严重问题:自DDoS风险
setInterval - 缺失随机数验证 → 安全问题(非性能问题,但需标记)
Template Files (*.php
in theme)
*.php模板文件(主题中的*.php
)
*.phpScan for:
- in loops → WARNING: Consider caching output
get_template_part - Database queries inside loops (N+1) → CRITICAL: Query multiplication
- in templates → WARNING: Blocks rendering
wp_remote_get
扫描以下内容:
- 循环中的→ 警告:考虑缓存输出
get_template_part - 循环内的数据库查询(N+1问题)→ 严重问题:查询次数倍增
- 模板中的→ 警告:阻塞渲染
wp_remote_get
JavaScript Files
JavaScript文件
Scan for:
- for read operations → WARNING: Use GET for cacheability
$.post( - → CRITICAL: Polling pattern
setInterval.*fetch\|ajax - → WARNING: Full library import bloats bundle
import _ from 'lodash' - Inline making AJAX calls on load → Check necessity
<script>
扫描以下内容:
- 读取操作使用→ 警告:使用GET以支持缓存
$.post( - → 严重问题:轮询模式
setInterval.*fetch\|ajax - → 警告:全库导入会增大包体积
import _ from 'lodash' - 内联在加载时发起AJAX请求 → 检查必要性
<script>
Block Editor / Gutenberg Files (block.json
, *.js
in blocks/)
block.json*.js区块编辑器/Gutenberg文件(block.json
、blocks/目录下的*.js
)
block.json*.jsScan for:
- Many calls → WARNING: Each creates preview iframe
registerBlockStyle() - in render callbacks → WARNING: Breaks InnerBlocks
wp_kses_post($content) - Static blocks without → INFO: Consider dynamic for maintainability
render_callback
扫描以下内容:
- 大量调用 → 警告:每个调用都会创建预览iframe
registerBlockStyle() - 渲染回调中的→ 警告:破坏InnerBlocks
wp_kses_post($content) - 无的静态区块 → 提示:考虑改为动态区块以提升可维护性
render_callback
Asset Registration (functions.php
, *.php
)
functions.php*.php资源注册(functions.php
、*.php
)
functions.php*.phpScan for:
- without version → INFO: Cache busting issues
wp_enqueue_script - without
wp_enqueue_script/deferstrategy → INFO: Blocks renderingasync - Missing constant → INFO: Version management
THEME_VERSION - without conditional check → WARNING: Assets load globally when only needed on specific pages
wp_enqueue_script
扫描以下内容:
- 无版本号的→ 提示:缓存更新问题
wp_enqueue_script - 无/
defer策略的async→ 提示:阻塞渲染wp_enqueue_script - 缺失常量 → 提示:版本管理问题
THEME_VERSION - 无条件判断的→ 警告:资源全局加载,但仅在特定页面需要
wp_enqueue_script
Transients & Options
临时数据(Transients)与选项
Scan for:
- with dynamic keys (e.g.,
set_transient) → WARNING: Table bloat without object cacheuser_{$id} - for frequently-changing data → WARNING: Defeats caching purpose
set_transient - 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 constant → INFO: Cron runs on page requests
DISABLE_WP_CRON - Long-running cron callbacks (loops over all users/posts) → CRITICAL: Blocks cron queue
- without checking if already scheduled → WARNING: Duplicate schedules
wp_schedule_event
扫描以下内容:
- 缺失常量 → 提示:Cron在页面请求时运行
DISABLE_WP_CRON - 长时间运行的Cron回调(遍历所有用户/文章的循环)→ 严重问题:阻塞Cron队列
- 未检查是否已调度就调用→ 警告:重复调度
wp_schedule_event
Search Patterns for Quick Detection
快速检测的搜索模式
bash
undefinedbash
undefinedCritical 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
undefinedgrep -rn "wp_schedule_event" . | grep -v "wp_next_scheduled" # 缺失调度检查
undefinedPlatform 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., on VIP)
wpcom_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.mdphp
// ❌ 警告:无索引时搜索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.mdSeverity Definitions
严重程度定义
| Severity | Description |
|---|---|
| Critical | Will cause failures at scale (OOM, 500 errors, DB locks) |
| Warning | Degrades performance under load |
| Info | Optimization opportunity |
| 严重程度 | 描述 |
|---|---|
| Critical(严重) | 高并发时会导致故障(OOM、500错误、数据库锁) |
| Warning(警告) | 高负载时会降低性能 |
| Info(提示) | 优化机会 |
Output Format
输出格式
Structure findings as:
markdown
undefined按以下结构整理发现的问题:
markdown
undefinedPerformance 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个提示
- 预估影响:[高/中/低]
undefinedCommon Mistakes
常见错误
When performing performance reviews, avoid these errors:
| Mistake | Why It's Wrong | Fix |
|---|---|---|
Flagging | Admin queries don't face public scale | Check context - admin, CLI, cron are lower risk |
Missing the | Cache bypass affects entire site | Always grep for |
Ignoring | Small optimization but adds up | Flag as INFO, not WARNING |
| Recommending object cache on shared hosting | Many shared hosts lack persistent cache | Check hosting environment first |
| Only reviewing PHP, missing JS polling | JS | Review |
执行性能审查时,避免以下错误:
| 错误 | 原因 | 修复方案 |
|---|---|---|
标记仅管理后台代码中的 | 管理后台查询无需面对公共高并发 | 检查上下文 - 管理后台、CLI、Cron的风险更低 |
遗漏插件中隐藏的 | 缓存绕会影响整个网站 | 始终在所有代码中搜索 |
忽略非分页查询的 | 虽小但累积影响大 | 标记为提示,而非警告 |
| 在共享主机上推荐使用对象缓存 | 许多共享主机无持久化缓存 | 先检查主机环境 |
| 仅审查PHP代码,忽略JS轮询 | JS的 | 审查 |
Deep-Dive References
深度参考
Load these references based on the task:
| Task | Reference to Load |
|---|---|
| Reviewing PHP code for issues | |
| Optimizing WP_Query calls | |
| Implementing caching | |
| High-traffic event prep | |
Note: For standard code reviews, contains all patterns needed. Other references provide deeper context when specifically optimizing queries, implementing caching strategies, or preparing for traffic events.
anti-patterns.md根据任务加载以下参考文档:
| 任务 | 参考文档 |
|---|---|
| 审查PHP代码问题 | |
| 优化WP_Query调用 | |
| 实现缓存策略 | |
| 高流量事件准备 | |
注意:标准代码审查仅需中的所有模式。在专门优化查询、实现缓存策略或准备高流量事件时,其他参考文档可提供更深入的内容。
anti-patterns.md