WordPress投稿時に重くなる問題を完全解決!原因特定から高速化まで

Web

「記事を投稿・更新すると管理画面がフリーズする」

「公開ボタンを押してから反映まで数分かかる」

「投稿後しばらくサイト全体が重くなる」

「下書き保存だけで30秒以上待たされる」

こんな悩みを今すぐ解決します!

WordPress投稿時の重さは、様々な処理が同時に走ることが原因です。

自動保存、リビジョン、画像処理、プラグインの処理、キャッシュクリア…これらが重なると、投稿が苦痛になるほど重くなります。

この記事では、投稿時に重くなる原因を特定し、具体的な解決方法を実践的に解説していきます!

スポンサーリンク

まず確認!投稿時のボトルネックを特定する

Query Monitorで処理時間を測定

// 1. Query Monitorプラグインをインストール
// 2. 投稿を保存・更新
// 3. 管理バーでQuery Monitorの結果を確認

// または、functions.phpに追加して手動測定
add_action('save_post', function($post_id) {
    $start_time = microtime(true);
    
    // ここで処理時間を記録
    add_action('shutdown', function() use ($start_time) {
        $execution_time = microtime(true) - $start_time;
        error_log('Post save time: ' . $execution_time . ' seconds');
    });
}, 1);

重い処理の特定チェックリスト

// functions.phpに追加して原因を特定
add_action('transition_post_status', function($new_status, $old_status, $post) {
    if ($new_status == 'publish') {
        // 各処理の時間を測定
        $timers = [];
        
        // フック処理時間を測定
        add_action('all', function($hook) use (&$timers) {
            if (strpos($hook, 'save_') === 0 || strpos($hook, 'publish_') === 0) {
                $timers[$hook] = microtime(true);
            }
        });
        
        // 結果をログに出力
        register_shutdown_function(function() use ($timers) {
            foreach ($timers as $hook => $time) {
                error_log("Hook {$hook}: " . (microtime(true) - $time) . "s");
            }
        });
    }
}, 10, 3);

投稿が重くなる12の原因と解決法

原因1:リビジョンの自動保存

症状: 編集中に頻繁に固まる、自動保存で止まる

解決方法:

// wp-config.phpに追加

// リビジョンを3つに制限
define('WP_POST_REVISIONS', 3);

// 自動保存の間隔を延長(デフォルト60秒→300秒)
define('AUTOSAVE_INTERVAL', 300);

// Ajax自動保存を無効化(極端な対策)
add_action('admin_init', function() {
    wp_deregister_script('autosave');
});

原因2:大量のカスタムフィールド

症状: カスタムフィールドが多い投稿タイプで特に遅い

解決方法:

// カスタムフィールドの保存を最適化
add_filter('update_post_metadata', function($check, $object_id, $meta_key, $meta_value, $prev_value) {
    // 変更がない場合はスキップ
    $current = get_post_meta($object_id, $meta_key, true);
    if ($current === $meta_value) {
        return true; // 更新をスキップ
    }
    return $check;
}, 10, 5);

// 不要なメタデータの自動保存を無効化
add_action('init', function() {
    remove_action('save_post', '_wp_save_post_revision', 10);
});

原因3:画像の自動生成サイズが多すぎる

症状: 画像を含む投稿で特に遅い

解決方法:

// functions.phpで不要な画像サイズを削除
add_action('init', function() {
    // デフォルトサイズを削除
    remove_image_size('medium_large');
    remove_image_size('1536x1536');
    remove_image_size('2048x2048');
});

// 画像生成を遅延実行
add_filter('intermediate_image_sizes_advanced', function($sizes, $metadata) {
    // アップロード時は最小限のサイズのみ生成
    $allowed = ['thumbnail', 'medium'];
    
    foreach ($sizes as $size => $values) {
        if (!in_array($size, $allowed)) {
            unset($sizes[$size]);
        }
    }
    
    return $sizes;
}, 10, 2);

// 必要に応じて後で生成
add_action('template_redirect', function() {
    if (is_single()) {
        $post_id = get_the_ID();
        $attachments = get_attached_media('image', $post_id);
        
        foreach ($attachments as $attachment) {
            // 必要なサイズを遅延生成
            wp_get_attachment_image_src($attachment->ID, 'large');
        }
    }
});

原因4:Pingback/Trackbackの送信

症状: 外部リンクを含む投稿で遅い

解決方法:

// wp-config.phpまたはfunctions.php

// Pingback/Trackbackを完全無効化
add_filter('xmlrpc_enabled', '__return_false');
add_filter('pings_open', '__return_false', 20, 2);

