Contact Form 7をREST API 経由でエラー415になった

React からREST API経由でContact Form 7 を利用していたのですが、エラーで415が返ってくるようになりました。

415は、以下のエラーとのこと。

HTTP 415 Unsupported Media Type クライアントエラーレスポンスコードは、ペイロードフォーマットがサポートされていないフォーマットであるため、サーバーがリクエストの受け入れを拒否することを示します

MDN

原因は何だったかと言うとContact Form 7 5.6に「REST API: フィードバック作成リクエストの Content-Type ヘッダーが multipart/form-data ではない場合に 415 HTTP エラーステータスを応答する。」というアップデートがあった為でした。

今までは、Content-Typeは、application/x-www-form-urlencodedとなっていました。ということで、修正後のコードがこちら。

  const handleSubmit = () => {

    const endpoint = process.env.REACT_APP_endpoint_contact
    const params = new FormData()
    params.append('yourName', name)
    params.append('yourEmail', email)
    params.append('yourMessage', message)

    const axiosConfig = {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    }

    axios
      .post(endpoint, params, axiosConfig)
      .then((res) => {
        setResMessage(res.data.message)
        setResStyle(res.data.status)

        if (res.data.status === 'mail_sent') {
          setName('')
          setEmail('')
          setMessage('')
        }
      })
      .catch((error) => {
        console.error(error)
      })
  }

参考ページ

https://reiji1020.hatenablog.com/entry/2018/12/31/113202

cypress入門

Cypressとは

Cypress はフロントエンドのE2E(End to End)テストツール

E2Eテストとは

  • E2E(End to End)は、端から端までの意味。
  • システム全体を通して正しく動くかを検証するためのテスト。
  • 人間が仕様書通りに動くか確認するテストも含まれる。

人力でのテストの課題

  • 工数がかかる。
  • 網羅性に欠ける

=> Cypressで自動化!コスト削減&品質向上!

E2E以外もテスト可能

Cypress v10リリース(2022-06-01)

Cypress v10では、cypressを立ち上げた時点で以下の2つから選択できる

  • E2E
  • コンポーネント

※ コンポーネントテストはのCypress v10からベータ版に昇格

cypressの特徴

特徴その1:mocha + chai ベースでテストを書くことができる

mocha.js

テスティングフレームワーク

  • テストの実行プログラムの作成
  • テスト結果の判定
  • 集計など

chai.js

アサーションライブラリー

プログラムの前提として満たされるべき条件を記述し、実行時にそれが満せてない場合にエラーや例外を発生させる機能

例)
テスト:AページでBボタンをクリックしてCコンポーネントが表示されること
アサーション:Cコンポーネントが表示されるかの判定

特徴その2:jQueryライクにかける

Cypressは、jQueryの強力なセレクタエンジンを活用している。

cy.get("#main-content")
.find(".article")
.children('a[href^="/static"]')
.click();

cypressインストール使うまで

$ yarn add -D cypress

package.jsonにCypressを起動するためのスクリプトを追加

"scripts": {
  //追加
  "start": "cypress open"
}
$ yarn start

ディレクトリ構成

cypress
– fixtures
テストで使用する静的データを管理するディレクトリ(json、image など)
– integration
テストを管理するディレクトリ
– suport
カスタムコマンド

※ v10と相違点あり

scssのディレクトリ構成

ディレクトリと用途

scss
global 必要箇所で@use "../global" as g;して使う
  ┃  ┣ _index.scss
  ┃  ┣ _variable.scss
┗ _mixin.scssfoundation 共通のデフォルト設定
  ┃  ┣ _index.scss
  ┃  ┣ _setting.scss コメント
  ┃  ┣ _sanitize.scss リセットスタイル
┗ _base.scss 共通のスタイル
layout 共通のページのレイアウト
  ┃  ┣ _index.scss
  ┃  ┣ _container.scss
  ┃  ┣ _header.scss
┗ _footer.scss  ┃
  ┣ component 共通モジュール
  ┃  ┣ _index.scss
  ┃  ┣ _button.scss
  ┃  ┗ _link.scss …
  ┃
  ┣ project ページ毎に固有のモジュール(他のページで使わない)
  ┃  ┣ top
