この記事は Vue.js #2 Advent Calendar 2018 – Qiita の 21日目の記事です。

背景

WordPressで10年以上運用してるブログをどうにかしたいと思い始める。

  • パーマリンクを変えたくない
  • WordPress つらくなってきている
    v5.0.0 の標準エディタGutenbergの具合がよろしくない
  • フロント実装(WordPressテーマ)をVue.jsで構築している
    移行先もスムーズにVue.jsが使えると良い
  • 完全に静的化する(Hugoなど)すると記事データの管理が面倒そう

上記を踏まえて、記事管理のためにCMS(WordPress)は残しつつ、移行の手間を掛けずに手軽に試せそうなGridsomeを試してみる。


Gridsomeを使ってみる

React製のGatsbyJSライクなVue.js製のGridsomeを使ってみる。

インストール

公式のドキュメントにそって入れていく。

使用モジュールのバージョン:

  • @gridsome/source-wordpress: v0.1.1
  • gridsome: v0.4.0

まずは「グローバルにインストールしろ」というのでひとまずインストールする。

npm install --global @gridsome/cli

データソースをWordPressにしたい。@gridsome/source-wordpressが用意されているが、同梱されてるみたいなので、下記を実行するだけで良い。

gridsome create my-gridsome-project wordpress

gridsome createが完了すると、下記のようなファイルが展開される。

.
├── src
├── gridsome.config.js
├── node_modules
├── package.json
└── README.md

gridsome.config.js

まずは取得先の情報を設定する。

module.exports = {
  plugins: [
    {
      use: '@gridsome/source-wordpress',
      options: {
        baseUrl: 'YOUR_WEBSITE_URL', // required
        typeName: 'WordPress', // GraphQL schema name (Optional)
        perPage: 100, // How many posts to load from server per request (Optional)
        concurrent: 10, // How many requests to run simultaneously (Optional)
        routes: {
          post: '/:year/:month/:day/:slug', //adds route for "post" post type (Optional)
          post_tag: '/tag/:slug' // adds route for "post_tag" post type (Optional)
        }
      }
    }
  ]
}

plugins.options.baseUrlの値を対象のWordPressのURLに書き換えてみる。もし、対象がない場合は、demo用のhttps://demo.wp-api.org/を指定しても良さそう。

実行

npm run develop  // or build
  Site running at:          http://localhost:8080/
  Explore GraphQL data at:  http://localhost:8080/___explore

http://localhost:8080/にアクセスするとGridsomeで構築したページが見れるようになる。
ライブリロードされるので、そのままVue SFCを修正して開発に取り掛かることができる。

http://localhost:8080/___exploreの方は、GraphQLのクエリをテストしたいときに使えるプレイグラウンドへアクセスできる。
プロジェクト内で使用可能なGraphQLコレクションの一覧も見ることができる。

GraphQL

ページ固有のデータを取得する

query Page {
  wordPressPage (path: "/pages/about") {
    title
    content
  }
}

pathに指定する値が、単純にaboutではなく/pages/を挟むことに注意。

カテゴリーの記事一覧を取得する

query {
  allWordPressCategory {
    edges {
      node {
        count
        title
        slug
      }
    }
  }
}

perPageのデフォルト値があるため、この指定だと全件は取得できない。

Vue SFC

<template>
  <Layout>
    <h1 v-html="$page.wordPressPostTag.title" />
  </Layout>
</template>

<page-query>
query PostTag ($path: String!) {
  wordPressPostTag (path: $path) {
    title
  }
}
</page-query>

$page.クエリ名でデータにアクセスができる。クエリによってデータ構造が違うので注意。

WordPress(WP-API)を調整

私が対象としていたWordPressは下記のようなパーマリンクになっていた。

/%year%%monthnum%%day%%hour%%minute%%second%.html

また、個別記事に関してはslug設定がない状態だった。

現状、Gridsomeで使用できるルートは、:year, :month,:day,:slugの組み合わせでしか設定できない。(post_tagも同様)

routes: {
  post: '/:year/:month/:day/:slug', //adds route for "post" post type (Optional)
  post_tag: '/tag/:slug' // adds route for "post_tag" post type (Optional)
}

WP-APIが吐き出すslugを調整して、既存のパーマリンクに寄せていく。

WP-APIの拡張

rest_prepare_postというhookを使い下記のようにAPIを書き換えてしまう。

add_filter('rest_prepare_post', 'adjusted_api_data');

public function adjusted_api_data($response, $post, $request) {
    $link = basename($response->data['link']);

    $response->data['link'] = '/' . $link;
    $response->data['slug'] = $link;

    return $response;
}

補足:
WP-APIのlinkは、NodeInterfaceにあるpathになる。

edges {
  node {
    id
    title
    slug
    path
  }
}

これでGridsomeが出力した個別記事にも既存パーマリンクと同じ状態でアクセスができるようになった。

最後に

始めは「えっ、こんなに簡単に…!?」という感想だったが、開発中につき機能がまだまだ足りず、痒いところに手が届かない状態であった。
(GatsbyJSで当たり前にある機能が足りないため、本番稼働させるには厳しいと感じた)

メジャーバージョンアップに期待。