// 既存投稿のPingback無効化
add_action('init', function() {
    global $wpdb;
    $wpdb->query("UPDATE {$wpdb->posts} SET ping_status = 'closed'");
});

// XMLRPCを無効化
add_filter('xmlrpc_methods', function($methods) {
    unset($methods['pingback.ping']);
    unset($methods['pingback.extensions.getPingbacks']);
    return $methods;
});

原因5:プラグインのフック処理が重い

症状: 特定のプラグインがある時だけ遅い

解決方法:

// 重いプラグインのフックを特定
add_action('all', function($tag) {
    if (doing_action('save_post') || doing_action('wp_insert_post')) {
        $callbacks = $GLOBALS['wp_filter'][$tag] ?? [];
        foreach ($callbacks as $priority => $hooks) {
            foreach ($hooks as $hook) {
                if (is_array($hook['function'])) {
                    $class = is_object($hook['function'][0]) 
                        ? get_class($hook['function'][0]) 
                        : $hook['function'][0];
                    error_log("Hook: {$tag} - Class: {$class} - Method: {$hook['function'][1]}");
                }
            }
        }
    }
});

// 特定のプラグインのフックを投稿時のみ無効化
add_action('admin_init', function() {
    if (isset($_POST['post_ID'])) {
        // 例:重いSEOプラグインの処理を一時無効化
        remove_all_actions('save_post_seo_processing');
        
        // 後で非同期実行
        wp_schedule_single_event(time() + 60, 'run_seo_processing', [$_POST['post_ID']]);
    }
});

原因6:キャッシュプラグインの再生成

症状: 投稿後にサイト全体が重くなる

解決方法:

// キャッシュクリアを遅延実行
add_action('transition_post_status', function($new_status, $old_status, $post) {
    if ($new_status === 'publish') {
        // 即座にクリアせず、5分後に実行
        wp_schedule_single_event(time() + 300, 'delayed_cache_clear', [$post->ID]);
    }
}, 10, 3);

add_action('delayed_cache_clear', function($post_id) {
    // キャッシュプラグインのクリア関数を呼ぶ
    if (function_exists('w3tc_flush_post')) {
        w3tc_flush_post($post_id);
    }
    if (function_exists('wp_cache_clear_cache')) {
        wp_cache_clear_cache();
    }
});

// 部分的なキャッシュクリア
add_filter('clean_post_cache', function($post_id) {
    // 全体クリアではなく、該当ページのみクリア
    wp_cache_delete('post_' . $post_id, 'posts');
    wp_cache_delete('recent_posts', 'widget');
    return $post_id;
});

原因7:検索インデックスの更新

症状: 投稿数が多いサイトで顕著

解決方法:

// 検索インデックスの更新を非同期化
add_action('save_post', function($post_id) {
    // 即座に更新せず、バックグラウンドで処理
    wp_schedule_single_event(time() + 10, 'update_search_index', [$post_id]);
}, 999);

add_action('update_search_index', function($post_id) {
    // ここで検索インデックスを更新
    do_action('update_post_search_index', $post_id);
});

原因8:大量の投稿での管理画面表示

症状: 投稿一覧の表示が遅い

解決方法:

// 投稿一覧の表示数を制限
add_filter('edit_posts_per_page', function($per_page, $post_type) {
    return 20; // デフォルトは20件表示
}, 10, 2);

// 不要なカラムを非表示
add_filter('manage_posts_columns', function($columns) {
    unset($columns['comments']);
    unset($columns['tags']);
    return $columns;
});

// カスタムクエリの最適化
add_action('pre_get_posts', function($query) {
    if (is_admin() && $query->is_main_query()) {
        // 不要なメタクエリを削除
        $query->set('update_post_meta_cache', false);
        $query->set('update_post_term_cache', false);
    }
});

原因9:外部API連携の処理

症状: SNS連携や外部サービス連携時に遅い

解決方法:

// 外部API呼び出しを非同期化
add_action('publish_post', function($post_id) {
    // 即座に実行せず、キューに追加
    as_schedule_single_action(time(), 'send_to_external_api', [$post_id]);
}, 999);

add_action('send_to_external_api', function($post_id) {
    // ここで外部APIを呼び出し
    $post = get_post($post_id);
    
    // タイムアウト設定
    $response = wp_remote_post('https://api.example.com/webhook', [
        'timeout' => 5,
        'blocking' => false, // ノンブロッキング
        'body' => [
            'title' => $post->post_title,
            'url' => get_permalink($post_id)
        ]
    ]);
});

