WordPress

【wordpress】予約投稿でスラッグに「-2」が付く原因と対処法|Custom Permalinks利用時

WordPressの標準機能である予約公開を使用し、複数記事を同時刻に公開設定した際、
事前に設定していたスラッグが勝手に変更され、「test-1-2」「test-1-3」のような連番が付与される事象が発生しました。

同じような事象の記事が見つからなかったため、記録として残しています。
本記事では、複数記事を同時公開した際に発生するこの問題の根本原因と、PHPコードによる回避策を解説します。

1.症状

スラッグをそれぞれ違うもので設定していても公開時に勝手に書き換えられ、「test-1-2」「test-1-3」という枝番が自動で付与されます。

スラッグに枝番がついている様子

2.発生環境と発生の条件

発生環境

運用要件:複数ページの同時刻での公開

CMS:WordPress 6.8.3

PHP:8.3.3

発生条件(再現性が高いパターン)

・Wordpressの予約公開機能を使用

・複数記事(固定ページ/投稿)を同時刻に公開予約

・3件以上の同時公開

・各記事でスラッグを個別に設定

・スラッグ変更にはCustom Permalinksを使用

発生手順

  1. 固定ページを追加(または投稿を追加)から新規作成
  2. 公開を「今すぐ」から未来時間に設定します。
  3. スラッグを変更するため、一度下書き保存
  4. その後スラッグを適当な文字列に変更します。
  5. 予約投稿のボタンを押して予約を確定させます。
  6. 予約が確定したらそのまま残り2つも同様の手順で作成します。
  7. 公開時間到達後、スラッグを確認します。

補足

親子階層の有無は影響しません。

また、新規作成ページに限らず
Custom Permalinks によってスラッグ変更されているページを同時刻に複数公開した場合にも
同様の書き換えが発生する可能性があります。

3.原因

本事象は、WordPressの予約公開における「同時実行処理」と、Custom Permalinks のスラッグ保存処理が競合することで発生していると考えています。

WordPressの予約投稿でスラッグに枝番がつく仕組みの図解

WordPressの予約公開は、同時刻に設定された複数の記事をcron処理によって短時間にまとめて公開します。

また、Custom Permalinks は、WordPress標準のスラッグ管理と異なり、パーマリンク情報をメタデータとして独自に保持しています。この独自処理がWP-Cronのフックと干渉しやすい点が、本件の主要な要因と考えられます。

この2つの処理が同時に実行されることで、
・スラッグの一意性チェックのタイミングのずれ
・パーマリンク情報の再保存
・既存URLの再評価
が同時に発生し、処理が競合します。

その結果、保存時の一意性チェックによって意図しない枝番(-2、-3)が付与される挙動が発生します。

なお、PHP8系では処理速度が向上しているため、これらの処理がより短時間に集中し、競合が発生しやすくなっている可能性があります。

4.対応策

効果のあった方法を3つご紹介します。

時間をずらす

1分ずつ公開時間をずらすことで、発生を確認しなくなりました。
秒数指定が可能な環境では、20秒~40秒ずらすだけでも一定の効果がありました。

メリット:手軽です。

デメリット:再発を確実に防止するものではなく、また秒数まで同じ時間に投稿することはできません。

function.phpに以下を記述

まずは公開時間をずらして改善するか確認してください。
改善しない場合のみ以下のコードを検討してください。
※function.phpを編集する際は必ずバックアップを取ってください

// 予約投稿が公開される瞬間のみ、Custom Permalinks の枝番付与を阻止
add_action('save_post', function($post_id, $post, $update) {

    // 1. 公開状態でなければスルー
    if ($post->post_status !== 'publish') return;

    // 2. 「予約投稿が今、公開された瞬間」であることをより厳密に判定
    // post_date(設定された公開日)と post_modified(現在の更新日)の差がほぼない場合、
    // または WP_START_TIMESTAMP を使って予約実行プロセスかを判定するのが確実です
    if ( !defined('DOING_CRON') ) return; // 予約投稿(Cron)経由の時だけガード

    $current = get_post_meta($post_id, 'custom_permalink', true);
    if (empty($current)) return;

    // ガード関数を定義
    $guard = function($check, $object_id, $meta_key, $meta_value) use ($post_id, $current) {
        if ($meta_key === 'custom_permalink' && $object_id == $post_id) {
            // 入力されようとしている値が、現在の値と違う(枝番がつこうとしている)ならブロック
            if ($meta_value !== $current) {
                return true; // 更新を阻止
            }
        }
        return $check;
    };

    // プラグイン(10)より早い(5)で登録
    add_filter('update_post_metadata', $guard, 5, 4);

    // 【重要】その投稿の保存処理が終わるまで(後片付けのタイミングで)ガードを外す
    add_action('clean_post_cache', function() use ($guard) {
        remove_filter('update_post_metadata', $guard, 5);
    }, 10);

}, 5, 3);

※ 予約公開(cron実行時)のみ、Custom Permalinks による
パーマリンクの再書き換えを抑制しています。

メリット:秒数指定かつ、複数の予約投稿でもスラッグが壊れません。

デメリット:function.phpに記述を追加する必要があります。

スラッグを変更しない(custom permrinksプラグインの無効化)

本事象は、Custom Permalinks によってスラッグ変更されているページでのみ確認されています。
そのため、同プラグインを使用しない、またはスラッグ変更を行わないことで、根本的な回避が可能です。

5.まとめ

本事象は、WordPressの予約公開処理とCustom Permalinks のスラッグ保存処理が同時に実行されることによる競合が主な原因と考えられます。

その他のWordPressに関する障害、エラーについての記事はこちら

TOP