Contact Form 7 を Python + WP-CLI で 5分で自動設置する手順 (2026年版)

前回の記事 (XServer × SWELL でブログを立ち上げた初日ログ) では、Contact Form 7 を WP管理画面の UI 操作で 20分かけて設置しました。1 サイトならそれで十分です。

ただ、AI × ソロ起業の前提だと、最終的に 3〜4個の WP サイトを並行運用する ことが確定しています。同じ UI クリックを 3回も 4回もやるのは時間がもったいない。そこで、ここでは Python + WP-CLI で全工程を自動化したスクリプトを公開します。

実行は 1 コマンド、所要 5分以内です。

目次

目次

  1. なぜ Contact Form 7 を自動化するのか
  2. スクリプトが何をするか (4 ステップ)
  3. ハマりポイント 2 つ
  4. スクリプト全文
  5. 実行ログと所要時間
  6. 次のサイトに使い回すときのカスタマイズ

1. なぜ Contact Form 7 を自動化するのか

ブログ立ち上げ作業のうち、Contact Form 7 設置は地味に時間が食う部分です。前回 UI 操作で行ったときの所要は 20分でした。プラグイン検索・インストール・有効化、フォーム本体の編集 (メール送信先・本文テンプレ)、お問い合わせ固定ページ作成、メール送信テストの 4 工程。

このうち、メール送信テストを除けば すべて WP-CLI で実行可能 です。3〜4 サイトに展開する前提なら、このスクリプトを 1 個書いておけば、残りのサイトは 5分で同じ状態に揃います。

2. スクリプトが何をするか (4 ステップ)

  1. プラグイン install + activate (wp plugin install contact-form-7 --activate)
  2. CF7 フォーム本体を作成 (wp post create --post_type=wpcf7_contact_form ...)
  3. メタ値を設定 (_form, _mail, _mail_2, _messages, _localewp post meta update で投入)
  4. お問い合わせ固定ページを作成 (本文にショートコード

    エラー: コンタクトフォームが見つかりません。

    を埋める)

CF7 のフォーム定義はすべて wp_postmeta テーブルに格納されています。具体的には:

meta_key 中身
_form 文字列 フォーム本体テンプレ (label + shortcode mix)
_mail PHP serialized array 主送信先・件名・本文・追加ヘッダー
_mail_2 PHP serialized array 自動返信メール (デフォルトは無効)
_messages PHP serialized array バリデーションメッセージ 22 種
_locale 文字列 ja
_additional_settings 文字列 追加設定 (空でよい)

PHP serialized array は WP-CLI に --format=json を付ければ JSON から自動変換されます。手で serialize() 形式を組み立てる必要はありません。

3. ハマりポイント 2 つ

3-1. wp post meta update <id> <key> - の stdin マーカーは --format=json と併用できない

長い JSON 値を渡すとき、最初は WP-CLI の stdin マーカー - で楽をしようとしました:

echo '{"active":true,...}' | wp post meta update 30 _mail - --format=json

これは失敗します。エラーは Error: Invalid JSON: ---format=json を付けると、WP-CLI は値を JSON-decode しようとしますが、その前に - を「stdin から読む」ではなく「リテラル - 」として解釈してしまいます。

正解: 通常の位置引数として直接渡します。shlex.quote を通せばシェルエスケープも問題ありません。

wp("post", "meta", "update", str(form_id), "_mail",
   json.dumps(mail, ensure_ascii=False), "--format=json")

json.dumps の出力は単一行で、シングルクォート含まないので shlex.quote で囲めば bash → SSH → WP-CLI まで素直に通ります。

3-2. _form の改行を保つには JSON を経由しないこと

_form は文字列ですが、改行を含みます:

<label> 氏名
    [text* your-name autocomplete:name] </label>

これを そのまま wp post meta update <id> _form "<multi-line string>" で渡せば、改行は単一引用符の中で保持されたまま PHP 側に届きます (Python の subprocess は引数として渡すので、bash で評価されない)。--format=json を付けて JSON 文字列で渡すと、\n のリテラル化で逆に問題が出るので、ここは plain text で渡すのが正解です。

つまり、

meta フォーマット
_form plain text (生の改行を保つ)
_mail / _mail_2 / _messages --format=json で JSON 渡し
_locale / _additional_settings plain text

の使い分けが要点です。

4. スクリプト全文

scripts/setup_contact_form_7.py (一部省略、リポジトリでフル公開):

"""Set up Contact Form 7 from scratch via WP-CLI over SSH."""
import argparse
import json
import shlex
import subprocess
import sys

SSH_HOST = "xserver-aishacho"
WP_PATH = "~/ai-shacho.com/public_html"


def ssh_run(cmd: str, timeout: float = 60.0) -> str:
    full = f"cd {WP_PATH} && {cmd}"
    r = subprocess.run(
        ["ssh", SSH_HOST, full],
        capture_output=True, text=True, encoding="utf-8", timeout=timeout,
    )
    if r.returncode != 0:
        sys.exit(f"[ssh fail] {cmd}\n stderr={r.stderr}")
    return r.stdout.strip()


def wp(*args: str) -> str:
    cmd = "wp " + " ".join(shlex.quote(a) for a in args)
    return ssh_run(cmd)


def build_form_template() -> str:
    return (
        "<label> 氏名\n"
        "    [text* your-name autocomplete:name] </label>\n\n"
        "<label> メールアドレス\n"
        "    [email* your-email autocomplete:email] </label>\n\n"
        "<label> 題名\n"
        "    [text* your-subject] </label>\n\n"
        "<label> メッセージ本文 (任意)\n"
        "    [textarea your-message] </label>\n\n"
        "[submit \"送信\"]"
    )


