16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WordPressの一部にReactを取り入れる

Posted at

目標

本記事はReactでアプリを作成することが目的ではなく、Reactで作成したものをWordPress内に取り入れることが目標となっております。
そのため、Reactのコンポーネント化等、最適化等はしておりません。
(TypeScriptも導入しておりません)

viteを使用して新規Reactアプリを作成する

viteを使用して新規Reactアプリの作成

yarn create vite

新規アプリ作成方法が分からない方は以下参考にしてみて下さい。
https://ja.vitejs.dev/guide/

(今回はTypeScript選択せずに、 JavaScriptを選択しました)

スクリーンショット 2024-01-21 15.10.47.png

上記コマンド実行してアプリを起動してみます。

以下のような画面が表示できたら成功です!

スクリーンショット 2024-01-21 15.11.58.png

作成したReactアプリを不要なデータ削除し何もない状態にする

src/App.jsx
の内容を綺麗に削除します。
一旦テストと表示させておきます。

スクリーンショット 2024-01-21 20.27.15.png

スクリーンショット 2024-01-21 15.30.58.png

WordPressの記事をJSON表示させてみる

実はWordPressは何もしなくてもJSONデータを生成して表示しています。。

https://{ドメイン}/wp-json/wp/v2/{表示したい記事種類等}

とすると確認できます。

実際に私のブログサイトで試してみます。

https://just-a-mother.com/wp-json/wp/v2/posts

私のブログは全て既存の投稿を使用しているの記事の種類はpostです。
ここがカスタム投稿タイプや固定ページなどになると変わってきます。

詳しくはいろいろあるので、自分が取得したい記事内容など調べてみて下さい。

上記にアクセスすると以下のようなJSONデータを確認することができます。

スクリーンショット 2024-01-21 15.21.10.png

上記のように成形されずただの文字列っぽく見えてしまう人はChromeの拡張機能の「JSON Viewer」

などを入れたら見やすくなります!

WordPressの記事をReatで取得してみる

apiを使用してHTTPリクエストするために今回はaxiosをインストールして使用します。

yarn add axios

axios以外にもいろいろあるので、良ければ調べてみて下さい。

import { useEffect, useState } from "react";
import "./App.css";
import axios from "axios";

function App() {
  const [posts, setPosts] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const URL = "https://just-a-mother.com/wp-json/wp/v2/posts";
    axios.get(URL).then((res) => {
      setPosts(res.data);
      setIsLoading(false);
    });
  }, []);
  console.log("posts", posts);
  return (
    <>
      <div>テスト</div>
    </>
  );
}

export default App;

上記のように最低限の記述ですが、コンソールログに取得した記事を出してみます。
ちゃんと10件分の記事が取得できました

スクリーンショット 2024-01-21 15.37.17.png

ですが、10件しか取得できていないですね。。
調べたところ、デフォルトで10件、パラメータ付きで100件までとありましたので、


const URL = "https://just-a-mother.com/wp-json/wp/v2/posts";

const URL = "https://just-a-mother.com/wp-json/wp/v2/posts?per_page=100";

としたところ、無事に全件取得できました!
(私のブログには28件しか記事がないんで、、、)

スクリーンショット 2024-01-21 15.51.46.png

もう一つ、今回は記事に設定してあるタグ情報を取得します。
下記でWordPressの記事投稿で設定しているタグ情報を取得できました。


const TAGS_URL = "https://just-a-mother.com/wp-json/wp/v2/tags";
 axios.get(TAGS_URL).then((res) => {
      setTags(res.data);
    });

こんな感じで取得できています!

スクリーンショット 2024-01-21 19.50.57.png

上記getするコードを追記しても良いのですが、
二つのapiでまとめてgetしたいのでPromise.allに記述を変更します。


axios.get(POSTS_URL).then((res) => {
      setPosts(res.data);
    });

axios.get(TAGS_URL).then((res) => {
      setTags(res.data);
      setIsLoading(false);
    });

// 以下に書き換える ↓

