稼働中のWordPressをGridsomeで構築してみる

6 min read

背景

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 で当たり前にある機能が足りないため、本番稼働させるには厳しいと感じた)

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