Gatsby + WordPress 構成の場合におけるメールフォームは、どのように実装すればいいだろうか?
このエントリーでは、Gatsby のメールフォームから Contact Form 7(WP プラグイン)にアクセスしてメール送信する方法を共有したい。
はじめに
Netlify にホスティングするならば Netlify Forms を選ぶだろうし、それ以外では、ホスティング先に関わらず静的サイトからアクセスできるフォームサービスも、いくつか選択肢がある。その、いずれもリーズナブルで活用できるし、専用の Web API エンドポイントとアクセスキーを設定するだけ、という簡単なものだ。
ただ、メールのフォーマットに不自由さがあったり、利用回数による課金の可能性を考えると不満がないなんてことにはならない。できるならば制約を抱えたくない。そもそも Headless CMS 枠に WordPress を用いているなら、そこでどうにかしたい。
まず候補に上がるのが、Contact Form 7 だ。WordPress のメールフォーム実装で普遍的な知名度を誇る WP プラグインである。WordPress を Headless 化していることで、各種機能やデータに REST API を介してアクセスできるようになっているわけだから、Contact Form 7 も使えるに違いないというわけだ。
動作環境について
- WordPress : 5.8.2
- npm : 6.14.15
- node : 14.18.0
- gatsby : 4.0.0
- axios : 0.24.0
- react-hook-form : 7.22.1
WordPress 側の準備
まず WordPress 側の準備をしよう。
以下が、メールフォームの実装に関わる WordPress プラグイン一覧だ。適宜インストールして有効化しておいてほしい。
必要なプラグイン
- Contact Form 7 : 5.5.3
- JWT Authentication for WP-API : 1.2.6
- Members : 3.1.6
- WP-CORS : 0.2.1
Step 1
wp-config.php に定数を定義する。これは JWT Authentication for WP-API を機能させるために必要な工程だ。
まず定数 JWT_AUTH_SECRET_KEY の 'your-top-secret-key'
は、一意な文字列を代入しよう。その際、自作のランダム文字列を用いるのではなく、WordPress の認証用ユニークキージェネレータなど、なにかしらのアルゴリズムで吐き出されたものを適用するといい。
そして、定数 JWT_AUTH_CORS_ENABLE に true
をセットする。これでクロスサイトリクエストが有効になって、Gatsby 側のリクエストで CORS エラーにならなくなるはずだ。
/**
* 秘密鍵の生成に用いる文字列をセット
*/
define('JWT_AUTH_SECRET_KEY', 'your-top-secret-key');
/**
* CORS を有効にする
*/
define('JWT_AUTH_CORS_ENABLE', true);
Step 2
[設定] > [CORS] で、リクエストを容認するドメインを設定しよう。
ここにはクロスサイトリクエストを承認するドメインを設定する。開発時は *
として、すべてのサイトからアクセスできるようになる。
Step 3
[Members] > [Roles] から権限を追加しよう。
フォームサブミットの API リクエストでトークンを要するため、お問い合わせ画面に訪れたタイミングでトークン取得を行う。このとき WordPress のユーザーアカウント情報(ユーザー名, パスワード)をリクエストボディに渡すのだけれど、管理者権限のアカウント情報を記述するわけにはいかない。さもなければログインされ放題になってしまうからだ。
専用のアカウントを用意してもらいたい。その場合のアカウントの権限はメール送信のみに制限したものにしよう。
- 「Add New」ボタンをクリックする
- 「Enter role name」の入力フィールドに権限名を記入する
- Role:「Edit」ボタンをクリックして現れる入力フィールドに slug を入力する
- 「General」タブの Read 項目の [Grant] のチェックを外す
- 「コンタクトフォーム」タブの wpcf7_edit_contact_forms の [Grant] にチェックを付ける
- 「Add Role」ボタンをクリックする
Step 4
[ユーザー] > [新規追加] から新規ユーザーを追加しよう。
トークン取得にともなう API リクエストに用いるアカウントとなる。リクエストボディには、ユーザー名とパスワードを付けることになる。このときユーザー名が2バイト文字であるケースは想定していないため、避けたほうが良さそうだ。
そして User Roles をさきほど作成した権限にする。わたしの場合は、「お客様」という名称で権限を作っている。さきほどの作成で異なったものにしていれば、その権限名が表示されているはずだ。
Step 5
[お問い合わせ] からフォームを作成しよう。
Contact Form 7 をインストールすると、フォームがひとつプリセットされている。これを使うもよし新規追加するもよし、好みの手段をとってほしい。
赤線が引かれているところを見てほしい。これらは、のちほど React コンポーネントに記述することになるから記憶に留めておいてほしい。
Gatsby 側の対応
続いて、Gatsby 側の対応に移ろう。
以下は、メールフォームを役割する React コンポーネントだ。ソースコードは見渡せるように、ひとつのファイルにしているが、実際には、処理を Hook 化したり、アーキテクチャに則ってコンポーネントに切り出したり、API リクエスト手法を整えたり、適宜対応してほしい。
import React, { useEffect, useState, useCallback } from 'react';
import axios from 'axios';
import { useForm } from 'react-hook-form';
const ContactPage = () => {
// WordPress の URL
const WEBSITE_URL = 'https://example.com';
// Contact Form 7 で作ったフォーム ID
const FORM_ID = '5';
const [token, setToken] = useState('');
const { register, handleSubmit } = useForm();
/**
* フォームで submit が発生したときの処理
* - contact form 7 の機能にアクセスしてメールを送信する
* - フォームデータは、React Hook Form から提供される
*/
const onSubmit = useCallback(data => {
const bodyFormData = new FormData();
bodyFormData.set('your-name', data['your-name']);
bodyFormData.set('your-email', data['your-email']);
bodyFormData.set('your-subject', data['your-subject']);
bodyFormData.set('your-message', data['your-message']);
axios({
method: 'post',
url: `${WEBSITE_URL}/wp-json/contact-form-7/v1/contact-forms/${FORM_ID}/feedback`,
data: bodyFormData,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'multipart/form-data',
},
}).then(response => {
console.log('成功');
}).catch(error => {
console.log('失敗');
});
}, [token]);
/**
* コンポーネントがマウントされたときの処理
* JWT トークンを取得してステートに格納する
*/
useEffect(() => {
axios({
method: 'post',
url: `${WEBSITE_URL}/wp-json/jwt-auth/v1/token`,
data: {
username: [ユーザー名],
password: [パスワード],
},
headers: {
'Content-Type': 'application/json',
},
}).then(response => {
setToken(response.data.token);
}).catch(error => {
console.error(error);
});
}, []);
return (
<Layout>
<h1>お問い合わせ</h1>
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="your-name">氏名</label>
<input id="your-name" {...register('your-name', { required: true })} />
</div>
<div>
<label htmlFor="your-email">メールアドレス</label>
<input id="your-email" {...register('your-email', { required: true })} />
</div>
<div>
<label htmlFor="your-subject">題名</label>
<input id="your-subject" {...register('your-subject', { required: true })} />
</div>
<div>
<label htmlFor="your-message">メッセージ本文 (任意)</label>
<textarea
cols="30"
rows="10"
id="your-message"
{...register('your-message')}
></textarea>
</div>
<button type="submit">送信</button>
</form>
</Layout>
);
}
export default ContactPage;
簡単なプロセスを解説しよう。
Step 1
API エンドポイントとなる URL を定数に格納する。WordPress 環境の URL を適用しよう。
Contact Form 7 で作ったフォームの Post ID を定数に格納する。プリセットされたものなら 5
だと思う。
// WordPress 環境の URL
const WEBSITE_URL = 'https://example.com';
// Contact Form 7 で作ったフォームの Post ID
const FORM_ID = '5';
Step 2
コンポーネントがマウントしたら JWT トークンを取得するため API リクエストする。
リクエストボディには、ユーザー名とパスワードを適用している。当該 ID, Password は、さきほど WordPress 側の準備 で作成した専用アカウントのものを使う。
/**
* コンポーネントがマウントされたときの処理
* JWT トークンを取得してステートに格納する
*/
useEffect(() => {
axios({
method: 'post',
url: `${WEBSITE_URL}/wp-json/jwt-auth/v1/token`,
data: {
username: [ユーザー名],
password: [パスワード],
},
headers: {
'Content-Type': 'application/json',
},
}).then(response => {
setToken(response.data.token);
}).catch(error => {
console.error(error);
});
}, []);
Step 3
フォームでサブミットが発生したら、contact form 7 の機能に API リクエストする。
リクエストボディには、フォームの入力値や任意のデータを適用している。そのとき FormData オブジェクトで整形したものを使う。
リクエストヘッダーには、トークンを適用する。
/**
* フォームで submit が発生したときの処理
* - contact form 7 の機能にアクセスしてメールを送信する
* - フォームデータは、React Hook Form から提供される
*/
const onSubmit = useCallback(data => {
const bodyFormData = new FormData();
bodyFormData.set('your-name', data['your-name']);
bodyFormData.set('your-email', data['your-email']);
bodyFormData.set('your-subject', data['your-subject']);
bodyFormData.set('your-message', data['your-message']);
axios({
method: 'post',
url: `${WEBSITE_URL}/wp-json/contact-form-7/v1/contact-forms/${FORM_ID}/feedback`,
data: bodyFormData,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'multipart/form-data',
},
}).then(response => {
console.log('成功');
}).catch(error => {
console.log('失敗');
});
}, [token]);
Step 4
フォームの各種フィールドの name 属性値と Contact Form 7 で設置したフィールドの name 属性値を同じにする。
<input id="your-name" {...register('your-name', { required: true })} />
まとめ
以上が、Gatsby のメールフォームから Contact Form 7 にアクセスしてメール送信する方法の共有だった。
ひとまずメールを受信するところまでの道案内だったわけだけれど、WordPress を設置するサーバ環境によっては迷惑メールとなってしまう恐れがある。そのようなときは、WordPress プラグインで対処を図れるかもしれない。
代表的なところで「WP Mail SMTP by WPForms」だろうか。SMTP を適切に整えてくれるプラグインで広く導入されていることが分かる。迷惑メール問題に見舞われたときは、試してみても良さそうだ。
さて、ここまで述べてきたことは、情報の共有のみを目的にしている。当該内容を用いた本番運用などは、すべてあなた自身の責任のもと行ってもらいたい。