┃  ┣ _index.scss
  ┃  ┃  ┣ _card.scss
  ┃  ┃  ┗ _profile.scss …
  ┃  ┃
  ┃  ページ名 …
  ┃
  utility helper的にさくっと使えるもの
  ┃  ┣ _index.scss
  ┃  ┣ _display.scss
  ┃  ┣ _margin.scss
  ┃  ┣ _padding.scss
  ┗ _typography.scss
  ┗ style.scss

FLOCSSのディレクトリ構成を参考にしました。
階層を深くしたくなかったので、component project utility は、object ディレクトリを使わずにroot直下に置きました。

また、object という読み込み様のディレクトリを作成しています。
変数など使いたいファイルで@use "../global" as g;して、globalを読み込んで、g.$variable@include g.mq(){}といった形で利用可能です。

Sassの@importが廃止

Sassの@importが2022年に廃止されます。来たる日に向けて、@importを@useに置き換えました。

EasySassだと@use, @forwordが使えない

トランスパイルには、VSCodeのExtentionsのEasySassを使っていたのですが、どうやらEasySassは、Node製ではないようで、うまくトランスパイルされません。
代わりに「DartJS Sass Compiler and Sass Watcher」というExtentionsに乗り換えました。

パーシャル編集時にも、自動でトランスパイルさせる

このままでは、パーシャル以外のscssファイルを保存した時にしかトランスパイルされません。実作業では、パーシャルのファイルを編集していくことになるので、パーシャルのファイルが保存された時にトランスパイルしたいです。
これは、以下のブログに記載されていた設定で実現できました。

【VSCode】Dart Sassが使える拡張機能 – DartJS Sass Compiler and Sass Watcherの使い方

試しにSass Watcherを使わずに作業したら、パーシャルファイルの保存時に、トランスパイルされました。(追記:2022.01.20)

dockerでWordPressの開発環境を構築したメモ

勉強がてら既存のWordPressサイトのローカル環境を構築したのでメモ。

条件

  • Docker Desktopインストール済み
  • 管理しているWordPressサイトがある

作業の流れ

  1. docker-compose.ymlの作成
  2. ボリュームの作成
    1. テーマ
    2. プラグイン
    3. 画像
  3. データベース初期値の設定
    1. sqlファイルの用意
    2. エクスポートしたSQLファイルを取り込む
    3. テーブル接頭辞の設定

最終的なファイル構成

mySite
 ┣ docker-compose.yml
 ┣ plugins
 ┃ ┣ plugin A
 ┃ ┣ plugin B
 ┃ plugin C
 ┣ themes
 ┃ ┣ mytheme
 ┃ ┗ mytheme-child
 ┣ uploads
 ┃ ┣ 2020
 ┃ ┗ 2021
 ┗ db_data
   ┗ initdb
     ┗ exported_data.sql

docker-composeのコマンド

コンテナの起動 docker-compose up -d
  • -d オプション:コンテナをバックグラウンドで起動させておくことが出来る
コンテナの再起動 docker-compose up -d
  • 更新したdocker-compose.ymlを反映させられる
コンテナの停止 docker-compose stop
  • コンテナは削除されずに残る
  • 再び起動してもDBのデータはそのまま保持される
停止したコンテナの起動 docker-compose start
コンテナの削除 docker-compose down
  • コンテナは削除される
  • 再び起動しても、以前のDBのデータは削除される(ボリューム{後述}を利用すれば削除されない)

docker-compose.ymlの作成

Docker Compose 概要

Compose とは、複数のコンテナを定義し実行する Docker アプリケーションのためのツールです。Compose においては YAML ファイルを使ってアプリケーションサービスの設定を行います。コマンドを1つ実行するだけで、設定内容に基づいたアプリケーションサービスの生成、起動を行います。

https://docs.docker.jp/compose/overview.html

docker-compose.ymlは、公式のものを編集して作成していきます。https://docs.docker.com/samples/wordpress/

上記サイトにあるコードをコピーして、mySiteディレクトリにdocker-compose.ymlを作成します。

version: "3.9"
    
services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    volumes:
      - wordpress_data:/var/www/html
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
volumes:
  db_data: {}
  wordpress_data: {}

