Vue.js + Wordpressで作ってみる

WordPress（以下WP）はまだまだ現役だけど、もっさり感がねぇ。
なので、WPは運用者の更新用にして、実際のビュー部分はVue.js(Nuxt.js)でやろうって話です。

##WPの準備
インストールは割愛
最近のWPはデフォルトでWP REST APIが入っているので、既存の投稿を使う場合は何もしなくていいです。
カスタムフィールドを追加する場合は、Advanced Custom FieldならAPI化が簡単らしいです。

###カスタム投稿をAPI化する

カスタム投稿追加とAPI化のコードをfunctions.phpに追加する。
https://ドメイン/wp/ にWPがインストールされているとして、[https://ドメイン/wp/wp-json/wp/v2/samplepost](https://ドメイン/wp/wp-json/wp/v2/サンプルポスト) でjson返します。


```php:functions.php
function create_post_type() {
	$supports = [ 
	  'title',
	  'editor',
	  'author',
	  'thumbnail', 
	  'excerpt', 
	  'custom-fields',
	];
	register_post_type( 'samplepost', 
	  array(
		// 以下は適当に
		'label' => 'サンプルポスト',  
		'public' => true,  
		'has_archive' => false,  
		'menu_position' => 7, 
		'supports' => $supports, 
		'show_in_rest' => true,
		'rest_base' => 'samplepost'
	  )	
	);	
  }
  add_action( 'init', 'create_post_type' );

  function slug_register_cutomposts() {
	  register_rest_field( 'samplepost', //デフォルトの投稿のカスタムフィールドをAPI化する場合はpostsに
		  'data',
		  array(
			  'get_callback'  => function(  $object, $field_name, $request  ) {
				$meta_fields = array( //ここにAPIで呼び出すカスタムフィールドを列挙
					'Customfield01',
					'Customfield02',
					'Customfield03',
				);
				$meta = array();
				foreach ( $meta_fields as $field ) {
				  $meta[ $field ] = get_post_meta( $object[ 'id' ], $field, true );
				}
				return $meta;
			  },
			  'update_callback' => null,
			  'schema'          => null,
		  )
	  );	  
  }
  add_action( 'rest_api_init', 'slug_register_cutomposts' );
```
カスタムフィールドは適当に準備してください。


##Nuxt.jsの準備
###インストール
vueとvue-cliはインストール済みとして。
`$ vue init nuxt-community/starter-template projName`
`$ npm install`
`$ npm run dev`

http://localhost:3000/ で以下が表示できていればOK
<img width="500" alt="Screen Shot 2019-05-09 at 13.47.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212730/4bf36c57-d57d-18b0-3c47-729fd1f3a655.png">

###ページの作成
pagesフォルダにこんな感じでフォルダとvueファイルを作っていきます。
newsはデフォルトのpostsに対応しています。Vueでは、アンダースコアをつけることで動的なルーティングを定義できます。
news/index.vue、samplepost/index.vue がそれぞれのアーカイブページに対応しています。

```
pages
├── index.vue
├── news
│   ├── _id.vue
│   └── index.vue
└── samplepost
    ├── _id.vue
    └── index.vue
```


ページを作っていきます。WPの投稿とも紐づけます。
axiosを使用します。

`$ npm install --save-dev axios`


```vue:pages/news/index.vue
<template>
<div>
    <PostList :posts="posts" />
</div>
</template>
 
<script>
import PostList from '~/components/posts/PostList.vue'
import wp from '~/wp'
 
export default {
    asyncData ({ params }) {
        return wp.posts()
    },
    components: {
        PostList,
    }
}
</script>
```

```vue:components/posts/PostList.vue
<template>
  <ul>
    <li v-for="post in posts" :key="post.id">
        <article>
          <a v-bind:href="'/news/' + post.id">
            <h2 class="subtitle">{{ post.title.rendered }}</h2>
            <div class="info" v-html="post.excerpt.rendered"></div>
          </a>
        </article>
    </li>
  </ul>
</template>
 
<script>
 
export default {
  props: ['posts'],
}
</script>
```

```js:wp.js
import axios from 'axios'
 
class WpApi {
  constructor (siteurl) {
    this.apiBase = `${siteurl}/wp-json`
  }
  async posts () {
    try {
          const json = await axios.get(`${this.apiBase}/wp/v2/posts`, {
              params: {
                  page: 1,
                  per_page: 5
              }
          });
          return { posts: json.data };
      }
      catch (e) {
          return { error: e };
      }
  }
  async samplepost () {
    try {
          const json = await axios.get(`${this.apiBase}/wp/v2/samplepost`, {
              params: {
                  page: 1,
                  per_page: 5
              }
          });
          return { samplepost: json.data };
      }
      catch (e) {
          return { error: e };
      }
  } 
}
const wp = new WpApi('https://ドメイン/wp/')
export default wp
```

```vue:pages/news/_id.vue
<template>
  <div>
      <h2>{{ post.id }}</h2>
      <h3 class="subtitle">{{ post.title.rendered }}</h3>
      <div class="info" v-html="post.content.rendered"></div>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  async asyncData ({ params }) {
    //id指定で個別の記事なんで直接書いた
    //WPのパーマリンク設定によってはgetするときのurlが違うかもですので、適宜変更してください。
    const { data: post } = await axios.get(`https://ドメイン/wp/wp-json/wp/v2/posts/${params.id}`)
    return {
      post
    }
  }
};
</script>
```

###サイト公開


```js:nuxt.config.js
//ここでもaxios呼んでおいてください
const axios = require('axios')
const apiUrl = 'https://ドメイン'


中略// nuxt generateの変更


  generate: {
    interval: 1000, //インターバルないとサーバーが落ちます。
    routes () {
      return Promise.all([
        axios.get(`${apiUrl}/wp-json/wp/v2/posts`),
      ]).then((data) => {
        const posts = data[0]
        return posts.data.map((post) => {
          return {
            route: '/news/' + post.id,
            payload: post
          }
        })
      })
    }
  },


以下略

```

`npm run generate` でdistフォルダが作成されます。中身を丸っとドメインのルートに入れれば、ページが公開されます。


##（未対応）WP更新で自動反映

このままだと、WP側で更新しても、サイトには反映されません。
generateして静的ファイルを生成しなおす必要があります。
そのため、WP更新 → Nuxt generate → 生成ファイルのアップロード を自動化できるとみんなハッピーですね。