【WordPress】特定のカスタムフィールドが空なら下書きに戻す自動処理の実装

【WordPress】特定のカスタムフィールドが空なら下書きに戻す自動処理の実装 WordPress

WordPressでは、入力必須のカスタムフィールドが空のままでも投稿を公開できてしまうため、重要な情報の入力漏れを防ぐために自動で「下書き」に戻す処理を入れたいケースがあります。

この記事では、特定のカスタムフィールドが未入力のまま保存された場合に、投稿ステータスを自動で「draft(下書き)」に変更する方法を紹介します。

スポンサーリンク

使用するフック:wp_after_insert_post

投稿が保存されたタイミングでカスタム処理を実行するために、wp_after_insert_postアクションを利用します。

save_postではACFとのフック優先度が競合する
ACF公式サポートフォーラムで確認したところ、ACF自身もカスタムフィールドの保存にsave_post優先度10を使用しており、「両方とも優先度10だとどちらが先に実行されるかは運任せ」と説明されています。save_postにデフォルト優先度で登録すると、プラグインの読み込み順によってはACFによるフィールド保存より先に実行され、get_post_meta()がまだ保存されていない古い値を読んでしまう可能性があります。WordPress 5.6で追加されたwp_after_insert_postフックは、投稿本体・ターム・メタデータすべてが確定した後に一貫して発火するよう設計されているため、こちらを使うことでこの競合を回避できます。

カスタムフィールド未入力時に自動で下書きに戻すコード例

以下は、カスタムフィールドrequired_fieldが空の場合に投稿を下書きへ変更するサンプルコードです。

functions.php:未入力時に下書きへ戻す
function revert_to_draft_if_field_empty($post_id, $post, $update, $post_before) {
  // 自動保存、リビジョン、ゴミ箱、Ajaxは除外
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
  if (wp_is_post_revision($post_id)) return;
  if (get_post_status($post_id) === 'trash') return;
  if (defined('DOING_AJAX') && DOING_AJAX) return;

  // 投稿タイプを限定(例:post)
  if (get_post_type($post_id) !== 'post') return;

  // 対象カスタムフィールドの値を取得
  $value = get_post_meta($post_id, 'required_field', true);

  // 未入力なら下書きに変更('0'のような正当な値を誤判定しないよう厳密比較)
  if ($value === '') {
    // 一時的にフックを解除して再帰防止
    remove_action('wp_after_insert_post', 'revert_to_draft_if_field_empty');

    // 投稿ステータスを下書きに更新
    wp_update_post(array(
      'ID'          => $post_id,
      'post_status' => 'draft',
    ));

    // 再度フックを有効化
    add_action('wp_after_insert_post', 'revert_to_draft_if_field_empty', 10, 4);
  }
}
add_action('wp_after_insert_post', 'revert_to_draft_if_field_empty', 10, 4);

投稿タイプを指定する方法

カスタム投稿タイプ(例:product)にだけ適用したい場合は、以下のように変更します。

投稿タイプの条件分岐
if (get_post_type($post_id) !== 'product') return;

この条件を使えば、他の投稿タイプには影響を与えず、目的の投稿タイプだけを制御できます。

複数のフィールドを対象にする方法

以下のように配列で複数のフィールドを指定し、どれか一つでも空なら下書きにする処理も可能です。

複数フィールドのチェック
$required_fields = array('price', 'stock', 'sku');
foreach ($required_fields as $key) {
  // '0'(在庫切れ・無料等)は正当な値のため、empty()ではなく厳密比較で判定する
  if (get_post_meta($post_id, $key, true) === '') {
    // 下書きに戻す処理
  }
}
empty()は’0’も空と判定してしまう
price(価格)やstock(在庫数)のように0が正当な値になりうるフィールドをempty($value)で判定すると、PHPのempty()は文字列'0'も空として扱うため、在庫0や価格0円を正しく入力したのに「未入力」と誤判定されて下書きに戻されてしまいます。$value === ''のように厳密比較を使いましょう。

ユーザーへの注意喚起メッセージを表示するには

保存後に「下書きに戻された」理由を管理者に伝えたい場合、admin_noticesフックを使って通知を表示することも可能です。リダイレクトURLへのクエリ付与にはWordPress標準のredirect_post_locationフィルターを使います。

functions.php:注意喚起メッセージの表示
function show_required_field_notice() {
  if (isset($_GET['missing_field'])) {
    echo '<div class="notice notice-error"><p>必須項目が未入力のため、下書きに戻しました。</p></div>';
  }
}
add_action('admin_notices', 'show_required_field_notice');

// 投稿保存後のリダイレクトURLにクエリを付与する(標準の仕組みを使う)
function add_missing_field_query_arg($location, $post_id) {
  $value = get_post_meta($post_id, 'required_field', true);
  if ($value === '') {
    $location = add_query_arg('missing_field', '1', $location);
  }
  return $location;
}
add_filter('redirect_post_location', 'add_missing_field_query_arg', 10, 2);

よくある質問(FAQ)

Q必須カスタムフィールドが未設定の場合に公開を防ぐ実装は?
Awp_after_insert_postフックでフィールドの値をチェックし、未設定の場合はwp_update_post(array(‘ID’ => $post_id, ‘post_status’ => ‘draft’))で下書きに戻します。管理画面にエラーメッセージをadmin_noticesで表示することも重要です。
QGutenbergエディターで保存時にバリデーションエラーを表示するには?
Arest_pre_insert_postフィルターでREST API経由の保存をフックし、バリデーション失敗時にWP_Errorを返します。Gutenbergはエラーレスポンスをエディター上に表示します。
Qカスタムフィールドの必須チェックをクライアントサイドでも行うには?
A管理画面にJavaScriptを読み込み、Gutenbergのsave完了前にイベントをフックしてフィールドの値を確認します。ただしサーバーサイドでの検証も必須です(クライアント検証のみでは迂回可能)。

まとめ

WordPressのwp_after_insert_postフックを使うことで、カスタムフィールドの入力チェックとステータス制御を自動化できます。

これにより、必須項目の入力漏れを防ぎ、運用の品質を保つことができます。ACFなどのUIと併用すれば、ユーザーにやさしいフォーム設計と自動処理を両立することも可能です。値が0になりうるフィールドではempty()を避け、厳密比較を使うことも忘れずに、効率的でミスの少ない記事管理環境を構築してください。