ブログ

  • ポートフォリオサイトをヘッドレスWordPress+Next.jsで作り直した話 (4) デザイン調整・ブログ機能追加編

    シリーズ最終回です。データがきちんと表示できるようになった後、「もとのサイトとだいぶ印象が違う」というフィードバックをもとに行ったデザイン調整と、このブログ機能を追加した経緯についてまとめます。

    もとのサイトの雰囲気に近づける

    ページ構成(実績・スキル・プロフィールを別ページに分ける形)はそのまま維持しつつ、見た目だけをもとのサイトに近づける方針にしました。具体的には、中央寄せの見出し+下線バーという共通の見出しコンポーネントを作ったり、ヘッダー・フッターに以前から使っていた「肉球マーク」のロゴを置き直したりしています。

    実績カードの画像・リンク・配色を見直す

    もともと実績カードには画像がなかったので、商用利用可能なオリジナル画像を4枚用意してカードに追加しました。また、実績の詳細ページへのリンクが軒並み404になっていた件は、前回の記事の通りスラッグの日本語表記が原因だったため、英数字への統一で解消しています。

    配色については、技術タグの色をハッシュ値だけで機械的に割り当てていたため、たとえば「JavaScript」が黄色ではなく別の色になってしまうなど、見た人が持っている技術のイメージと合わない配色になっていました。そこで、HTML・CSS・JavaScript・WordPress・PHPなど、よく知られた技術については実際のブランドカラーに近い色を明示的に割り当て、それ以外の名前だけハッシュ値ベースの配色にするよう調整しました。

    プロフィール画像は、新しく作り直すのではなく「もとのサイトの画像をそのまま使ってほしい」というリクエストだったので、WordPressのメディアライブラリにもとの画像を取り込み直して差し替えています。

    カラーパレットの調整とブログ機能の追加イメージ

    ブログ機能を追加する

    ここまでで実績・スキル・プロフィールのリニューアルは一段落したので、追加で「ブログ」機能を作りました。専用のカスタム投稿タイプは作らず、WordPress標準の「投稿」をそのまま使い、カテゴリだけ「技術系」「読んだ本の感想」の2つを新設しています。Next.js側では /blog に一覧ページ、/blog/[slug] に詳細ページを用意し、一覧ページではカテゴリ別の絞り込みタブも付けました。今読んでいただいているこの記事も、その「技術系」カテゴリの投稿の1つです。

    シリーズを終えて

    静的サイトの書き換えから始まり、WordPressのDocker環境構築、GraphQLでのデータ取得、細かい不具合対応、デザインの調整、そしてブログ機能の追加まで、全4回で振り返ってきました。実務であまり触れる機会のないヘッドレスCMS構成を、自分のポートフォリオという実物を通して一通り経験できたのは、学習の題材として良かったと思っています。今後は「技術系」「読んだ本の感想」の記事を少しずつ増やしていく予定です。

  • ポートフォリオサイトをヘッドレスWordPress+Next.jsで作り直した話 (3) Next.js実装編

    シリーズ3回目です。今回はNext.js側の実装と、そのなかで実際に踏んだ不具合について書きます。

    データ取得の流れ

    WordPress側にWPGraphQLでAPIを用意したので、Next.js側はそれを叩くだけ…なのですが、クエリを文字列のまま書くとレスポンスの型が付かず補完も効きません。そこで GraphQL Codegen を導入し、次のような流れでデータを取得しています。

    // src/lib/queries/projects.ts
    export const GET_PROJECTS = graphql(/* GraphQL */ `
      query GetProjects {
        projects(first: 100) {
          nodes {
            id
            title
            content
            uri
            featuredImage { node { sourceUrl altText } }
            projectCategories { nodes { name slug } }
            projectDetail { role period toolsused }
          }
        }
      }
    `);
    

    graphql() タグでクエリを書いておき、npm run codegen を実行すると、クエリごとに型安全な戻り値の型が自動生成されます。ACFのフィールドを追加・変更してWordPress側のスキーマが変わった場合も、コマンド一発で型を追従させられるのが便利なところです。あとはこれを Server Component の中で await して呼び出すだけなので、データ取得部分はシンプルに書けました。

    GraphQLクエリからCodegen、Server Component、レンダリングまでのデータフロー

    ハマった不具合: 日本語スラッグが404になる

    実装を進めるなかで一番手こずったのが、実績の詳細ページが軒並み404になるという不具合でした。原因を辿ってみると、WordPress側で実績のスラッグ(URLの末尾部分)を日本語のまま(例:「wordpressオリジナルテーマ作成」)にしていたことが原因でした。Next.jsの動的ルート([slug]/page.tsx)がURLからパラメータを受け取る際、環境によってスラッグがパーセントエンコードされたまま渡ってくることがあり、WPGraphQL側の nodeByUri がそれをうまく解決できずにnullを返していた、というのが実態です。

    対処としては、実績のスラッグをすべて英数字(ローマ字)にリネームしたうえで、念のためNext.js側でも decodeURIComponent(params.slug) を挟むようにしました。

    const decodedSlug = decodeURIComponent(params.slug);
    const uri = `/projects/${decodedSlug}/`;
    const project = await getProjectByUri(uri);
    

    この不具合については、原因調査から検証までをもう少し詳しく別記事にまとめてあります。よければあわせてどうぞ。

    日本語スラッグの投稿がNext.jsで404になった話 →

    今回のまとめ

    Codegenのおかげでデータ取得部分は型安全に保てましたが、「URLエンコーディング」のような地味な足回りの部分は結局手を動かして初めて気づく類の問題でした。次回は、デザインをもとのサイトに近づける調整と、このブログ機能の追加について書きます。

  • ポートフォリオサイトをヘッドレスWordPress+Next.jsで作り直した話 (2) WordPress構築編

    「サイト制作の流れ」シリーズ2回目です。前回は全体の設計方針を書いたので、今回は実際にWordPress側をどう構築したかをまとめます。

    Docker Composeでローカル環境を用意する

    まず、ローカル開発用にDocker ComposeでWordPress環境を用意しました。db(MySQL)とwordpress(WordPress本体)の2コンテナ構成にしています。

    services:
      db:
        image: mysql:8.0
        environment:
          MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
          MYSQL_DATABASE: ${MYSQL_DATABASE}
        volumes:
          - db_data:/var/lib/mysql
    
      wordpress:
        image: wordpress:latest
        depends_on:
          - db
        ports:
          - "8080:80"
        volumes:
          - wordpress_data:/var/www/html
          - ./wp-content:/export/sd220/www/jp/r/e/gmoserver/3/2/sd1108332/cms.kisaku.site/wordpress-6.2.2-ja-jetpack_webfont-undernavicontrol/wp-content
    

    ポイントは volumes の分け方です。WordPress本体(core)は named volume に置いたままにして、wp-content だけをホスト側にバインドマウントしています。こうしておくと「コア本体の更新はコンテナにお任せ、プラグイン・テーマ・カスタムコードだけ手元のファイルとしてGit管理する」という役割分担がしやすくなります。

    Docker構成とWordPress+ACF+WPGraphQLのスタック図

    カスタム投稿タイプで「実績」「スキル」を作る

    標準の「投稿」をそのまま使うのではなく、実績用に project、スキル用に skill というカスタム投稿タイプを用意しました。それぞれにカテゴリ用のタクソノミー(project_category, skill_category)も追加しています。標準の投稿は今回作ったブログ用にそのまま使う形にしました。

    ACFでカスタムフィールドを持たせる

    実績には「役割(role)」「期間(period)」「使用技術(toolsused)」「外部URL」、スキルには「習熟度(level)」といった、投稿本文だけでは表現しづらい構造化データをACF(Advanced Custom Fields)のフィールドグループとして追加しました。使用技術は本来リピーターフィールドで持たせたいところですが、リピーターはACF Proの機能なので、今回は「HTML、CSS、JavaScript」のように読点区切りのテキスト1本で保存し、フロントエンド側で配列に分解する方式にしています。

    WPGraphQLでAPI化する

    WordPressの管理画面から入力したデータをNext.js側から取得できるように、WPGraphQL と WPGraphQL for ACF の2つのプラグインを導入しました。これにより、投稿タイプやACFフィールドがそのままGraphQLのスキーマに反映され、/graphql エンドポイント経由でJSON形式のデータとして取得できるようになります。管理画面にGraphiQL IDEという画面が追加されるので、実際にNext.js側のコードを書く前に、ここでクエリが正しく書けるか確認しながら進められるのも便利でした。

    次回は、このAPIをNext.js側からどう呼び出しているか、そして実装中に実際にハマった不具合について書きます。

  • ポートフォリオサイトをヘッドレスWordPress+Next.jsで作り直した話 (1) 企画・設計編

    このブログを含む「KiSAKU Portfolio」を、静的なHTMLサイトから ヘッドレスWordPress + Next.js という構成に作り直しました。せっかくなので、企画から実装、デザイン調整までの流れを何回かに分けて記事にしていこうと思います。今回はその1回目、「なぜこの構成にしたか」という設計の話です。

    もとのサイトの課題

    もとのサイトは素のHTML/CSS/JSで書かれた静的サイトでした。表示は軽快でしたが、実績を1件追加するにもHTMLを直接編集してデプロイし直す必要があり、正直そこそこ面倒でした。文章の言い回しを直したいだけなのに、わざわざエディタでタグを探す…というのを繰り返すうちに、「更新のしやすさ」を持ち込みたくなりました。

    加えて、個人的な学習目的も大きな理由でした。普段の実務では見る機会が少ない「ヘッドレスCMS」や「GraphQL」「Next.jsのApp Router」を実際に手を動かして試してみたい、というのが今回のリニューアルの裏テーマです。

    なぜ「ヘッドレスWordPress」なのか

    更新のしやすさだけなら普通にWordPressのテーマを作ればいい話ですが、あえてヘッドレス(フロントエンドとバックエンドを分離する)構成にしたのは、次の2点が理由です。

    ひとつは、管理画面(投稿・カスタムフィールドの入力)にはWordPressの使いやすさをそのまま活かしつつ、表示側は自由に作りたかったこと。もうひとつは、Next.jsのサーバーコンポーネントやApp Routerといった今どきのフロントエンド技術を、実際の題材で試したかったことです。

    静的サイトからヘッドレスWordPress+Next.js構成への移行イメージ

    採用した構成

    最終的に、次のような構成に落ち着きました。

    • バックエンド: WordPress(Docker上のローカル環境) + ACF(Advanced Custom Fields) + WPGraphQL
    • フロントエンド: Next.js(App Router, TypeScript)
    • データの受け渡し: GraphQL(WPGraphQLが公開するエンドポイントに、Next.jsのServer Componentから直接問い合わせる)

    実績(project)やスキル(skill)は標準の「投稿」とは別のカスタム投稿タイプとして用意し、それぞれ専用のカスタムフィールド(役割・期間・使用技術など)をACFで持たせています。この設計の詳細は次回の記事でまとめます。

    このシリーズで書くこと

    今回のリニューアル作業を、次の4回に分けて記録していきます。

    • (1) 企画・設計編 ← 今回
    • (2) WordPress構築編 – Docker環境構築、カスタム投稿タイプとACF、WPGraphQLの設定
    • (3) Next.js実装編 – データ取得の実装と、実際にハマった不具合(日本語スラッグが404になる問題)
    • (4) デザイン調整・ブログ機能追加編 – もとのサイトの見た目に近づける作業と、このブログ機能の追加

    次回はWordPress側の構築、カスタム投稿タイプとACF、WPGraphQLまわりの設定についてまとめます。

  • 日本語スラッグの投稿がNext.jsで404になった話

    ヘッドレスWordPress + Next.jsで実績ページ(/projects/[slug])を作っていたとき、一覧からリンクをクリックすると404になる不具合に遭遇しました。

    原因

    WordPress側の投稿スラッグを日本語のまま(例: 「wordpressオリジナルテーマ作成」)にしていたことが原因でした。一覧ページのリンクはブラウザによってURLエンコードされるため、実際のリンク先は次のようになります。

    /projects/wordpress%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E3%83%86%E3%83%BC%E3%83%9E%E4%BD%9C%E6%88%90

    Next.jsのApp Routerはこの値を自動でデコードしてくれると思い込んでいましたが、実行環境によってはparams.slugがエンコードされたまま渡ってくるケースがあり、WordPress側のGraphQL(nodeByUri)に渡すURIと文字列が一致せず、該当データが見つからない(=404)という結果になっていました。

    対処

    1. WordPress側の投稿スラッグをローマ字(例: wordpress-theme)に変更した(パーマリンクが読みやすくなる副次効果もある)
    2. 念のためNext.js側でもdecodeURIComponent(params.slug)を通してからGraphQLに渡すようにし、日本語スラッグの投稿が増えても壊れないよう防御的にした

    日本語タイトルの投稿を作るときは、パーマリンク欄でスラッグをローマ字に直す一手間を忘れないようにしたいです。

  • 「読んだ本の感想」カテゴリを始めます

    このカテゴリでは、仕事に関係する技術書から小説まで、読んだ本の感想を気軽に書き残していこうと思います。

    まずは箱だけ作りました。次回から実際に読んだ本の感想を投稿していきます。

  • ポートフォリオサイトをヘッドレスWordPress + Next.jsでリニューアルしました

    このサイトはWordPress(ヘッドレスCMS) + WPGraphQL + Next.js(App Router)という構成で作り直しました。管理画面で書いた記事や実績データを、GraphQL経由でNext.jsのフロントエンドが取得して表示しています。

    技術スタック: WordPress / WPGraphQL / ACF / Next.js / TypeScript / Tailwind CSS / Docker

    今後、このブログでは制作の記録や学習メモを発信していく予定です。