ターミナルでmySiteディレクトリ に移動して、次のコマンドを実行しWordPressの環境を立ち上げます。

docker-compose up -d

http://localhost:8000/にアクセスするとWordPressの初期設定画面が表示されます。
画面に従って、WordPressの初期設定を完了させます。

ボリュームの作成

ボリュームとは、Docker コンテナーにおいて生成され利用されるデータを、永続的に保持する目的で利用される仕組みです。

https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/

今回、既存サイトのローカル環境の構築ということなので、すでにWordPressで使っているテーマ、プラグイン、DBのデータをこのボリュームを使ってコンテナにマウントすることで、コンテナからアクセスできるようになります。

テーマ、プラグイン、画像のボリューム作成

docker-compose.ymlファイルの19行目のvolumesに以下を追加

      - ./themes:/var/www/html/wp-content/themes
      - ./plugins:/var/www/html/wp-content/plugins
      - ./uploads:/var/www/html/wp-content/uploads

mySiteディレクトリ の直下にthemes, pulugins, uploadsディレクトリを作成し、それぞれに既存サイトで使っているテーマ、プラグイン、画像を配置します。

コマンドラインで、次のコマンドを実行して、コンテナを再起動します。
編集したdocker-compose.ymlファイルの内容を取り込みます。

docker-compose up -d

WordPressの管理画面からテーマの編集ページにアクセスすると、themesディレクトリに配置したテーマが、プラグインの編集ページにアクセスすると、pluginsディレクトリに配置したプラグインが表示されます。
この時点で、画像もマウントされてますので、次に説明するデータベースのデータを読み込めば、表示されます。

データベース初期値の設定

既存サイトで投稿された記事、ページ、プラグインの設定などのデータを初期値としてmySQLコンテナに取り込みます。

新しいインスタンスの初期化

コンテナが初めて起動されると、指定された名前の新しいデータベースが作成され、提供された設定変数で初期化されます。さらに、/docker-entrypoint-initdb.d にある拡張子 .sh, .sql, .sql.gz のファイルがアルファベット順で実行されます。このディレクトリにSQLダンプをマウントすることで、簡単にmysqlサービスにデータを取り込むことができ、カスタムイメージにデータを提供することができます。SQLファイルはデフォルトでMYSQL_DATABASE変数で指定されたデータベースにインポートされます。

https://hub.docker.com/_/mysql/

sqlファイルの用意

まずは、既存サイトのデータをエクスポートします。今回は、phpMyAdminからエクスポートします。次のページを参考にエクスポートしてください。
WordPress Codex

エクスポート設定

  • エクスポート方法:「詳細」を選択
  • 生成オプション:「DROP TABLE / VIEW / PROCEDURE / FUNCTION / EVENT / TRIGGER コマンドを追加する」オプションを選択

siteurl, homeの編集

エクスポートしたファイルのままだとoptionsテーブルのsiteurlとhomeが既存サイトのURLになっているので、サイトが表示されませんので、修正します。

エクスポートしたファイルをエディターで開いて、’siteurl’や’home’でファイル内を検索すると以下のような箇所がありますので、urlをhttp://localhost:8000に置き換えます。

(1, 'siteurl', 'https://hogehoge.jp/', 'yes'),
(37, 'home', 'https://hogehoge.jp/', 'yes'),

これで、SQLファイルの用意ができました。

エクスポートしたSQLファイルを取り込む

SQLファイルをSQLコンテナに取り込むには、/docker-entrypoint-initdb.dにSQLファイルをマウントします。

docker-compose.ymlファイルの6行目にあるvolumesに以下を追加します。

      - ./db_data/initdb:/docker-entrypoint-initdb.d

mySiteディレクトリ の直下にdb_dataディレクトリを作成し、用意したsqlファイルを配置します。

コマンドラインで次のコマンドを実行して再起動させます。

docker-compose down
docker volume rm $(docker volume ls -qf dangling=true)
docker-compose up -d

docker-compose up -dだけではなく、docker volume rm $(docker volume ls -qf dangling=true)で、ボリュームを一旦削除しています。そうしないと更新まえのボリュームを読み込んでしまい、sqlが読み込まれません。

