6
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Headless CMS(WordPress)とGatsby.jsでサイト制作する際の備忘録

Last updated at Posted at 2019-12-08

静的サイトジェネレーター「Gatsby.js」について知りたかったのでUdemyのコースで学び、その備忘録となります。
以下の内容となっています。

Set Up

環境

  • MAMPでlocal環境構築
  • localのphpmyadminでDB接続

API

WordPressが提供しているREST APIからdataを取得するのではなくGraphQLでdata取得

REST API例
http://localhost:8888/myawesomeportfolio.io/wp-json/wp/v2/pages

gatsbyをinstall

$ npm install -g gatsby-cli

WordPressのREST APIをGatsbyにデータをpullさせるプラグインを設定

  • npm「gatsby-source-wordpress」をinstall
  • gatsby-config.jsにplugin設定。公式サイトを参考
  • baseUrlでMAMPで設定したWordpressのURLを指定

WordPressのdataをNode.jsで読み込みRouting処理

  • CreatePageを設定
    • component(適用したいcomponentのpathを指定)
    • context(componentのpropsで受け取るvalue)
    • path(Routing処理)
gatsby-node.js
const _ = require(`lodash`)
const Promise = require(`bluebird`)
const path = require(`path`)
const slash = require(`slash`)

exports.createPages = ({ graphql, actions }) => {
  const { createPage, createRedirect } = actions;
  return new Promise((resolve, reject) => {
    // ==== 固定ページ ====
    graphql(
      `
        {
          allWordpressPage {
            edges {
              node {
                id
                slug
                status
                template
                title
                content
                template
              }
            }
          }
        }
      `
    )
      .then(result => {
        if (result.errors) {
          console.log(result.errors)
          reject(result.errors)
        }

        // Create Page pages.
        const pageTemplate = path.resolve("./src/templates/page.js")
        _.each(result.data.allWordpressPage.edges, edge => {
          createPage({
            path: `/${edge.node.slug}/`,
            component: slash(pageTemplate),
            context: edge.node,
          })
        })
      })
      // ==== END 固定ページ ====

      // ==== 投稿ページ ====
      .then(() => {
        graphql(
          `
            {
              allWordpressPost {
                edges{
                  node{
                    id
                    title
                    slug
                    excerpt
                    content
                  }
                }
              }
            }
          `
        ).then(result => {
          if (result.errors) {
            console.log(result.errors)
            reject(result.errors)
          }
          const postTemplate = path.resolve("./src/templates/post.js")
          _.each(result.data.allWordpressPost.edges, edge => {
            createPage({
              path: `/post/${edge.node.slug}/`,
              component: slash(postTemplate),
              context: edge.node,
            })
          })
          resolve()
        })
      })
    // ==== END 投稿ページ ====
  })
}
  • context: edge.nodeと指定するとpropsにdataが入る
src/templates/page.js
import React from 'react';

export default ({ pageContext }) => (
  <div>
    <h1>
      {pageContext.title}
    </h1>
  </div>
)
  • pageでredirect処理
  • root pathで/homeにredirect
const { createRedirect } = actions;
createRedirect({ fromPath: '/', toPath: '/home', redirectInBrowser: true, isPermanent: true })

制作

ツール

  • ダミーテキスト生成用のfakerを使用
  • メニューのAPIを生成のWordPressプラグイン「WP REST API Menus」をでinstall

GraphQLで取得したdataにLinkを設定

  • GatsbyのLink componentを使用
import { graphql, StaticQuery, Link } from 'gatsby';

<StaticQuery query={graphql`
  {
    allWordpressWpApiMenusMenusItems{
      edges{
        node{
          items{
            title
            object_slug
          }
        }
      }
    }
  }
  `} render={props => (
  <div>
    {props.allWordpressWpApiMenusMenusItems.edges[0].node.items.map(item => (
      <Link to={`/${item.object_slug}`} key={item.title}>
        {item.title}
      </Link>
    ))}
  </div>
)} />

styled-componentsを使用

$ yarn add gatsby-plugin-styled-components styled-components babel-plugin-styled-components
  • gatsby-config.jsのpluginに設定
gatsby-config.js
plugins: [
    `gatsby-plugin-styled-components`,
],
  • globalにstyleを設定する場合はcreateGlobalStyleを使用
import styled, { createGlobalStyle } from 'styled-components';

const GlobalStyles = createGlobalStyle`
  @import url('https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i&display=swap');
  body, html {
    font-family: 'Open Sans', san-serif;
    margin: 0 !important;
    padding: 0 !important;
  }
`;

const Layout = ({ children }) => (
 <div>
   <GlobalStyles />
  {children}
 </div>
);
  • Linkにstyled-componentsを使用する場合はstyled(Link)を指定
import { graphql, StaticQuery, Link } from 'gatsby';
import styled from 'styled-components';

const ManuItem = styled(Link)`
  color: white;
  display: block;
  padding: 8px 16px;
`;

const MainMenu = () => (
  <StaticQuery query={graphql`
    {
      allWordpressWpApiMenusMenusItems(filter: {
        name: {
          eq: "Main menu"
        }
      }){
        edges{
          node{
            items{
              title
              object_slug
            }
          }
        }
      }
    }
  `} render={props => (
    <MainMenuWrapper>
      {props.allWordpressWpApiMenusMenusItems.edges[0].node.items.map(item => (
        <ManuItem to={`/${item.object_slug}`} key={item.title}>
          {item.title}
        </ManuItem>
      ))}
    </MainMenuWrapper>
  )} />
);

