2026年8月10日

2026年8月10日

WordPressからMailchimpのAPIへ直接登録してメルマガ購読を自動化する方法

WordPress の独自フォームから Mailchimp のオーディエンス(購読者リスト)へ登録するには、Mailchimp Marketing API の「メンバーの追加または更新」を、WordPress のサーバー側から呼ぶのが基本です。この記事では、APIキーとオーディエンスIDの準備、nonce・スパム対策・連続送信の制限を入れたフォーム処理、ダブルオプトインの扱い、よくあるエラーの読み方までを、そのまま応用できる形で説明します。

直接連携が向く場面と、プラグインで足りる場面

単に「サイトに登録フォームを置きたい」だけなら、Mailchimp for WordPress(MC4WP)のような定評のあるプラグインで十分です。フォームの作成、ダブルオプトイン、主要なフォームプラグインとの連携まで画面上で設定できます。

直接 API を呼ぶ実装が向いているのは、たとえば次のような場合です。

  • 会員登録や購入など、既存の処理の流れの中で購読登録も行いたい
  • 登録時にタグや独自項目(マージフィールド)を細かく付け分けたい
  • 余計なスクリプトやスタイルを読み込まずに、テーマのデザインに合わせた最小限のフォームにしたい

この記事のコードは、子テーマの functions.php か wp-content/mu-plugins/ 内のファイルに置く前提です。まずステージング環境と、テスト用のオーディエンスで試してください。

準備:APIキー・データセンター・オーディエンスID