参考記事:
https://qiita.com/kondo0602/items/ab0a85fb1e731234eb1a
https://qiita.com/t-kigi/items/82e36bcc7630f92fc24e

テーブル接頭辞の設定

既存サイトのWordPressのテーブル接頭辞がwp_でない場合、テーブル接頭辞の設定が必要です。

docker-compose.ymlファイルの28行目environmentに以下を追加します。(接頭辞をhoge_の場合)

      WORDPRESS_TABLE_PREFIX: hoge_

コマンドラインで、次のコマンドを実行して、コンテナを再起動します。

docker-compose up -d

http://localhost:8000/にアクセスすると既存サイトが表示されるはずです。

その他メモ

//使用していないDockerオブジェクトの削除
docker system prune
https://docs.docker.jp/config/pruning.html

//mySQLに入る
docker exec -it <コンテナ名> bash
※コンテナ名は、docker psで表示されるNAMESの値

// wordpressに入る
docker-compose exec <サービス名(wordpress)> sh
※サービス名は、docker-compose psで表示されるSERVICEの値

//データベース接続
mysql -u root -p

//データベース確認
show databases;

//データベース選択
use <データベース名>;

//テーブル確認
show tables;

プラグインを起動時にインストール(Dockerfile)(いつか書く)

参考:https://tech.recruit-mp.co.jp/infrastructure/post-11266/#h-5

Git 作業別まとめ

更新

ブランチを切って、リモートブランチ作成

// リモートリポジトリーの確認
$ git remote -v

// 新しくブランチを作成
$ git branch [ブランチ名]

// 作ったブランチにチェックアウト
$ git checkout [ブランチ名]

// 手元のリポジトリをリモートリポジトリにプッシュ
$ git push [リモートリポジトリの名前] [ブランチの名前]

// ブランチの追跡設定
$ git branch --set-upstream-to=[リモートリポジトリの名前]/[追跡したいリモートブランチ] [手元のブランチ]

ブランチを切って、リモートブランチ作成(ショートVer.)

// ブランチを切ってそこにチェックアウト
$ git checkout -b [ブランチ名]

// 手元のリポジトリをリモートリポジトリにプッシュ(追跡設定つき)
$ git push -u [リモートリポジトリの名前] [ブランチの名前]

// 空のコミット作成
$ git commit --allow-empty -m "first commit"

// ↑の名前指定しないVer.
$ git push -u origin HEAD

コミットからプッシュまで

// 編集したファイルのステージング
$ git add .

// メッセージつきコミット
$ git commit -m 'コミットメッセージ'

// リモートリポジトリにプッシュ
$ git push

マージからリポジトリの削除(GitHUB Flow)

// masterにチェックアウト
$ git checkout master

// マージ
$ git merge --no-ff [ブランチ名]

// マージした内容をリモートリポジトリにプッシュ
$ git push

// 作業の終了したブランチを削除
$ git branch -d [ブランチ名]

設定

クローン

// リポジトリをクローンしたいディレクトリに移動して
$ git clone [複製元]

VS Code Formatter

VS Codeのデフォルトでは、HTML JSのフォーマッターは、入っているようです。
その他の言語には、各言語に対応したフォーマッターを追加してあげないといけません。

以下に追加したフォーマッターをメモとして、残しておきます。

適宜、追記します。

VS Codeの使い方メモ

Autoprefixer

VS CodeのAutoSaveをafterDelayで使用する場合、AutoprefixerのFormat On Saveにすると保存される度にカーソルが末尾に移動してしまい不便なので、Autoprefixerは、手動でコマンドパレット(shift + command + P)から使います。
SassのコンパイラーをEasy Sassではなく、Autoprefix機能のあるLive Sass Compileにするのも手かもしれません。

Work Space

VS CodeのWork Spaceには、編集するDirを直接設定する。複数ある場合、個々のDirを指定する。

EassySassの出力先

親のDirを指定するとEassySassの出力先が指定のパスと合わないのでエラーになってしまう。

EasySass出力先:sass/css(workspaceに指定されたDir/sass/cssに出力)

パネルの出し方

command + J

VS CodeでMarkdownのプレビュー

サイドバイサイドにプレビューを表示

[Command]+[K]→[V]