def build_mail(recipient: str) -> dict:
    return {
        "active": True,
        "subject": "[_site_title] \"[your-subject]\"",
        "sender": f"[_site_title] <{recipient}>",
        "recipient": recipient,
        "body": (
            "差出人: [your-name] [your-email]\n"
            "題名: [your-subject]\n\n"
            "メッセージ本文:\n[your-message]\n\n"
            "-- \n本メールはあなたのウェブサイト ([_site_title] [_site_url]) "
            "のコンタクトフォームに送信があったことをお知らせするものです。"
        ),
        "additional_headers": "Reply-To: [your-email]",
        "attachments": "",
        "use_html": True,
        "exclude_blank": True,
    }


def main() -> int:
    ap = argparse.ArgumentParser()
    ap.add_argument("--form-title", default="お問い合わせ")
    ap.add_argument("--page-title", default="お問い合わせ")
    ap.add_argument("--recipient", default="contact@ai-shacho.com")
    args = ap.parse_args()

    # 1. plugin install + activate (idempotent)
    wp("plugin", "install", "contact-form-7", "--activate")

    # 2. create CF7 form post
    form_id = int(wp(
        "post", "create",
        "--post_type=wpcf7_contact_form",
        f"--post_title={args.form_title}",
        "--post_status=publish",
        "--porcelain",
    ))

    # 3. set meta values
    wp("post", "meta", "update", str(form_id), "_form", build_form_template())
    wp("post", "meta", "update", str(form_id), "_mail",
       json.dumps(build_mail(args.recipient), ensure_ascii=False),
       "--format=json")
    # _mail_2 と _messages も同様 (省略・リポジトリ参照)
    wp("post", "meta", "update", str(form_id), "_locale", "ja")

    # 4. create page with shortcode
    body = (
        "ご質問・お仕事のご依頼はこちらからお願いします。\n\n"
        f'

エラー: コンタクトフォームが見つかりません。

\n' ) page_id = int(wp( "post", "create", "--post_type=page", f"--post_title={args.page_title}", f"--post_content={body}", "--post_status=publish", "--porcelain", )) site_url = wp("option", "get", "home") print(f"[OK] form_id={form_id} page_id={page_id}") print(f" URL: {site_url}/?page_id={page_id}") return 0 if __name__ == "__main__": sys.exit(main())

_mail_2 (自動返信メール) と _messages (バリデーションメッセージ 22種) は紙面の都合で省略しました。フル版はリポジトリの scripts/setup_contact_form_7.py を参照してください。

5. 実行ログと所要時間

実行コマンド:

python scripts/setup_contact_form_7.py \
    --form-title "お問い合わせ" \
    --page-title "お問い合わせ" \
    --recipient contact@ai-shacho.com

実行ログ:

[1/4] install + activate contact-form-7 (idempotent)
[2/4] create CF7 form: お問い合わせ
[3/4] set meta on form_id=32
[4/4] create or update page: お問い合わせ

[OK] form_id=32 page_id=33
     URL: https://ai-shacho.com/?page_id=33

各ステップの所要時間:

ステップ 所要
プラグイン install + activate 約 30秒
フォーム post + メタ 6 件投入 約 1分
お問い合わせ固定ページ作成 約 10秒
メール送信テスト (UI で 1 回) 約 2分

合計 約 4分。残り 1分はメール届確認の待ち時間です。前回の UI 手作業 20分から 80% 短縮できました。

レンダリング確認:

Invoke-WebRequest "https://ai-shacho.com/?page_id=33" `
    | Select-Object -ExpandProperty Content `
    | Select-String -Pattern 'wpcf7-form|your-name|your-email'

wpcf7-form クラス・your-nameyour-email フィールドがすべてレンダリング側に出ていれば成功です。

6. 次のサイトに使い回すときのカスタマイズ

本記事のスクリプトは XServer (エックスサーバー) 上の WordPress 前提で書いています。SSH 接続が標準で使えてWP-CLI が /usr/bin/wp に入っているため、追加セットアップなしでこのスクリプトが動きます。

スクリプトのトップに 2 つの定数があります:

SSH_HOST = "xserver-aishacho"
WP_PATH = "~/ai-shacho.com/public_html"

新サイトでは ~/.ssh/config に新サイト用 Host を追加し、SSH_HOSTWP_PATH を書き換えれば動きます。実引数 --recipient でメール送信先を切り替えれば、フォームの _mail.recipient が新ドメインの問い合わせ用アドレスになります。

CF7 のフォーム定義 (build_form_template) や送信本文 (build_mail) はサイトごとに変えたい場合があるかもしれません。その場合は YAML 設定ファイルから読み込む形に拡張すると、サイト名 + recipient のペアを並べておくだけで全サイトに同じ仕様を投入できます。

まとめ

WP-CLI と Python の組み合わせは、Contact Form 7 のような「UI で 20分かかるが裏側は単純なメタ値更新」系の作業と相性が良いです。

ハマりポイントは「- stdin マーカーが --format=json と併用不可」と「_form は plain text で渡す」の 2 点だけ把握しておけば、CF7 以外の WordPress プラグインも同じパターンで自動化できます。


次に読むおすすめ

CTA

X 会社アカウントをフォロー: @ai_shacho_jp — 日々の自動化スクリプト・実装ログを投稿しています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

目次