これまでWordPressを使ったユーザー投稿型のサイトをいくつか作ってきたのですが
フロント部分をVueにして投稿処理や記事取得にWP REST APIを使ったらどうだろうと思い試してみたところ、びっくりするぐらい簡単にできてしまったのでその感動をお伝えします。
ADs
サーバーにWordPressをインストールします。
WordPressはREST APIによってVueによるページからの投稿データを保存する、記事を出力するだけの役割ですので、テーマは使いません(万が一見られても困るので空白のテーマを作って適用させておけばよい)。
投稿者用のユーザーを作成します。
外部からの投稿ユーザーも管理者と同じアカウントを使っても問題ありませんが、別ユーザーを作っておいたほうが管理しやすいでしょう。投稿権限が必要なので投稿が可能なグループ(「投稿者」やUser Role Editorで細かく設定するなど)にしておきます。
Application Passwordsプラグインをインストールし、有効化します。
有効化してユーザー一覧を開き、先程作成したユーザー(consumer)の詳細を見ると「Application Passwords」という項目が増えています。
ここの「New Application Password Name」に同じユーザー名(consumer)を入力し、「Add New」をクリックするとパスワードが発行されます。
このパスワードは一度しか表示されないためコピペしておきます。
今回は投稿内容にカスタムフィールドを含めたいため、
・投稿時にカスタムフィールドを追加する関数
・記事取得時にカスタムフィールドを取得する関数
を追加します。
投稿内容に「meta」というオブジェクトがあった場合、そのオブジェクトのキー名をカスタムフィールド名、valueをカスタムフィールドの値とする関数です。
1 2 3 4 5 6 7 8 9 10 11 12 |
add_action('rest_insert_post', function (\WP_Post $post, $request, $creating) { $metas = $request->get_param('meta'); if (is_array($metas)) { foreach ($metas as $name => $value) { update_post_meta($post->ID, $name, $value); } } }, 10, 3); |
WP REST APIによる記事取得はカスタムフィールドが含まれませんので、カスタムフィールドを含めるようにする関数です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
add_action( 'rest_api_init', 'add_custom_fields_to_rest' ); function add_custom_fields_to_rest() { register_rest_field( 'post', 'custom_fields', [ 'get_callback' => 'get_custom_fields_value', // カスタム関数名指定 'update_callback' => null, 'schema' => null, ] ); } function get_custom_fields_value() { return get_post_custom(); } |
この2つの関数は定型文として毎回functions.phpに追加するかオレオレプラグインとして置いておくといいでしょう。
WordPress側の作業はこれで終わりです。
ビルドされたデータ(distフォルダの中身)を公開ディレクトリに置きます。
シンプルに本文(WordPressから見た場合、post_contentに当たる)と種類(「genre」というカスタムフィールドに持たせる)のみのフォームを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<div class="row mb-2"> <div class="col-4">コメント</div> <div class="col-8"> <textarea class="form-control" v-model="content"></textarea> </div> </div> <div class="row mb-2"> <div class="col-4">種類</div> <div class="col-8"> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="type" id="type1" value="人間" v-model="genre" /> <label class="form-check-label" for="type1">人間</label> </div> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="type" id="type2" value="犬" v-model="genre" /> <label class="form-check-label" for="type2">犬</label> </div> <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="type" id="type3" value="人外" v-model="genre" /> <label class="form-check-label" for="type3">人外</label> </div> </div> </div> <div class="row"> <div class="col"> <button class="btn btn-primary" v-on:click="post">投稿する</button> </div> </div> |
textareaとradioにv-modelでデータをバインドし、「投稿する」をクリックすることでpost()関数を実行するだけのシンプルなものです。
記事一覧をpostsという名称で保持し(これはのちほどaxiosで取得します)、v-forで一覧表示させます。
1 2 3 4 5 6 7 8 9 10 11 |
<div class="row border-top pt-4 mt-4 align-items-stretch"> <div class="col-4 mb-4" v-for="(item,index) in posts" :key="index"> <div class="p-2 border h-100"> <div v-html="item.content.rendered"></div> <div class="text-right small" v-if="item.custom_fields.genre" >{{ item.custom_fields.genre[0] }}</div> </div> </div> </div> |
実運用ではページネーションや無限スクロールも考えないといけないですが、とりあえずは一覧を出すだけにしておきます。
スクリプト部分はたったこれだけ!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import axios from "axios"; export default { data() { return { content: "", genre: "", posts: [] }; }, mounted() { var vm = this; vm.url = "https://example.com/wp/wp-json/wp/v2"; vm.get(); }, methods: { post() { var vm = this; axios .post( vm.url + "/posts", { content: vm.content, author: 2,//consumerのユーザーID meta: { genre: vm.genre }, status: "publish" }, { headers: { Authorization: "Basic <<username:passordをbase64にしたもの:後述>>" } } ) .then(function() { vm.get(); }); }, get() { var vm = this; axios.get(vm.url + "/posts").then(function(response) { vm.posts = response.data; }); } } }; |
post関数はCSRF対策やエラー処理やバリデーション、重複投稿などやることはまだあるものの、フロントから記事を投稿させるだけならaxios.postの数行で済んでしまいます。
かつてはphpでwp_insert_postの処理を書き、jQueryでAjaxによるPOST送信の処理を書き…と面倒な仕事でしたが、非同期の送信処理がこれほど簡単に書けるとは…いい時代になったものです。
「ユーザー名:Application Passwordsプラグインが生成したパスワード」をbase64にエンコードしたテキストを記述します。
つまり、ユーザー名が「consumer」、パスワードが「R9TM 38p0 Cm40 7czU fzXZ jlgY」ですので、
consumer:R9TM 38p0 Cm40 7czU fzXZ jlgY
をエンコードして
Basic Y29uc3VtZXI6UjlUTSAzOHAwIENtNDAgN2N6VSBmelhaIGpsZ1k==
となります。
コード全文はGithubをご覧ください。
ちょっと仕事の気晴らしにやってみようと思っただけでしたが、思いのほか簡単で驚きました。
Web制作系の方なら使い慣れているWordPressとモダンなフロントエンド環境であるVueの組み合わせというのもありだと思うのですが、いかがでしょう?
ADs
コメントはまだありません。