同一エディタに別タブとしてプレビューを表示

[Shift]+[Command]+[V]

エンコーディングを指定して表示する

開いたファイルで文字化けが発生していたら、画面下部にあるステータスバー右側にエンコーディング情報が表示されているので、クリックする。
画面上部に[アクションの選択]から[エンコード付きで再度開く]をクリック、エンコードを選択して再度開く。

随時追記

VS Code プラグイン markdownlintで、同じ名前の見出しをつけると注意される

VS Codeにプラグインmarkdownlintを入れました。
同じ見出しをつけるとこのルールにより注意を受けてしまいます。

でも、複数の親見出しの中に同じ名前の子見出しをつけたいこともあると思います。
こんな場合。

# 果物
    ## みかん
        ### 色
        ### 個数
    ## りんご
        ### 色
        ### 個数

このケースですと、色と個数に警告が出ます。
同じ名前を付けられない訳ではないのですが、警告の対象になって、気持ちが悪いです。

この警告を回避するためには、VS Codeのsetting.jsonに以下を設定します。

"markdownlint.config": {
    "MD024": {
        "siblings_only": true
    }
}

WordPress:REST API with Smart Custom Field

REST API

以前は、プラグインが必要だったREST APIですが、現行のWordPress5のcoreには、初めからREST APIが入っているようです。
今回、繰り替えしのフィールドが必要だったため、カスタムフィールドを登録するプラグインはSmart Custom Fieldを使用します。

カスタム投稿タイプとカスタムフィールドをREST APIに出力

カスタム投稿タイプをREST APIに出力するには、カスタム投稿タイプ作成時にREST APIに出力する設定が必要です。

function create_post_type() {
  $supports = [ 
    'title', // title
    'editor', // editor
  ];
  register_post_type( 'fruits', // 例:果物の場合
    array(
      'label' => '果物',
      'public' => true,
      'has_archive' => false,
      'menu_position' => 7,
      'supports' => $supports,
      'show_in_rest' => true, //rest api での取得有効にする
      'rest_base' => 'fruits' // rest api での取得名  /wp-json/wp/v2/fruits
    )
  );
}
add_action( 'init', 'create_post_type' );

REST APIの結果を確認してみましょう。

https://your-domain.com/wp-json/wp/v2/fruits

次にSmart Custom Fieldの値をREST APIに出力する設定を行います。
仮にSmart Custom Fieldに設定した名前が以下とします。

fruits_color テキストが入ります。
fruits_image idが入ります。

functions.phpに以下のコードを入力します。

// rest apiにカスタムフィールドを出力
add_action( 'rest_api_init', 'slug_register_fruits' );
function slug_register_fruits() {
  register_rest_field( 
    'fruits',   //フィールドを追加したいcustom投稿タイプを指定(先ほど登録したカスタム投稿タイプslugを指定)
    'fruits_meta',  // rest-apiに追加するキー
    array(
      'get_callback' => function( $object, $field_name, $request ) {
        // 出力したいカスタムフィールドのキーをここで定義
        $meta_fields = array(
          'fruits_color',
          'fruits_image',
        );
        $meta = array();
        foreach ( $meta_fields as $field ) {
          // バリデーションを一切してないので注意
          $meta[ $field ] = get_post_meta( $object['id'], $field, false ); // 第3引数はfalse、Smart Custom Fieldの繰り替えし機能を使うため
        }
        return $meta;
      },
      'update_callback' => null,
      'schema'          => null,
    )
  );
}

ここで注意して欲しいのが17行目のget_post_meta関数の第3引数です。
Smart Custom Fieldの繰り返しの機能を利用すると、繰り返されたグループの値は、カスタムフィールドに配列で格納されます。
そのため、第3引数にfalseを渡して、値を配列として受け取ります。
第3引数がtrueだと、繰り返されたグループの値が取得できません。

REST APIの出力結果を確認してみましょう。
カスタムフィールドの値が出力されているのが確認できると思います。

https://your-domain.com/wp-json/wp/v2/fruits

参考

wordpress rest-apiでカスタムフィールドを出力する際に処理結果を整形したい
https://qiita.com/kinshist/items/cd9f74af7db7c80746a1