useEffect(() => {
    Promise.all([axios.get(POSTS_URL), axios.get(TAGS_URL)]).then(
      ([postsResponse, tagsResponse]) => {
        setPosts(postsResponse.data);
        setTags(tagsResponse.data);
        setIsLoading(false);
      }
    );

まず、タグリストを表示させます。

下記でタグリストが表示されました!
(CSSは当ててます)

 {isLoading ? null : (
        <div className="">
           <ul className="tag-list">
            {tags.map((tag, i) => (
              <li key={i} className="tag-item">
                {tag.name}
              </li>
            ))}
            </ul>
        </div>
      )}

スクリーンショット 2024-01-21 20.44.57.png

クリックしたタグが付与されている記事を下へ表示させる

次にタグボタン下に選択したタグに関連する記事を表示させてみます。


 const handleFiler = useCallback(
    (id) => {
      setFilteredPosts(posts.filter((post) => post.tags.includes(id)));
    },
    [posts]
  );
  

上記フィルターする関数を作成します。
ulの方も以下のように修正します。

<ul className="tag-list">
    {tags.map((tag, i) => (
        <li
            key={i}
            className="tag-item"
            onClick={() => handleFiler(tag.id)} // clickしてidが取得できるように追記
        >
            {tag.name}
        </li>
    ))}
</ul>
<ul className="post-list">
    {filteredPosts.map((post, i) => (
        <li key={i} className="post-item">
            <a href={post.link} className="post-link">
                {post.title.rendered}
            </a>
        </li>
    ))}
</ul>

これでクリックしたら該当タグが付与されてた記事が下へ表示できるようになりました。

スクリーンショット 2024-01-21 21.35.39.png

Reactアプリをビルドする

上記までで簡単ではありますが、Reactを使用したアプリが完成できました。

ビルドします。
ビルドするとdistディレクトリができました。

スクリーンショット 2024-01-22 20.48.52.png

dist/assets/index--1kmMQDK.css
dist/assets/index-Zr6b2y_5.js
この二つのソースを使用します!

WordPressに組み込んでみる

先ほどビルドしたソースを使用します。

オリジナルテーマに組み込む

例えば特定の固定ページに組み込みたいとします。

page-{記事slug}.php

<!-- 記事ページ -->
<?php get_header(); ?>
<section class="main_post">
    <div id="app"></div>  //ここにReact組み込む
    <!-- サイトバー -->
    <?php get_sidebar(); ?>
</section>
<?php get_footer(); ?>

記事のPHPテンプレートの組み込みたい場所に

<div id="app"></div>

を入れます。
そして、このページに先ほどビルドしたjsファイルとCSSファイルを読み込みします。
もちろん、サーバーへjsファイル、cssファイルをアップすることもお忘れなく!

有料テーマを使用しつつ、特定ページに組み込む

私はブログ用にSWELL(有料テーマ)を使用しています。
この特定の固定ページに組み込みたいと思います。

カスタムHTMLを入力できる枠を出し、そこに

<div id="app"></div>

を記載します。

スクリーンショット 2024-01-21 22.00.13.png

その下のこのページに読み込むCSSとJSという箇所に先ほどビルドしたファイルをコピぺします。

スクリーンショット 2024-01-21 21.59.55.png

そして更新&公開

スクリーンショット 2024-01-21 22.01.43.png

ちゃんと表示できました!

なぜid="app"??

Reactアプリを組み込みしたい箇所には

<div id="app"></div>

としたらそこにReactで作成したアプリが表示されました。
なぜid="app"なのか?他のidだとダメ??

Reactアプリを生成する際の大元の
index.htmlにid="app"としています。

スクリーンショット 2024-01-22 20.55.05.png

そして、そこに
src/main.jsxにて

document.getElementById("app")

とid="app"にをレンダーしているのでid="app"にしないといけません。

スクリーンショット 2024-01-22 20.56.46.png

ここのidを例えばid="myApp"とかにしていれば、id="myApp"を使用しないといけません。
なので、どんな時でもid="app"ではないということは気をつけましょう。

上記が実際に作成したReactアプリを組み込みしたページとなります。

## 補足
最終的にapp.jsxのソースはこちらです。

import { useEffect, useState, useMemo, useCallback } from "react";
import "./App.css";
import "./reset.css";
import axios from "axios";

const POSTS_URL = "https://just-a-mother.com/wp-json/wp/v2/posts?per_page=100";
const TAGS_URL = "https://just-a-mother.com/wp-json/wp/v2/tags";

function App() {
  const [posts, setPosts] = useState([]);
  const [tags, setTags] = useState([]);
  const [filteredPosts, setFilteredPosts] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    Promise.all([axios.get(POSTS_URL), axios.get(TAGS_URL)]).then(
      ([postsResponse, tagsResponse]) => {
        setPosts(postsResponse.data);
        setTags(tagsResponse.data);
        setIsLoading(false);
      }
    );
  }, []);

  const handleFiler = useCallback(
    (id) => {
      console.log("id", id);
      setFilteredPosts(posts.filter((post) => post.tags.includes(id)));
    },
    [posts]
  );

  return (
    <>
      {isLoading ? null : (
        <div className="">
          <h2 className="title">興味がある分野を選んで下さい</h2>
          <ul className="tag-list">
            {tags.map((tag, i) => (
              <li
                key={i}
                className="tag-item"
                onClick={() => handleFiler(tag.id)}
              >
                {tag.name}
              </li>
            ))}
          </ul>
          <ul className="post-list">
            {filteredPosts.map((post, i) => (
              <li key={i} className="post-item">
                <a href={post.link} className="post-link">
                  {post.title.rendered}
                </a>
              </li>
            ))}
          </ul>
        </div>
      )}
    </>
  );
}

export default App;

以上です。
WordPressや静的サイトに気軽にReactアプリを組み込みして見て下さいね!

16
16
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
16
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?