【Contact Form 7】Form内容をオブジェクトで取得したい

## 概要

Contact Form 7（以下、CF7）のフォーム内容をHTMLではなく、オブジェクトか何かで欲しい場合があったので、プラグインのソースから色々拝借しました。
今回はサーバーサイドバリデーション実装で必要だったけど、他のシーンでも使えるかと思います。

## 先に結論
```functions.php
// CF7の投稿IDからフォームデータを返す
function my_get_wpcf7_form_values_by_id( $id ) {
  $form = wpcf7_contact_form($id);
  $res = [];
  if($form) {
    $manager = WPCF7_FormTagsManager::get_instance();
    $form = $form->prop( 'form' );
    $form = $manager->replace_with_placeholders( $form );
    $form = $manager->restore_from_placeholders( $form );
    $form = $manager->replace_all( $form );
    $res = $manager->get_scanned_tags();
  }
  return $res;
}

// inputのname値から選択項目を返す
function my_get_form_values_by_name( $name, $tags ) {
  $res = [];
  if ( !is_array($tags) ) return $res;
  foreach( $tags as $tag ) {
    if( $tag->name == $name) {
      $res = $tag->values;
    }
  }
  return $res;
}
```
### 使い方例
以下のような問い合わせフォームの中身を取得してみます。

![ss_example_form.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5943/6d1eba8e-3ee2-429a-b5cb-b1d72fa7b150.png)

```php
$contact_form_id = '0000'; // 管理画面の投稿ID
$contact_tags = my_get_wpcf7_form_values_by_id($contact_form_id);

// 入力項目のname値が「checkbox-947」の場合。
// optionの中身（問い合わせ種別）が配列で渡される
$option_values = my_get_form_values_by_name('checkbox-947', $contact_tags);
```

```php
// $contact_tagsの中身
array(6) {
  [0]=>
  object(WPCF7_FormTag)#1109 (11) {
    ["type"]=>
    string(5) "text*"
    ["basetype"]=>
    string(4) "text"
    ["raw_name"]=>
    string(9) "your-name"
    ["name"]=>
    string(9) "your-name"
    ["options"]=>
    array(1) {
      [0]=>
      string(17) "autocomplete:name"
    }
    ["raw_values"]=>
    array(0) {
    }
    ["values"]=>
    array(0) {
    }
    ["pipes"]=>
    object(WPCF7_Pipes)#1099 (1) {
      ["pipes":"WPCF7_Pipes":private]=>
      array(0) {
      }
    }
    ["labels"]=>
    array(0) {
    }
    ["attr"]=>
    string(0) ""
    ["content"]=>
    string(0) ""
  }
  [1]=>
  object(WPCF7_FormTag)#1111 (11) {
    ["type"]=>
    string(6) "email*"
    ["basetype"]=>
    string(5) "email"
    ["raw_name"]=>
    string(10) "your-email"
    ["name"]=>
    string(10) "your-email"
    ["options"]=>
    array(1) {
      [0]=>
      string(18) "autocomplete:email"
    }
    ["raw_values"]=>
    array(0) {
    }
    ["values"]=>
    array(0) {
    }
    ["pipes"]=>
    object(WPCF7_Pipes)#1110 (1) {
      ["pipes":"WPCF7_Pipes":private]=>
      array(0) {
      }
    }
    ["labels"]=>
    array(0) {
    }
    ["attr"]=>
    string(0) ""
    ["content"]=>
    string(0) ""
  }
  [2]=>
  object(WPCF7_FormTag)#1113 (11) {
    ["type"]=>
    string(5) "text*"
    ["basetype"]=>
    string(4) "text"
    ["raw_name"]=>
    string(12) "your-subject"
    ["name"]=>
    string(12) "your-subject"
    ["options"]=>
    array(0) {
    }
    ["raw_values"]=>
    array(0) {
    }
    ["values"]=>
    array(0) {
    }
    ["pipes"]=>
    object(WPCF7_Pipes)#1112 (1) {
      ["pipes":"WPCF7_Pipes":private]=>
      array(0) {
      }
    }
    ["labels"]=>
    array(0) {
    }
    ["attr"]=>
    string(0) ""
    ["content"]=>
    string(0) ""
  }
  [3]=>
  object(WPCF7_FormTag)#1118 (11) {
    ["type"]=>
    string(8) "checkbox"
    ["basetype"]=>
    string(8) "checkbox"
    ["raw_name"]=>
    string(12) "checkbox-947"
    ["name"]=>
    string(12) "checkbox-947"
    ["options"]=>
    array(1) {
      [0]=>
      string(17) "use_label_element"
    }
    ["raw_values"]=>
    array(3) {
      [0]=>
      string(11) "選択肢 1"
      [1]=>
      string(11) "選択肢 2"
      [2]=>
      string(11) "選択肢 3"
    }
    ["values"]=>
    array(3) {
      [0]=>
      string(11) "選択肢 1"
      [1]=>
      string(11) "選択肢 2"
      [2]=>
      string(11) "選択肢 3"
    }
    ["pipes"]=>
    object(WPCF7_Pipes)#1114 (1) {
      ["pipes":"WPCF7_Pipes":private]=>
      array(3) {
        [0]=>
        object(WPCF7_Pipe)#1115 (2) {
          ["before"]=>
          string(11) "選択肢 1"
          ["after"]=>
          string(11) "選択肢 1"
        }
        [1]=>
        object(WPCF7_Pipe)#1116 (2) {
          ["before"]=>
          string(11) "選択肢 2"
          ["after"]=>
          string(11) "選択肢 2"
        }
        [2]=>
        object(WPCF7_Pipe)#1117 (2) {
          ["before"]=>
          string(11) "選択肢 3"
          ["after"]=>
          string(11) "選択肢 3"
        }
      }
    }
    ["labels"]=>
    array(3) {
      [0]=>
      string(11) "選択肢 1"
      [1]=>
      string(11) "選択肢 2"
      [2]=>
      string(11) "選択肢 3"
    }
    ["attr"]=>
    string(0) ""
    ["content"]=>
    string(0) ""
  }
  [4]=>
  object(WPCF7_FormTag)#1120 (11) {
    ["type"]=>
    string(8) "textarea"
    ["basetype"]=>
    string(8) "textarea"
    ["raw_name"]=>
    string(12) "your-message"
    ["name"]=>
    string(12) "your-message"
    ["options"]=>
    array(0) {
    }
    ["raw_values"]=>
    array(0) {
    }
    ["values"]=>
    array(0) {
    }
    ["pipes"]=>
    object(WPCF7_Pipes)#1119 (1) {
      ["pipes":"WPCF7_Pipes":private]=>
      array(0) {
      }
    }
    ["labels"]=>
    array(0) {
    }
    ["attr"]=>
    string(0) ""
    ["content"]=>
    string(0) ""
  }
  [5]=>
  object(WPCF7_FormTag)#1123 (11) {
    ["type"]=>
    string(6) "submit"
    ["basetype"]=>
    string(6) "submit"
    ["raw_name"]=>
    string(0) ""
    ["name"]=>
    string(0) ""
    ["options"]=>
    array(0) {
    }
    ["raw_values"]=>
    array(1) {
      [0]=>
      string(6) "送信"
    }
    ["values"]=>
    array(1) {
      [0]=>
      string(6) "送信"
    }
    ["pipes"]=>
    object(WPCF7_Pipes)#1121 (1) {
      ["pipes":"WPCF7_Pipes":private]=>
      array(1) {
        [0]=>
        object(WPCF7_Pipe)#1122 (2) {
          ["before"]=>
          string(6) "送信"
          ["after"]=>
          string(6) "送信"
        }
      }
    }
    ["labels"]=>
    array(1) {
      [0]=>
      string(6) "送信"
    }
    ["attr"]=>
    string(0) ""
    ["content"]=>
    string(0) ""
  }
}
```