原因10:メディアライブラリの肥大化

症状: メディア選択画面が重い

解決方法:

-- 未使用の添付ファイルを確認
SELECT * FROM wp_posts 
WHERE post_type = 'attachment' 
AND post_parent = 0;

-- メタデータのクリーンアップ
DELETE FROM wp_postmeta 
WHERE post_id NOT IN (
    SELECT ID FROM wp_posts
);
// メディアライブラリの最適化
add_filter('ajax_query_attachments_args', function($query) {
    // 表示数を制限
    $query['posts_per_page'] = 20;
    
    // 不要なメタデータを取得しない
    $query['update_post_meta_cache'] = false;
    
    return $query;
});

原因11:複雑なタクソノミー処理

症状: カテゴリやタグが多い場合に遅い

解決方法:

// タクソノミーの保存を最適化
add_action('set_object_terms', function($object_id, $terms, $tt_ids, $taxonomy) {
    // キャッシュをクリア
    clean_object_term_cache($object_id, $taxonomy);
    
    // 重い処理を遅延実行
    wp_schedule_single_event(time() + 10, 'update_term_counts', [$taxonomy]);
}, 10, 4);

// ターム数の更新を最適化
add_action('update_term_counts', function($taxonomy) {
    wp_update_term_count_now(get_terms([
        'taxonomy' => $taxonomy,
        'fields' => 'ids',
        'hide_empty' => false
    ]), $taxonomy);
});

原因12:データベースのロック待ち

症状: 同時編集時に特に遅い

解決方法:

// トランザクション処理の最適化
add_filter('query', function($query) {
    global $wpdb;
    
    // INSERT/UPDATE時のロックを軽減
    if (strpos($query, 'INSERT') === 0 || strpos($query, 'UPDATE') === 0) {
        $wpdb->query('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED');
    }
    
    return $query;
});

// 自動ドラフトの削除を定期実行
if (!wp_next_scheduled('cleanup_auto_drafts')) {
    wp_schedule_event(time(), 'daily', 'cleanup_auto_drafts');
}

add_action('cleanup_auto_drafts', function() {
    global $wpdb;
    $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_status = 'auto-draft' AND DATE_SUB(NOW(), INTERVAL 7 DAY) > post_date");
});

即効性のある5つの対策

1. Heartbeat APIの調整

// functions.phpに追加
add_action('init', function() {
    wp_deregister_script('heartbeat');
});

// または間隔を延長
add_filter('heartbeat_settings', function($settings) {
    $settings['interval'] = 60; // 60秒に延長(デフォルト15秒)
    return $settings;
});

// 投稿画面のみHeartbeatを制限
add_action('admin_enqueue_scripts', function($hook) {
    if ($hook == 'post.php' || $hook == 'post-new.php') {
        wp_localize_script('heartbeat', 'heartbeatSettings', [
            'interval' => 120 // 投稿画面は2分間隔
        ]);
    }
});

2. ブロックエディタの最適化

// 不要なブロックを無効化
add_filter('allowed_block_types_all', function($allowed_blocks, $editor_context) {
    // 使用するブロックのみ許可
    return [
        'core/paragraph',
        'core/heading',
        'core/image',
        'core/list',
        'core/quote',
        'core/gallery'
    ];
}, 10, 2);

// ブロックパターンを無効化
remove_theme_support('core-block-patterns');

// ブロックディレクトリを無効化
add_filter('should_load_remote_block_patterns', '__return_false');

3. 管理画面のCSS/JS最適化

// 不要なスクリプトを削除
add_action('admin_init', function() {
    // 投稿画面で不要なスクリプトを削除
    if (isset($_GET['post'])) {
        wp_deregister_script('admin-comments');
        wp_deregister_script('admin-tags');
    }
});

// 管理画面のスタイルを軽量化
add_action('admin_print_styles', function() {
    wp_dequeue_style('wp-admin');
    wp_dequeue_style('buttons');
    wp_dequeue_style('forms');
});

4. Ajax処理の最適化

// Admin-ajaxの負荷軽減
add_action('admin_init', function() {
    // 不要なAjaxアクションを削除
    remove_action('wp_ajax_nopriv_heartbeat', 'wp_ajax_nopriv_heartbeat', 1);
    
    // カスタムAjaxエンドポイント
    add_action('wp_ajax_fast_save', function() {
        // 最小限の処理のみ
        $post_id = intval($_POST['post_id']);
        $content = wp_kses_post($_POST['content']);
        
        wp_update_post([
            'ID' => $post_id,
            'post_content' => $content
        ]);
        
        wp_die('saved');
    });
});