カスタム投稿タイプ「portfolio」を追加

  • gatsby-config.jsgatsby-source-wordpressのoptionsに追加
  • gatby-node.jsに「portfolio」のtemplateを追加
gatsby-config.js
includedRoutes: [
  "**/categories",
  "**/posts",
  "**/pages",
  "**/media",
  "**/tags",
  "**/taxonomies",
  "**/users",
  "**/menus",
  "**/portfolio",
]
gatby-node.js
// ==== カスタム投稿タイプ(portfolio) ====
.then(() => {
  graphql(
    `
      {
        allWordpressWpPortfolio{
          edges{
            node{
              id
              title
              slug
              excerpt
              content
              featured_media{
                source_url
              }
            }
          }
        }
      }
    `
  ).then(result => {
    if (result.errors) {
      console.log(result.errors)
      reject(result.errors)
    }
    const portfolioTemplate = path.resolve("./src/templates/portfolio.js")
    _.each(result.data.allWordpressWpPortfolio.edges, edge => {
      createPage({
        path: `/portfolio/${edge.node.slug}/`,
        component: slash(portfolioTemplate),
        context: edge.node,
      })
    })
    resolve()
  })
})
// ==== カスタム投稿タイプ(portfolio) ====

templateの選択によってレイアウトを変える場合

  • WordPressの固定ページにTemplate選択機能を追加、投稿ページに適用
  • gatsby-node.jsにtemplateの種類を追加、その分岐処理
wp-content/themes/wp-gatsby-js-theme-starter-master/portfolio_under_content.php
<?php /* Template name: Portfolio items below content */ ?>
gatsby-node.js
const pageTemplate = path.resolve("./src/templates/page.js")
const portfolioUnderContentTemplate = path.resolve("./src/templates/portfolioUnderContent.js")
_.each(result.data.allWordpressPage.edges, edge => {
  createPage({
    path: `/${edge.node.slug}/`,
    component: slash(edge.node.template === 'portfolio_under_content.php' ? portfolioUnderContentTemplate : pageTemplate),
    context: edge.node,
  })
})

「Advanced Custom Fields」を扱う

  • WordPressの「Advanced Custom Fields」のAPIを取得プラグインで「ACF to REST API」をinstall
  • gatsby-node.jsでGraphQLで取得するdataにacfを追加
gatsby-node.js
graphql(
  `
    {
      allWordpressWpPortfolio{
        edges{
          node{
            id
            title
            slug
            excerpt
            content
            featured_media{
              source_url
            }
            acf{
              portfolio_url
            }
          }
        }
      }
    }
  `
)

投稿一覧画面にページネーション実装

  • gatsby-node.jsでGraphQLで展開したdataを元にCreatePageを設定
gatsby-node.js
const posts = result.data.allWordpressPost.edges;
const postsPerPage = 2;
const numberOfPages = Math.ceil(posts.length / postsPerPage);
const blogPostListTemplate = path.resolve('./src/templates/blogPostList.js');

Array.from({ length: numberOfPages }).forEach((page, index) => {
  createPage({
    component: slash(blogPostListTemplate),
    path: index === 0 ? '/blog' : `/blog/${index + 1}`,
    context: {
      posts: posts.slice(index * postsPerPage, (index * postsPerPage) + postsPerPage),
      numberOfPages,
      currentPage: index + 1
    },
  });
});
  • CreatePageのdataをtemplatesで画面制作
  • pageContext.postsはcontextで設定したpostsで、GraphQLから取得したdata
  • Array.from({ length: pageContext.numberOfPages})でページャの番号を生成
src/templates/blogPostList.js
const blogPostList = ({ pageContext }) => (
  <Layout>
    {
      pageContext.posts.map(post => (
        <div key={post.node.wordpress_id}>
          <h3 dangerouslySetInnerHTML={{ __html: post.node.title }} />
          <p dangerouslySetInnerHTML={{ __html: post.node.content }} />
        </div>
      ))
    }
    {
      Array.from({ length: pageContext.numberOfPages}).map((page, index) => (
        <div key={index}>
          <Link to={index === 0 ? '/blog' : `/blog/${index + 1}`}>
            {index + 1}
          </Link>
        </div>
      ))
    }
  </Layout>
);

export default blogPostList;

一覧画面のページネーションでCurrentPageかを判定

  • style-componentsでpropsを受け取って判定
  • pageContext.currentPagegatsby-node.jsのcontextで設定した値
import styled from 'styled-components';

const PageNumberWrapper = styled.div`
  border: 1px solid #eee;
  background-color: ${props => props.isCurrentPage ? '#eee' : 'white'};
`;

<PageNumberWrapper key={index} isCurrentPage={index + 1 === pageContext.currentPage}>

GraphQLで日付フォーマットを指定

  • formatStringで指定
{
  allWordpressPost{
    edges{
      node{
        excerpt
        date(formatString: "YYYY/MM/DD hh:mm")
      }
    }
  }
}

その他

WordPressにカスタム投稿タイプ「portfolio」を追加

  • WordPressのthemeで管理しているfunctions.phpに記述
functions.php
<?php
add_theme_support( 'custom-logo' );
add_theme_support( 'menus' );
add_theme_support('post-thumbnails');

function create_custom_portfolio_post_type() {
	register_post_type('portfolio', 
    array(
      'labels' => array(
        'name' => __('portfolio'),
    	  'singular_name' => __('portfolio')
      ),
      'public' => true,
      'show_in_admin_bar' => true,
      'show_in_rest' => true,
    ));
	add_post_type_support('portfolio', array('thumbnail', 'excerpt'));
}

add_action('init', 'create_custom_portfolio_post_type');
6
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?