```php
// $option_valuesに「checkbox-947」を指定した場合
array(3) {
  [0]=>
  string(11) "選択肢 1"
  [1]=>
  string(11) "選択肢 2"
  [2]=>
  string(11) "選択肢 3"
}
```

## 解説

引数 `$id` は編集画面でのCF7の投稿ID。

https://100webdesign.jp/services/wordpress/wp_result/wp_result-24879/

また、バリデーションやメール送信前にフックして使う場合は、 `WPCF7_ContactForm::get_current();` が使えます。

https://wp-doctor.jp/blog/2023/05/22/contact-form-%EF%BC%97%E3%81%A7%E9%80%81%E4%BF%A1%E6%88%90%E5%8A%9F%E5%BE%8C%E3%81%AB%E9%80%81%E4%BF%A1%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97%E3%81%97%E3%81%A6%E6%A7%98%E3%80%85/

尚、ショートコードにあるidはハッシュ化された値で、投稿IDとは異なるそう。

https://contactform7.com/ja/2023/08/06/contact-form-7-58/

ショートコードのID値から取得する場合は、 `wpcf7_get_contact_form_by_hash();` を、
ショートコードのtitle値からは、`wpcf7_get_contact_form_by_title();` で。

```wp-content/plugins/contact-form-7/includes/contact-form-functions.php
function wpcf7_contact_form_tag_func( $atts, $content = null, $code = '' ) {
	    /* 略 */
        // ショートコードのid値から取得したい場合
		$contact_form = wpcf7_get_contact_form_by_hash( $id );

		if ( ! $contact_form ) {
			$contact_form = wpcf7_contact_form( $id );
		}

		if ( ! $contact_form ) {
            // ショートコードのtitle値から取得したい場合
			$contact_form = wpcf7_get_contact_form_by_title( $title );
		}
        /* 略 */
		$contact_form = wpcf7_get_contact_form_by_old_id( $id );
		/* 略 */
}
```

取得したFormデータから入力項目をオブジェクトにしてくれる、`get_scanned_tags()`を利用しました。

```wp-content/plugins/contact-form-7/includes/contact-form.php
public function replace_all_form_tags() {
    $manager = WPCF7_FormTagsManager::get_instance();
	$form = $this->prop( 'form' );

	if ( wpcf7_autop_or_not() ) {
		$form = $manager->replace_with_placeholders( $form );
		$form = wpcf7_autop( $form );
		$form = $manager->restore_from_placeholders( $form );
	}

	$form = $manager->replace_all( $form );
    // ↓入力項目のタグをObjectにし配列でまとめている
	$this->scanned_form_tags = $manager->get_scanned_tags();

	return $form;
}
```

### 実例

https://qiita.com/gips_nita/items/25cf2ffcef5409189284