Zendesk Guide のセクションテンプレートで content_tags を表示する構成(Lambda + JS)

Zendesk Guide のセクションテンプレートで content_tags を表示する構成(Lambda + JS)

Zendesk Guide のセクションページでは、content_tags(コンテンツタグ)がテンプレート上で直接参照できません。本記事では、AWS Lambda と API Gateway を用いた Proxy API を構築し、JavaScript 経由で記事のタグを描画する構成を紹介します。

概要

本記事では、Zendesk Guide のセクションページに「コンテンツタグ(content tags)」を表示する方法について検証した内容を紹介します。

画像2

Zendesk の記事には「ラベル(label)」とは別に「コンテンツタグ(content tags)」という分類機構があります。これは、記事やコミュニティ投稿に一貫したタグ付けを行うことで、関連コンテンツを束ねたり、検索体験を向上させたりするための機能です。

しかし、テンプレートカスタマイズの観点から見ると、このコンテンツタグは意外とクセがあります。たとえば section_page.hbs(=特定セクション内の記事一覧を表示するテンプレート)では、各記事オブジェクトに content_tag_ids が含まれておらず、単純に {{#each section.articles}} でループしてもタグ情報を参照することはできません。この制約を回避するための方法としては、JavaScript で API を非同期に呼び出す方法が挙げられます。Zendesk API への認証が必要となるため、別途サーバーサイドの実装が必要です。

本記事ではその一例として、AWS Lambda を用いた Proxy API を活用し、テンプレート側でタグを描画する仕組みを紹介します。

画像3

対象読者

  • Zendesk Guide のカスタマイズを業務で担当しているエンジニアの方
  • セクションページなどに追加情報(タグ・属性)を表示したいが、テンプレート上で取得できず困っている方
  • AWS Lambda や API Gateway を用いて Zendesk API を拡張的に活用したい方

想定ユースケース

本構成は以下のような場面での活用を想定しています:

ユースケース 説明
リージョン・言語別の FAQ 管理 #jp, #us などのタグを記事に付与し、対象ユーザー層を明示
機能別ドキュメント分類 #API, #UI, #beta などをタグで表示し、視認性を高める
社内ナレッジのフィルタリング 「社内限定」「外部向け」などの情報分類を可視化したい場合

タグはあくまで「分類と強調表示」を目的とするため、Zendesk の「セクション」や「カテゴリ」とは補完関係にあります。
コンテンツの粒度や公開対象が増えてくると、こうしたタグによる補助的な構造が重要になってきます。

用語と構成の前提知識

用語 説明
content_tags Zendesk Guide Enterprise プランで利用可能なタグ分類機能。API 経由で記事との関連付けが可能
section_page.hbs Zendesk のテーマテンプレートの一部で、特定セクション内の記事一覧を描画するテンプレート
label_names 記事に付与可能なラベル(公開用キーワード)。テンプレートから直接参照可能だが、content_tagsとは用途が異なる
AWS Lambda サーバーレスで JavaScript/Node.js の処理を実行できるマネージドサービス
API Gateway HTTP 経由で Lambda を呼び出すためのエンドポイントを作成できる AWS サービス

Lambda を用いた Proxy API の構成と実装

クライアントサイドから Zendesk API を直接叩けない制約を回避するため、今回は AWS Lambda + API Gateway を用いた Proxy API を実装しました。Lambda は認証済みのバックエンドとして動作し、必要なタグ情報を取得してフロントエンドに返す役割を担います。

使用する API(2段階構成)

この構成では、Zendesk API の2つのエンドポイントを順番に呼び出す必要があります。

第1段階:記事から content_tag_ids を取得

GET /api/v2/help_center/articles/:id.json

レスポンス例(抜粋):

{
  "article": {
    "id": 123456789,
    "title": "テンプレート:よくある質問",
    "content_tag_ids": [112233, 445566]
  }
}

第2段階:タグ ID からタグ名を取得

GET /api/v2/guide/content_tags/:id.json

レスポンス例:

{
  "content_tag": {
    "id": 112233,
    "name": "jp"
  }
}

Lambda 実装例

検証では AWS Lambda を Node.js 22.x で実装し、API Gateway 経由で HTTPS リクエストを受け取れるよう構成しています。トークンによる Basic 認証の処理や、非同期 API 呼び出しのハンドリングを行うだけのシンプルな設計です。

検証環境

  • ランタイム : Node.js 22.x
  • ライブラリ : node-fetch@2
  • 環境変数で以下を定義:
環境変数 用途
ZENDESK_DOMAIN 例: yourcompany.zendesk.com
ZENDESK_EMAIL API 認証用メールアドレス(/token)
ZENDESK_API_TOKEN Zendesk API トークン

Lambda コード(index.js)

実装の全体像としては、リクエストパラメータから article_id を受け取り、Zendesk の記事情報 API → タグ情報 API を順に呼び出し、タグ名のリストを JSON として返却するという処理です。以下がそのサンプルコードです。

const fetch = require("node-fetch");

const ZENDESK_DOMAIN = process.env.ZENDESK_DOMAIN;
const ZENDESK_EMAIL = process.env.ZENDESK_EMAIL;
const ZENDESK_API_TOKEN = process.env.ZENDESK_API_TOKEN;

exports.handler = async (event) => {
  const articleId = event.queryStringParameters?.article_id;
  if (!articleId) {
    return { statusCode: 400, body: "Missing article_id" };
  }

  const authHeader = "Basic " + Buffer.from(`${ZENDESK_EMAIL}:${ZENDESK_API_TOKEN}`).toString("base64");

  try {
    const articleRes = await fetch(`https://${ZENDESK_DOMAIN}/api/v2/help_center/articles/${articleId}.json`, {
      headers: { Authorization: authHeader }
    });

    const articleJson = await articleRes.json();
    const tagIds = articleJson.article?.content_tag_ids || [];

    const tagNames = await Promise.all(tagIds.map(async (id) => {
      const res = await fetch(`https://${ZENDESK_DOMAIN}/api/v2/guide/content_tags/${id}.json`, {
        headers: { Authorization: authHeader }
      });
      const json = await res.json();
      return json.content_tag?.name;
    }));

    return {
      statusCode: 200,
      body: JSON.stringify({ tags: tagNames.filter(Boolean) }),
      headers: { "Access-Control-Allow-Origin": "*" }
    };
  } catch (err) {
    console.error("タグ取得失敗:", err);
    return { statusCode: 500, body: JSON.stringify({ error: "Internal error" }) };
  }
};

動作確認用 curl コマンド

curl -X GET \
  'https://your-api-id.execute-api.ap-northeast-1.amazonaws.com/default/zendeskContentTagProxy?article_id=123456789'

レスポンス例:

{ "tags": ["jp", "beta"] }

この Lambda 関数が動作していれば、次にクライアント側で fetch() によってこの API を呼び、DOM にタグを描画することが可能になります。

セクションテンプレートにタグを描画する JavaScript の実装

Proxy API の準備ができたら、次は section_page.hbs から呼び出される script.js を編集して、実際にタグを描画していきます。本構成では、各記事タイトルの横に #jp#beta などのタグを表示することを目指します。

1. テンプレート側:article_id を data 属性として埋め込む

以下のように、各 <li> 要素に data-article-id="{{id}}" を追加しておきます。

<ul class="article-list">
  {{#each section.articles}}
    <li class="article-list-item" data-article-id="{{id}}">
      <a href="{{url}}" class="article-list-link">{{title}}</a>
    </li>
  {{/each}}
</ul>

2. JavaScript の実装:タグを取得して描画

セクションページが読み込まれた後、JavaScript で各記事の data-article-id を取得し、Lambda 経由でタグ情報を取得します。取得したタグ名は DOM に挿入し、記事タイトルの直後に表示されるようにします。

document.addEventListener("DOMContentLoaded", async () => {
  const items = document.querySelectorAll(".article-list-item");

  for (const item of items) {
    const articleId = item.getAttribute("data-article-id");
    if (!articleId) continue;

    try {
      const res = await fetch(
        `https://your-api-id.execute-api.ap-northeast-1.amazonaws.com/default/zendeskContentTagProxy?article_id=${articleId}`
      );
      const data = await res.json();
      const tags = data.tags || [];

      if (tags.length > 0) {
        const tagContainer = document.createElement("span");
        tagContainer.classList.add("tag-list");

        tags.forEach((tag) => {
          const span = document.createElement("span");
          span.classList.add("tag");
          span.textContent = `#${tag}`;
          tagContainer.appendChild(span);
        });

        const link = item.querySelector(".article-list-link");
        if (link) {
          link.insertAdjacentElement("afterend", tagContainer);
        }
      }
    } catch (e) {
      console.error(`タグ取得失敗(article_id=${articleId}):`, e);
    }
  }
});

3. スタイリング(任意)

タグ表示が見やすくなるよう、以下のような簡単なスタイルを追加しておくと便利です。

.tag-list {
  margin-left: 8px;
  display: inline-flex;
  gap: 4px;
}

.tag {
  font-size: 12px;
  color: #666;
  background-color: #eee;
  padding: 2px 6px;
  border-radius: 4px;
}

4. 注意点・補足

  • fetch() の呼び出しは記事ごとに個別実行されるため、記事数が多いと並列アクセスが発生します。

    • 必要に応じてキャッシュ機構や Promise.allSettled() を使った並列制御も検討してください。
  • クライアントサイドで描画されるため、JavaScript 無効時はタグが表示されません

  • content_tags が使用可能な料金プランについては別途ご確認ください。

まとめ

本記事では、Zendesk Guide のセクションページに記事ごとの「コンテンツタグ(content tags)」を表示する構成を紹介しました。

デフォルトのテンプレートでは content_tag_ids が展開されないため、タグ情報を取得するには JavaScript + Zendesk API の組み合わせが不可欠です。
しかし、Zendesk API の呼び出しには認証が必要なため、クライアントから直接取得することはできません。

この制約を解決するため、AWS Lambda を用いた Proxy API を中継サーバーとして構築し、テンプレート側から非同期にタグ情報を取得して表示する方法を取りました。

本構成のポイント

要素 説明
Lambda + API Gateway Zendesk API を代理で呼び出す Proxy API を構築し、認証をサーバー側で管理
クライアント JS section.articles の各記事 ID をもとにタグ情報を取得して DOM に描画
非同期処理 JavaScript によって複数記事に対する API 呼び出しを並列処理
セキュリティ配慮 CORS 対策および API 認証情報の秘匿をサーバー側で完結
スタイリング タグ表示に CSS クラスを用いることで、見やすさやアクセントを追加可能

今後の展開・検討ポイント

  • タグのクリックで絞り込みを行う構成(例:タグをクリックすると https://support.example.com/hc/ja/sections/1234567890-FAQ?tag=jp に遷移し、該当タグを含む記事のみを絞り込んで表示)
  • content_tags のキャッシュ構造の導入(記事数が多い場合の最適化)
  • Proxy サーバーの運用管理・監視体制

おわりに

Zendesk Guide のカスタマイズでは、公式テンプレートの制約をうまく乗り越えていく必要があります。
今回のように、「直接取得できない情報は API 経由で補完し、描画はクライアントで行う」 というパターンは、他の用途でも応用しやすい汎用的なアプローチです。

本構成が、Zendesk カスタマイズに取り組む方の参考になれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.