WordPressで予約番号や管理コードなど、投稿に対して一意な連番を自動で付与したいケースは多くあります。この記事では、カスタム投稿ごとに採番される連番フィールドを実装する方法を紹介します。
目的と仕様
以下の仕様を満たす自動採番機能を実装します。
- 投稿タイプごとに採番を独立させる(例:event投稿なら1から、request投稿なら別のカウント)
- 投稿保存時に空のときだけ自動採番
- 投稿が削除されても番号は詰めずに保持
- 複数の投稿が同時に保存されても番号が重複しない
カスタムフィールドの作成
ACFやMeta Boxなどを使って、採番用のカスタムフィールド(例:serial_number)を作成します。ACFの場合は「テキスト」型でOKです。
functions.phpにコードを追加
以下のコードをfunctions.phpに追加してください。
functions.php:アトミックな連番採番処理
function assign_custom_post_serial_number($post_id) {
// 自動保存やリビジョンはスキップ
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (wp_is_post_revision($post_id)) return;
$post = get_post($post_id);
// 対象の投稿タイプを指定(複数対応可)
$target_post_types = ['event', 'request'];
if (!in_array($post->post_type, $target_post_types)) return;
// すでに採番済みならスキップ
$serial = get_post_meta($post_id, 'serial_number', true);
if (!empty($serial)) return;
global $wpdb;
$option_name = 'serial_counter_' . $post->post_type;
// カウンターが未作成なら0で初期化(autoload=noでキャッシュに乗せない)
$wpdb->query($wpdb->prepare(
"INSERT IGNORE INTO {$wpdb->options} (option_name, option_value, autoload) VALUES (%s, '0', 'no')",
$option_name
));
// アトミックにインクリメントし、自分の増分後の値を確実に取得する
$wpdb->query($wpdb->prepare(
"UPDATE {$wpdb->options} SET option_value = LAST_INSERT_ID(option_value + 1) WHERE option_name = %s",
$option_name
));
$new_serial = (int) $wpdb->get_var('SELECT LAST_INSERT_ID()');
// 採番を保存
update_post_meta($post_id, 'serial_number', $new_serial);
}
add_action('save_post', 'assign_custom_post_serial_number');
「最大値+1」方式は同時保存で番号が重複する
単純に「現在の最大値をクエリで取得してから+1して保存」という方式は、2つの投稿がほぼ同時に保存された場合、両方のリクエストが同じ最大値を読み取ってからそれぞれ+1してしまうため、同じ連番が重複して割り当てられる危険なパターンです。上記コードではMySQLの
単純に「現在の最大値をクエリで取得してから+1して保存」という方式は、2つの投稿がほぼ同時に保存された場合、両方のリクエストが同じ最大値を読み取ってからそれぞれ+1してしまうため、同じ連番が重複して割り当てられる危険なパターンです。上記コードではMySQLの
LAST_INSERT_ID(expr)関数を使い、UPDATE文でカウンターをインクリメントすると同時に、そのPHPリクエストの接続専用に増分後の値を記録しています。これにより、他の同時実行リクエストと衝突せず、確実に自分の増分値だけを取得できます。update_option()ではなく直接SQLを使っているのは、WordPressのオプションキャッシュ経由だと古い値を読んでしまう可能性があるためです。注意点と拡張
- 採番フィールドが編集できないようにするには、ACFで「読み取り専用」に設定するか、admin_headで非表示にするカスタマイズを行います。
- 投稿タイプが増える場合は、$target_post_typesに追加してください。
- 非常にアクセスの多いサイトでさらに厳密な管理をしたい場合は、専用のカスタムテーブルを用意する方法もあります。
よくある質問(FAQ)
Qカスタム投稿タイプに自動連番を付けるには?
Asave_postフックで、wp_optionsのカウンターをMySQLのLAST_INSERT_ID(option_value + 1)でアトミックにインクリメントし、その値をupdate_post_meta()に保存します。単純な「最大値+1」方式は同時保存時の重複リスクがあるため避けてください。
Q連番を記事スラッグに組み込むには?
A記事保存後にwp_update_post()でpost_nameを連番ベースのスラッグに更新します。ただし公開後のスラッグ変更はSEOに影響するため、初回公開時のみに処理を制限します。
Q連番がリセットされないよう確実に管理するには?
Awp_optionsをカウンターとして使いLAST_INSERT_ID()でアトミックに更新する方法で多くのケースに対応できます。非常に高頻度なアクセスがある場合は、専用のカスタムテーブルとトランザクションによる管理が推奨されます。
まとめ
カスタム投稿ごとに連番を自動付与することで、投稿管理がしやすくなり、外部連携や業務用途でも役立ちます。WordPressの投稿保存フックとカスタムフィールドを活用すれば、プラグインなしでも実装可能です。ただし「一意性」が重要な用途では、単純な最大値取得方式ではなく、アトミックなカウンター実装を使うようにしましょう。

