応用編
⚡ パフォーマンス最適化
重いプラグインはサイトの表示速度・SEO・ユーザー体験を悪化させます。Transients APIによるキャッシュ・WP_Queryの最適化・アセット管理・WP Cronによる非同期処理を習得しましょう。
📊 パフォーマンスが重要な理由
Googleはページ表示速度をSEOランキングの指標として使っています。また表示に3秒以上かかると約53%のユーザーが離脱するというデータもあります。プラグイン開発者は常にパフォーマンスを意識しましょう。
よくある遅い原因
- 毎回DBクエリを実行している(キャッシュなし)
- 全ページでCSS/JSを読み込んでいる
- WP_Queryのオプションが最適化されていない
- 外部APIを同期で呼び出している
- ループ内でDBクエリを実行(N+1問題)
改善のアプローチ
- Query Monitorで遅いクエリを特定する
- Transients APIでキャッシュを実装
- WP_Queryのオプションを見直す
- アセットを必要なページだけに限定
- 重い処理をWP Cronに移す
📦 Transients API — 一時キャッシュ
重いDBクエリや外部APIリクエストの結果をキャッシュして、繰り返しの処理を防ぎます。Redis/Memcachedが導入されているサーバーでは自動的にメモリキャッシュを使用します。
function mfp_get_popular_posts( $count = 10 ) {
$cache_key = 'mfp_popular_' . $count; // 引数ごとに異なるキーを使う
$cached = get_transient( $cache_key );
if ( false !== $cached ) {
return $cached; // キャッシュヒット
}
// 重いクエリ(初回のみ実行)
$posts = get_posts( array(
'numberposts' => $count,
'meta_key' => 'mfp_view_count',
'orderby' => 'meta_value_num',
'order' => 'DESC',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
) );
set_transient( $cache_key, $posts, HOUR_IN_SECONDS );
return $posts;
}
// 投稿が更新・削除されたらキャッシュを無効化
add_action( 'save_post', 'mfp_clear_post_cache' );
add_action( 'delete_post', 'mfp_clear_post_cache' );
function mfp_clear_post_cache() {
foreach ( array( 5, 10, 20 ) as $n ) {
delete_transient( 'mfp_popular_' . $n );
}
}
| 時間定数 | 秒数 | 用途例 |
|---|---|---|
| MINUTE_IN_SECONDS | 60 | 頻繁に更新されるデータ |
| HOUR_IN_SECONDS | 3,600 | 記事一覧・人気投稿 |
| DAY_IN_SECONDS | 86,400 | 統計・ランキング |
| WEEK_IN_SECONDS | 604,800 | 外部APIデータ |
| MONTH_IN_SECONDS | 2,592,000 | ほぼ変わらないデータ |
🔍 WP_Query の最適化
$query = new WP_Query( array(
'post_type' => 'post',
'posts_per_page' => 10,
// ─ パフォーマンス最適化オプション ─────────────────────
'no_found_rows' => true, // ページネーションが不要なら必ずtrue
// (SQL_CALC_FOUND_ROWSを省略できる)
'update_post_meta_cache' => false, // ループ内でget_post_meta()を使わないならfalse
'update_post_term_cache' => false, // カテゴリー・タグを表示しないならfalse
'fields' => 'ids', // IDだけ必要な場合(最も軽量)
) );
💡 N+1問題を避ける
ループ内で get_post_meta() を呼ぶとクエリが投稿数分発生します。update_post_meta_cache => true(デフォルト)のままにすることで、WP_Queryが postmeta を一括プリロードします。fields => 'ids' を使う場合はプリロードされないので注意してください。
📦 アセット(CSS/JS)の最適化
add_action( 'wp_enqueue_scripts', 'mfp_enqueue_assets' );
function mfp_enqueue_assets() {
// 投稿ページのみ読み込む
if ( is_singular( 'post' ) ) {
wp_enqueue_style( 'mfp-post', plugin_dir_url(__FILE__) . 'css/post.css', array(), '1.0.0' );
}
// WooCommerceがアクティブなショップページのみ
if ( class_exists( 'WooCommerce' ) && is_shop() ) {
wp_enqueue_script( 'mfp-shop', plugin_dir_url(__FILE__) . 'js/shop.js', array('jquery'), '1.0.0', true );
}
}
// 管理画面でも特定ページのみ読み込む
add_action( 'admin_enqueue_scripts', 'mfp_admin_enqueue' );
function mfp_admin_enqueue( $hook ) {
// 自分の設定ページ以外では読み込まない
if ( 'settings_page_my-first-plugin' !== $hook ) return;
wp_enqueue_style( 'mfp-admin', plugin_dir_url(__FILE__) . 'css/admin.css', array(), '1.0.0' );
wp_enqueue_script( 'mfp-admin-js', plugin_dir_url(__FILE__) . 'js/admin.js', array('jquery'), '1.0.0', true );
}
⏱️ WP Cron で非同期・定期処理
重い処理をリクエスト中に実行せず、WP Cronでバックグラウンド処理することで表示速度への影響をなくせます。
// 独自スケジュール間隔を追加
add_filter( 'cron_schedules', function( $schedules ) {
$schedules['every_15_minutes'] = array(
'interval' => 15 * MINUTE_IN_SECONDS,
'display' => '15分ごと',
);
return $schedules;
} );
// 有効化時にスケジュール設定
register_activation_hook( __FILE__, function() {
if ( ! wp_next_scheduled( 'mfp_daily_cleanup' ) ) {
wp_schedule_event( time(), 'daily', 'mfp_daily_cleanup' );
}
} );
// 無効化時に必ずスケジュール削除
register_deactivation_hook( __FILE__, function() {
$ts = wp_next_scheduled( 'mfp_daily_cleanup' );
if ( $ts ) wp_unschedule_event( $ts, 'mfp_daily_cleanup' );
} );
// 処理本体
add_action( 'mfp_daily_cleanup', function() {
global $wpdb;
$wpdb->query( $wpdb->prepare(
"DELETE FROM {$wpdb->prefix}mfp_logs WHERE created_at < %s",
gmdate( 'Y-m-d H:i:s', strtotime( '-30 days' ) )
) );
} );
💡 WP Cron の注意点
WP CronはWordPressへのアクセスが発生したときに実行されます。アクセスの少ないサイトでは遅延することがあります。wp-config.phpに define('DISABLE_WP_CRON', true); を設定し、サーバーのcrontabから wp-cron.php を直接呼び出すと確実に実行できます。
✏️ 演習
📝 課題
- 外部APIからデータを取得する関数を作成し、結果を1時間キャッシュする
- 管理画面に「キャッシュをクリア」ボタンを追加する
- WP Cronで1時間ごとにキャッシュを自動更新する仕組みを実装する
- (発展)Query Monitorでキャッシュ前後のクエリ数の変化を確認する
✅ この章のチェックリスト
- Transients APIでクエリ結果をキャッシュできた
- 投稿更新時にキャッシュを無効化できた
- WP_Queryのno_found_rowsなどのオプションを使えた
- N+1問題とその回避方法を理解した
- アセットを必要なページのみに限定できた
- WP Cronで定期処理を実装し、無効化時に削除できた
🔗 関連ページ・次のステップ
📘 前提知識
- STEP 4: 機能を実装する(WP_Query基礎)
- データベース操作(クエリの仕組み)
🚀 あわせて学ぶ
- テストとデバッグ(Query Monitorで計測)
- REST API拡張(APIレスポンスのキャッシュ)
📚 補足
- 実例集(Transients APIの使用例)
- トラブルシューティング