5. データベース接続の最適化

// wp-config.phpに追加
define('WP_ALLOW_REPAIR', true);
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', 'utf8mb4_unicode_ci');

// 永続的接続を使用
define('DB_HOST', 'localhost:3306');

// クエリキャッシュを有効化
define('WP_CACHE', true);

パフォーマンス測定と監視

投稿処理時間の測定

// functions.phpに追加
class PostPerformanceMonitor {
    private $start_time;
    private $checkpoints = [];
    
    public function __construct() {
        add_action('save_post', [$this, 'start_timing'], 1);
        add_action('save_post', [$this, 'end_timing'], 999);
        
        // 各フックポイントで測定
        $hooks = ['wp_insert_post', 'add_post_meta', 'set_post_terms'];
        foreach ($hooks as $hook) {
            add_action($hook, [$this, 'checkpoint'], 10);
        }
    }
    
    public function start_timing($post_id) {
        $this->start_time = microtime(true);
        $this->checkpoints = [];
    }
    
    public function checkpoint() {
        $hook = current_filter();
        $this->checkpoints[$hook] = microtime(true) - $this->start_time;
    }
    
    public function end_timing($post_id) {
        $total_time = microtime(true) - $this->start_time;
        
        if ($total_time > 3) { // 3秒以上かかった場合
            error_log('Slow post save detected: ' . $total_time . ' seconds');
            error_log('Checkpoints: ' . print_r($this->checkpoints, true));
            
            // 管理者に通知
            if (current_user_can('administrator')) {
                set_transient('slow_save_notice_' . get_current_user_id(), [
                    'time' => $total_time,
                    'post_id' => $post_id,
                    'checkpoints' => $this->checkpoints
                ], 60);
            }
        }
    }
}

new PostPerformanceMonitor();

// 通知を表示
add_action('admin_notices', function() {
    $notice = get_transient('slow_save_notice_' . get_current_user_id());
    if ($notice) {
        echo '<div class="notice notice-warning"><p>';
        printf('投稿の保存に%.2f秒かかりました。', $notice['time']);
        echo '</p></div>';
        delete_transient('slow_save_notice_' . get_current_user_id());
    }
});

根本的な解決策

非同期処理の実装

// Action Schedulerを使った非同期処理
// 1. Action Schedulerプラグインをインストール

// 2. 重い処理を非同期化
add_action('transition_post_status', function($new_status, $old_status, $post) {
    if ($new_status === 'publish' && $old_status !== 'publish') {
        // 重い処理をスケジュール
        as_enqueue_async_action('process_published_post', [$post->ID]);
    }
}, 10, 3);

add_action('process_published_post', function($post_id) {
    // ここで重い処理を実行
    // - サムネイル生成
    // - 外部API通知
    // - キャッシュ生成
    // - 検索インデックス更新
    
    update_post_meta($post_id, '_processing_complete', time());
});

REST APIを使った投稿

// JavaScriptで非同期保存
jQuery(document).ready(function($) {
    $('#custom-save-button').on('click', function(e) {
        e.preventDefault();
        
        const postData = {
            title: $('#title').val(),
            content: tinymce.get('content').getContent(),
            status: 'draft'
        };
        
        $.ajax({
            url: wpApiSettings.root + 'wp/v2/posts/' + postId,
            method: 'PUT',
            beforeSend: function(xhr) {
                xhr.setRequestHeader('X-WP-Nonce', wpApiSettings.nonce);
            },
            data: postData,
            success: function(response) {
                console.log('保存完了');
            },
            error: function(error) {
                console.error('保存失敗', error);
            }
        });
    });
});

まとめ – 快適な投稿環境を実現しよう!

WordPress投稿時の重さを解決する方法について、詳しく解説してきました。

重要ポイント:

  • リビジョンとHeartbeat APIの調整が最優先
  • プラグインのフック処理を最適化
  • 重い処理は非同期実行に変更
  • キャッシュクリアを遅延実行
  • データベースのロックを最小限に

即効性のある対策TOP5:

  1. リビジョン数を制限(3個まで)
  2. 自動保存間隔を延長(300秒)
  3. Heartbeat APIを調整
  4. 不要なプラグインを無効化
  5. キャッシュクリアを遅延実行

これらの対策を実施することで、投稿時のストレスから解放され、快適な執筆環境を実現できます。

まずは簡単な設定から始めて、徐々に最適化を進めていきましょう!

コメント

タイトルとURLをコピーしました