Mailchimp の管理画面のアカウント設定から API キーを発行します。API キーの末尾には -us21 のようなデータセンターの識別子が付いており、API の接続先ホストはこの識別子で決まります(https://us21.api.mailchimp.com/3.0/)。オーディエンスIDは、オーディエンスの設定画面で確認できます。画面のメニュー構成や名称は変更されることがあるため、見つからない場合は Mailchimp のヘルプで「API key」「audience ID」を検索してください(2026年10月現在)。無料プランで使える機能や制限も変わることがあるので、契約中のプランで必要な機能が使えるかもあわせて確認します。

API キーはアカウント全体を操作できる強い権限を持ちます。テーマのファイルやデータベースのオプションに平文で置かず、wp-config.php の定数か、Web からアクセスできない場所の環境変数に置きます。

<?php
// wp-config.php(値はダミー)
define( 'MYSITE_MAILCHIMP_API_KEY', 'your-api-key-us21' );
define( 'MYSITE_MAILCHIMP_LIST_ID', 'your-list-id' );

Mailchimpに登録する関数を作る

Marketing API では、メンバーを「メールアドレスを小文字にしたものの MD5 ハッシュ」で識別します。このハッシュを使って PUT /lists/{list_id}/members/{subscriber_hash} を呼ぶと、未登録なら追加、登録済みなら更新という動きになり、同じ人が二度送信してもエラーになりません。

<?php
/**
 * Mailchimp のオーディエンスに追加(既存なら更新)する。
 * 新規の人はダブルオプトインの確認待ち(pending)として登録する。
 */
function mysite_mailchimp_upsert( $email, $first_name = '', $tags = array() ) {
	$api_key = MYSITE_MAILCHIMP_API_KEY;
	$dc      = substr( strrchr( $api_key, '-' ), 1 ); // 末尾のデータセンター識別子
	$hash    = md5( strtolower( $email ) );
	$base    = sprintf( 'https://%s.api.mailchimp.com/3.0/lists/%s/members/%s', $dc, MYSITE_MAILCHIMP_LIST_ID, $hash );
	$headers = array(
		'Authorization' => 'Basic ' . base64_encode( 'wp:' . $api_key ),
		'Content-Type'  => 'application/json',
	);

	$response = wp_remote_request( $base, array(
		'method'  => 'PUT',
		'timeout' => 15,
		'headers' => $headers,
		'body'    => wp_json_encode( array(
			'email_address' => $email,
			'status_if_new' => 'pending', // 新規はダブルオプトイン。既存の人の状態は変えない
			'merge_fields'  => array( 'FNAME' => $first_name ),
		) ),
	) );

	$code = wp_remote_retrieve_response_code( $response );
	if ( is_wp_error( $response ) || 200 !== $code ) {
		$body = json_decode( wp_remote_retrieve_body( $response ), true );
		return new WP_Error( 'mailchimp_error', isset( $body['title'] ) ? $body['title'] : 'request failed', array( 'status' => $code ) );
	}

	if ( $tags ) {
		wp_remote_post( $base . '/tags', array(
			'timeout' => 15,
			'headers' => $headers,
			'body'    => wp_json_encode( array(
				'tags' => array_map( function ( $t ) {
					return array( 'name' => $t, 'status' => 'active' );
				}, $tags ),
			) ),
		) );
	}
	return true;
}

ここで status ではなく status_if_new を使っているのが大事な点です。status_if_new は新規の人にだけ適用されるため、過去に配信停止した人がフォームから再送信しても、勝手に購読状態に戻すことはありません。配信停止の意思を尊重する意味でも、法令やガイドラインに沿う意味でも、この形が安全です。

pending で登録すると、Mailchimp から確認メールが送られ、本人がリンクを押した時点で購読が有効になります。第三者が他人のアドレスを勝手に登録するいたずらを防げるため、Web フォームからの登録ではダブルオプトインを基本にしてください。

認証ヘッダーのユーザー名部分(例では wp)は任意の文字列で構いません。Mailchimp は Basic 認証のパスワード部分に入った API キーで認証します。

フォームを受け取る処理:nonce・スパム対策・連続送信の制限

フォームの送信先には admin-post.php を使います。ログインしていない訪問者からの送信は admin_post_nopriv_{action}、ログイン中のユーザーからは admin_post_{action} のフックで受け取れます。

<?php
// フォーム(テンプレートやショートコードから出力)
function mysite_newsletter_form() {
	ob_start(); ?>
	<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
		<input type="hidden" name="action" value="mysite_subscribe">
		<?php wp_nonce_field( 'mysite_subscribe', 'mysite_subscribe_nonce' ); ?>
		<label>お名前 <input type="text" name="fname" maxlength="50"></label>
		<label>メールアドレス <input type="email" name="email" required></label>
		<p style="display:none"><label>空欄のまま <input type="text" name="website" tabindex="-1" autocomplete="off"></label></p>
		<label><input type="checkbox" name="consent" value="1" required> プライバシーポリシーに同意してメールマガジンを受け取る</label>
		<button type="submit">登録する</button>
	</form>
	<?php
	return ob_get_clean();
}
add_shortcode( 'mysite_newsletter', 'mysite_newsletter_form' );

// 送信の受け取り
function mysite_handle_subscribe() {
	$back = wp_get_referer() ? wp_get_referer() : home_url( '/' );

	if ( ! isset( $_POST['mysite_subscribe_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['mysite_subscribe_nonce'] ) ), 'mysite_subscribe' ) ) {
		wp_safe_redirect( add_query_arg( 'nl', 'error', $back ) );
		exit;
	}
	// ボット対策:隠し項目に値が入っていたら登録しない
	if ( ! empty( $_POST['website'] ) || empty( $_POST['consent'] ) ) {
		wp_safe_redirect( add_query_arg( 'nl', 'error', $back ) );
		exit;
	}
	// 同じ IP からの連続送信を 1 分に 3 回までに制限
	$key   = 'mysite_nl_' . md5( isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '' );
	$count = (int) get_transient( $key );
	if ( $count >= 3 ) {
		wp_safe_redirect( add_query_arg( 'nl', 'wait', $back ) );
		exit;
	}
	set_transient( $key, $count + 1, MINUTE_IN_SECONDS );

	$email = sanitize_email( wp_unslash( isset( $_POST['email'] ) ? $_POST['email'] : '' ) );
	$fname = sanitize_text_field( wp_unslash( isset( $_POST['fname'] ) ? $_POST['fname'] : '' ) );
	if ( ! is_email( $email ) ) {
		wp_safe_redirect( add_query_arg( 'nl', 'invalid', $back ) );
		exit;
	}

	$result = mysite_mailchimp_upsert( $email, $fname, array( 'wp-form' ) );
	wp_safe_redirect( add_query_arg( 'nl', is_wp_error( $result ) ? 'error' : 'pending', $back ) );
	exit;
}
add_action( 'admin_post_nopriv_mysite_subscribe', 'mysite_handle_subscribe' );
add_action( 'admin_post_mysite_subscribe', 'mysite_handle_subscribe' );

リダイレクト先のURLには結果の種類(nl=pending など)だけを付け、メールアドレスのような個人情報は付けません。表示側では $_GET['nl'] を決まった値と照合し、「確認メールを送りました。メール内のリンクを押すと登録が完了します」のような案内を出します。

ページキャッシュを使っているサイトでは、フォームを含むページがキャッシュされると nonce が古くなり、一定時間後に送信が失敗することがあります。フォームのあるページをキャッシュ対象から外すか、nonce の有効期間内にキャッシュが更新される設定にしてください。

よくあるエラーの読み方

失敗時は、Mailchimp が返す JSON の title と detail に原因が書かれています。上の関数では title を WP_Error に入れているので、まずそれを確認します。

  • 401 / API Key Invalid:キーの貼り間違いか、失効しています。データセンター識別子とホスト名が一致しているかも見ます。
  • 404 / Resource Not Found:オーディエンスIDの誤りが多い原因です。別アカウントのIDを使っていないかも確認します。
  • 400 / Invalid Resource:メールアドレスの形式やマージフィールドの値が不正です。detail や errors にどの項目かが出ます。
  • Forgotten Email Not Subscribed:Mailchimp 上で恒久的に削除(個人データの削除依頼などによる)されたアドレスは、API からは再登録できません。本人に Mailchimp の公式登録フォームから改めて登録してもらう必要があります。
  • Member Exists:POST /members で追加しようとしたときの重複エラーです。この記事のように PUT と status_if_new を使えば発生しません。

まとめ

  • フォームを置くだけならプラグインで足りる。既存処理と組み合わせたい、タグを細かく付けたい場合に直接連携を選ぶ。
  • API キーは wp-config.php の定数か環境変数に置き、データセンター識別子から接続先ホストを決める。
  • PUT /lists/{list_id}/members/{hash} と status_if_new: pending で、重複エラーを避けつつダブルオプトインにし、配信停止した人を勝手に戻さない。
  • 受け取り処理には nonce、隠し項目によるボット対策、IP 単位の連続送信制限、同意チェックを入れる。
  • エラーは返ってきた title と detail で切り分け、個人情報は URL やログに残さない。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