Contact Form 7の入力から、ログインした投稿権限のあるユーザー自身の下書きを作成する例です。
対象はタイトルとプレーンテキストの本文で、画像・カテゴリー・タグは保存後にWordPressの編集画面から設定します。
旧稿の匿名投稿と画像コピーのコードは撤回しました。
旧画像処理は同名ファイルを上書きし得るうえ、投稿権限・実際の画像形式・保存失敗を十分に確認していませんでした。
変更前に旧コードを停止する
検証環境でデータベースとスニペットをバックアップし、旧稿のcf7_create_post、wpcf7_insert_image_post、cf7_create_post_with_thumbnailと、そのフック登録を停止します。
旧画像用のadd_attachment_from_form・cf7_add_attachmentも、この用途で追加したものか確認して取り除きます。
新旧のフックを同時に有効にすると、1回の送信で別々の記事を作成する可能性があります。
Contact Form 7のフォームを設定する
専用フォームの「フォーム」欄に次の内容を設定します。
<label>タイトル(200文字以内)
[text* post-title maxlength:200]
</label>
<label>本文(20000文字以内・HTMLは使用しない)
[textarea* post-content maxlength:20000]
</label>
[submit "下書きを保存"]「その他の設定」欄には次の1行を入れます。
subscribers_only: trueこの設定でフォームをログインユーザー向けにし、PHP側ではさらにedit_posts権限を確認して購読者からの保存を拒否します。
「メッセージ」欄の送信成功メッセージは「下書きを保存しました。」へ変更します。
この例は対象フォームのメール送信を省略するため、メール送信成功を保存成功の根拠にはしません。
フォームを載せるページを共有キャッシュの対象から外し、ログイン後に読み込み直してください。
下書き保存用のPHPを追加する
PHPのmbstring拡張を利用できる環境で、子テーマのfunctions.phpかCode SnippetsのPHPスニペットへ追加し、waza_draft_form_id()の97を専用フォームの実際のIDへ変更します。
既存のPHPファイル内やCode Snippetsへ貼る場合、先頭の<?phpは追加しません。
// 対象のCF7フォームIDへ変更する。
function waza_draft_form_id() { return 97; }
// ログイン中のフォームにREST用nonceを出力させる。
add_filter('wpcf7_verify_nonce', function ($active, $form) {
return (int) $form->id() === waza_draft_form_id() ? true : $active;
}, 10, 2);
add_action('wpcf7_before_send_mail', function ($form, &$abort, $submission) {
if ((int) $form->id() !== waza_draft_form_id() || $abort) return;
$nonce = $_POST['_wpnonce'] ?? '';
if (!current_user_can('edit_posts') || !is_string($nonce)
|| !wp_verify_nonce(wp_unslash($nonce), 'wp_rest')) {
$abort = true;
$submission->set_response('ログイン状態と投稿権限を確認して、フォームを読み込み直してください。');
return;
}
$title = $submission->get_posted_data('post-title');
$body = $submission->get_posted_data('post-content');
if (!is_string($title) || !is_string($body)) {
$abort = true;
$submission->set_response('入力形式を確認してください。');
return;
}
$title = sanitize_text_field($title);
$body = sanitize_textarea_field($body);
if ($title === '' || $body === '' || mb_strlen($title) > 200 || mb_strlen($body) > 20000) {
$abort = true;
$submission->set_response('タイトルは200文字、本文は20000文字以内で入力してください。');
return;
}
$content = '<!-- wp:paragraph --><p>' . nl2br(esc_html($body)) . '</p><!-- /wp:paragraph -->';
$id = wp_insert_post(wp_slash([
'post_type' => 'post', 'post_status' => 'draft',
'post_title' => $title, 'post_content' => $content,
'post_author' => get_current_user_id(),
]), true);
if (is_wp_error($id) || !$id) {
$abort = true;
$submission->set_response('下書きを保存できませんでした。管理者へ確認してください。');
}
}, 10, 3);
// このフォームではメール送信を行わず、下書き保存を結果とする。
add_filter('wpcf7_skip_mail', function ($skip, $form) {
return (int) $form->id() === waza_draft_form_id() ? true : $skip;
}, 10, 2);
投稿者ID・公開状態は送信値から受け取らず、現在のユーザーとdraftに固定しています。
権限やnonceが不正な場合、配列入力・空の入力・上限超過がある場合、保存が失敗した場合は処理を中止します。
送信結果から確認先を選ぶ
| 送信後の状態 | 次に確認する場所・操作 |
|---|---|
| 「下書きを保存しました。」 | 投稿一覧で本人の下書きが1件増えたか確認し、タイトル・本文を照合する |
| ログイン状態と投稿権限の案内 | 投稿権限と対象フォームIDを確認。ログイン後にフォームページを読み込み直す |
| 入力形式・文字数の案内 | タイトル200文字・本文20000文字以内の文字列を入力する。PHPは配列入力を受け付けない |
| 下書きを保存できない案内 | 再送する前に投稿一覧を確認し、管理者が保存処理とログを調べる |
| 応答が分からない・もう一度送信したい | 投稿一覧で同じ内容の下書きを確認する。再送は別の下書きを作る |
確認は「フォームの応答」「投稿一覧」「保存内容」の順に行います。この例は、送信後に作られた投稿IDをフォームへ返す処理を持ちません。投稿一覧で送信時刻・投稿者・タイトルを照合して対象を特定します。
まず検証環境で短いタイトルと2行の本文を送信し、本人の下書きだけが増えるかを確認します。次に匿名・購読者・空欄で保存されないか確認し、通常のお問い合わせフォームには下書き保存の処理やメール省略が適用されないことも比較してください。
共有キャッシュから古いフォームが表示された疑いがある場合は、対象ページの除外設定を確認して読み込み直します。エラーが出るたびにキャッシュ設定全体を変更するのではなく、投稿権限・フォームID・保存済み下書きの有無を先に切り分けます。
保存後の確認と戻し方
投稿権限のあるユーザーでタイトルと本文を送信し、管理画面の「投稿」から下書きが1件作られたことを確認します。
投稿者・タイトル・本文を照合し、必要なカテゴリー・タグ・アイキャッチ画像を編集画面で設定してから公開します。
この例には送信ごとに1回だけ保存する保証がなく、再送すると別の下書きが作られます。
結果が不明なときは再送する前に投稿一覧を確認してください。
フォームからの画像取り込みと、同時送信を含む重複防止が必要な運用は、この例の対象外です。
戻す場合は今回のPHPスニペットを停止し、フォーム設定とメッセージを変更前へ戻します。
スニペットの停止だけでは作成済みの下書きは戻らないため、管理画面で対象を確認して整理します。
実HTTPで確認した送信結果
| 送信条件 | HTTP・フォーム応答 | 投稿一覧の確認 |
|---|---|---|
| 投稿権限のあるユーザー・有効nonce | HTTP 200、mail_sent | 本人の下書きが1件増える |
| 無効nonce | HTTP 403、rest_cookie_invalid_nonce | 下書きは増えない |
| 匿名送信 | HTTP 200、error | 下書きは増えない |
HTTP 200だけで保存成功と判断せず、CF7の応答と投稿一覧を照合します。
この専用フォームはメールを省略するため、mail_sentは受信メールの到達を意味しません。
日本語と改行、バックスラッシュを含む本文を保存でき、入力したscriptタグが実行用HTMLとして残らないことを確認しました。
フォームIDは検証用へ変更しており、本番に検証データは送信していません。
確認した範囲
2026年10月2日、WordPress 7.1.2とContact Form 7 6.1.7の隔離環境で、実プラグインの送信処理から下書き保存を確認しました。
管理者・投稿者の保存、匿名・購読者・不正nonce・配列入力・空欄の拒否を検証しています。
2026年10月3日には、通常のWordPressログインで取得したCookieと、フォームが発行したnonceを使い、CF7のREST送信から投稿者本人の下書きを1件保存できることも確認しました。
ブラウザーでのフォーム操作、スマホ表示、キャッシュとの組み合わせは未検証です。
フォームの設置はContact Form 7の公式手順、保存処理はWordPressのwp_insert_post()仕様も確認してください。



