WordPressのフォーム送信から投稿を作成し、カスタムフィールドへ追加した話

フロントエンドエンジニアをしていますが、最近は以前にも増してWordpressの実装が多くなってきました。

数をこなしているうちにWordpressに絡むベーシックなPHPは結構わかるようになっていますが
基本的には文字の処理とかループ回してとかそういうのがメインで、それ以上はいつも先人の知恵（検索）に助けられています。

今回、案件でタイトルの通りフォームの送信時にメール送信だけではなく非公開で投稿を作成してほしい（いわゆる投稿フォーム）
という依頼があり、仕様と完全に合致する情報も少なく、私にとってはとても頭を悩まされたので記録として残しておきます。

## 仕様は以下のとおり。

* フォームはプラグイン「Contact Form 7」を使用
* カスタムフィールドは「Advanced Custom Fields」で設定済み
* 投稿は、カスタム投稿
* フォームの項目は、氏名、メール等の基本的な内容に加えて、画像もあり
* フォームの項目からカテゴリーの選択も可能とする

画像を含むという点で一番苦労しました。。

### テーマ側からの投稿作成

Wordpress側で用意されている「wp_insert_post()」を使用します。
この関数の使い方自体は割と情報があったので、公式へのリンクを貼って、詳細は割愛します。
[関数リファレンス/wp insert post - WordPress Codex 日本語版](https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/wp_insert_post)

### Contact Form 7 からの送信

これは、Contact Form 7 で用意されているフック「wpcf7_before_send_mail」を使用します。
[wpcf7_before_send_mail | action | WordPress | hookr.io](http://hookr.io/actions/wpcf7_before_send_mail/)

## 最終的なソースコード

```

//----------------------------------------------
// Add post from Form
//----------------------------------------------
function wpcf7_insert_post(){
	$submission = WPCF7_Submission::get_instance();
	if($submission) {
		$data = $submission->get_posted_data();
		$uploaded_files = $submission->uploaded_files();
		$timeStamp = $submission->get_meta('timestamp');
		$time = date('Ymd_Gi',$timeStamp);
		extract($data);

		if($data['_wpcf7'] == 11) {　　//サイト内にフォームが複数あるため、IDで判別

			$post_value = array(
				'post_type' => 'custompost',
				'post_title' => $data['your-company'],
				'post_status' => 'draft'　　//下書きで作成
			);	
			$insertPost = wp_insert_post($post_value);　　//ここで投稿を作成します

			if($insertPost) {　　//無事に投稿が作成されたら、その後カスタムフィールド等の処理をします

				/* タクソノミー（カテゴリー）の設定 */
				wp_set_object_terms($insertPost,$data['category'],'keyword');

				/* テキストのみのカスタムフィールドの設定 */
				update_post_meta($insertPost, 'acf_name', $data['your-company']);
				
				/* 画像の設定 */
				if (isset($uploaded_files['your-img01'])) {
					$thumb_path = '/wp/' . str_replace($baseurl, '', $uploaded_files['your-img01']);
					$thumb_id = 
						addAttachmentFromForm($thumb_path, $uploaded_files['your-img01'], $insertPost, $time);
					update_field('acf_img', $thumb_id,  $insertPost);　//関数で生成した画像をカスタムフィールドに追加
				}
			}
		}
	}
}
add_action('wpcf7_before_send_mail', 'wpcf7_insert_post', 10, 1);

/* 画像の詳細処理については、別関数を作成しました */
function addAttachmentFromForm($filename, $file_base, $post_id, $time) {
	$layout_img_value = '';

	$filetype = wp_check_filetype( basename( $filename ), null );
	$wp_upload_dir = wp_upload_dir();　　//メディアライブラリのアップロードディレクトリを取得
	$upfile = $wp_upload_dir['url'] . '/' . $time . basename( $filename );
	$copyfile = $wp_upload_dir['path'] .'/' . $time . basename( $filename );
	copy($file_base, $copyfile);　　//コピーを作成
	$attachment = array(
		'guid'           => $upfile,
		'post_mime_type' => $filetype['type'],
		'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $upfile ) ),
		'post_content'   => '',
		'post_status'    => 'inherit'
	);
	$attach_id = wp_insert_attachment( $attachment, $copyfile, $post_id );　　//メディアライブラリにコピーした画像を追加
	require_once( ABSPATH . 'wp-admin/includes/image.php' );
	$attach_data = wp_generate_attachment_metadata( $attach_id, $copyfile );　　//画像のメタデータ作成とサムネイル等別サイズ画像生成
	wp_update_attachment_metadata( $attach_id, $attach_data );

	if($attach_id) return $attach_id;
	else return false;
}
```

### 少しだけ解説

画像の処理については、Contact Form 7 での画像送信は、あくまでもメール送信を目的としているため
一時ディレクトリにアップロードされ、メール送信が終わった際に削除されてしまいます。

そのため、今回作成した関数addAttachmentFromForm()内では、他のアップロード画像と同一のディレクトリへコピーを作成し
管理画面の「メディア」から確認可能なように追加しています。