📊 パフォーマンスが重要な理由

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_SECONDS60頻繁に更新されるデータ
HOUR_IN_SECONDS3,600記事一覧・人気投稿
DAY_IN_SECONDS86,400統計・ランキング
WEEK_IN_SECONDS604,800外部APIデータ
MONTH_IN_SECONDS2,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 を直接呼び出すと確実に実行できます。

✏️ 演習

📝 課題

  1. 外部APIからデータを取得する関数を作成し、結果を1時間キャッシュする
  2. 管理画面に「キャッシュをクリア」ボタンを追加する
  3. WP Cronで1時間ごとにキャッシュを自動更新する仕組みを実装する
  4. (発展)Query Monitorでキャッシュ前後のクエリ数の変化を確認する

✅ この章のチェックリスト

  • Transients APIでクエリ結果をキャッシュできた
  • 投稿更新時にキャッシュを無効化できた
  • WP_Queryのno_found_rowsなどのオプションを使えた
  • N+1問題とその回避方法を理解した
  • アセットを必要なページのみに限定できた
  • WP Cronで定期処理を実装し、無効化時に削除できた

🔗 関連ページ・次のステップ

📘 前提知識

🚀 あわせて学ぶ

📚 補足