Zendesk ヘルプセンターのサイドバーに、カテゴリ、セクション、記事一覧を表示する方法

# これは何？
Zendeskのヘルプセンターのカスタマイズに関する記事です。
以下２つを書いています。
1. カテゴリページと検索結果ページで、カテゴリ一覧を表示する方法
2. セクションページ、記事ページで、上位カテゴリのセクションと記事一覧を表示する方法

Zendesk Guideは簡単にサポートサイトを構築できるサービスですが、
良い意味で制約があり、これができないのか...というところがちょいちょいあったりします。

その中でも、わりと上位にあると考えられるのが今回の内容かと思いますので、qiitaに残します。
なお、本画面のスクショは、実際に提供しているSaaSのヘルプセンターの画像です。

# 前提知識
- html、css、javascriptの知識が多少ある方

# 本記事に書いてあること
## 1：（上位カテゴリの）セクションと記事一覧を表示する
セクションページと記事ページで、上位カテゴリ内のセクションと記事一覧を表示します。
実際の表示イメージはこちらです。記事ページとセクションページで、同じ内容を表示しています。

![イメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30859/fb670a22-f89f-1b75-4f0a-635933b8cd84.jpeg)

## 2：カテゴリページで、カテゴリ一覧を表示する
カテゴリページで、カテゴリカテゴリ一覧を表示しています。
カテゴリ一覧だけですが、ソースコード内のセクションも合わせて表示できるようにしています。
![スクリーンショット_2022-05-16_0_46_12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30859/ba29f3ce-ec4a-2f01-b240-52f7840f4b78.jpeg)


# 参考にした記事（というか、流用に近い...
本記事に書いてある内容は、以下の記事を相当参考にさせていただいています。。感謝！！！！ありがとうございます！ありがとうございます！
本記事では、コードの詳細は詳しく記載しませんので、以下の記事を必ず併せてご覧ください。
表示を早くさせるために工夫したり、非公開の記事を表示させないようにするなどの制御が入っており、その説明の記載があります。

**Zendesk Guideでカテゴリ内のArticle一覧を左メニューに出力するようにカスタマイズする**
https://blog.torut.tokyo/entry/2018/03/04/012913

# ざっくりとした仕組み
表示するデータ(カテゴリ/セクション/記事)は、Zendesk APIから取得します。
Javascriptを使いAPIから必要なデータを取得し、その内容を表示します。

対象のhbsファイルに下記コードを入れることで、下の階層にjavascriptでhtmlが挿入されます。
```
<div class="nav-category-contents"></div>
```

# （上位カテゴリの）セクションと記事一覧を表示する方法
## 対象ファイル
記事ページ　article_page.hbｓ
セクションページ　section_page.hbs

## javascript
```
$(document).ready(function() {
  if(document.URL.match(/\/sections\/|\/articles\//)) {
    var category_id = $(".breadcrumbs-wrapper li:nth-child(2) a").attr("href").match(/[0-9]+/);
    var locale = window.location.pathname.split('/')[2];

    $('.nav-category-contents').append('<div class="js-loading">loading...</div>');

    var Zendesk = {
      sections: function (category_id) {
        var defer = $.Deferred();
        $.ajax({
          url: "/api/v2/help_center/" + locale + "/categories/" + category_id + "/sections.json?sort_by=position&include=translations",
          type: "GET",
          localCache: true,
          cacheTTL: 24,
          cacheKey: locale + category_id,
          dataType: 'json',
          success: defer.resolve,
          error: defer.reject
        });
        return defer.promise();
      },
      articles: function (section_id) {
        var defer = $.Deferred();
        $.ajax({
          url: "/api/v2/help_center/" + locale + "/sections/" + section_id + "/articles.json",
          type: "GET",
          localCache: true,
          cacheTTL: 24,
          cacheKey: locale + section_id,
          dataType: 'json',
          success: defer.resolve,
          error: defer.reject
        });
        return defer.promise();
      }
    };

    Zendesk.sections(category_id).done(function (category) {
      $.each(category.sections, function (i, v) {
        // Section is hidden?
        var hidden = true;
        v.translations.filter(function (translation, index) {
          if (translation.locale == locale && translation.hidden == true) {
            hidden = true;
          } else if (translation.locale == locale && translation.hidden == false) {
            hidden = false;
          }
        });
        if (hidden) return true;

        $('.js-loading').remove();

        $('.nav-category-contents').append('<div class="nav-category-title" id=' + v.id + '><a  class="nav-category-title-link" href=' + v.html_url + '">' + v.name + '</a></div>');

        Zendesk.articles(v.id).done(function (section) {
          var nesting = $("<ul>");
          $.each(section.articles, function (j, x) {
            if (x.draft) {
              return true;
            }
            nesting.append('<li class="nav-section-item" id=' + x.id + '><a href=' + x.html_url + ' class="nav-section-link ' + (x.html_url == window.location ? "current-article" : "") + '">' + x.name + '</a></li>');
          });
          $('.nav-category-title#' + v.id).after(nesting);
        });
      });
    });
  }
});
```


# カテゴリページと検索結果ページで、カテゴリ一覧を表示する

## 対象ファイル
カテゴリページ　category_page.hbｓ
検索結果ページ　search_results.hbs

## javascript
```
$(document).ready(function() {
// For Articles in Category
  if(document.URL.match(/\/categories\/|\/search/)) {
    var locale = window.location.pathname.split('/')[2];

    $('.nav-category-contents').append('<div class="js-loading">loading...</div>');

    var Zendesk = {
      categories: function () {
        var defer = $.Deferred();
        $.ajax({
          url: "/api/v2/help_center/" + locale + "/categories.json",
          type: "GET",
          localCache: true,
          cacheTTL: 24,
          cacheKey: locale,
          dataType: 'json',
          success: defer.resolve,
          error: defer.reject
        });
        return defer.promise();
      },
      sections: function (category_id) {
        var defer = $.Deferred();
        $.ajax({
          url: "/api/v2/help_center/" + locale + "/categories/" + category_id + "/sections.json?sort_by=position",
          type: "GET",
          localCache: true,
          cacheTTL: 24,
          cacheKey: locale,
          dataType: 'json',
          success: defer.resolve,
          error: defer.reject
        });
        return defer.promise();
      }
    };

    Zendesk.categories().done(function (categories) {
      $.each(categories.categories, function (i, v) {

        $('.js-loading').remove();

        $('.nav-category-contents').append('<div class="nav-category-title" id=' + v.id + '><a  class="nav-category-title-link" href=' + v.html_url + '">' + v.name + '</a></div>');

        // セクションを表示する
        // Zendesk.sections(v.id).done(function (section) {
        //   var nesting = $("<ul>");
        //   $.each(section.sections, function (j, x) {
        //     nesting.append('<li class="nav-section-item" id=' + x.id + '><a href=' + x.html_url + ' class="nav-section-link ' + (x.html_url == window.location ? "current-article" : "") + '">' + x.name + '</a></li>');
        //   });
        //   $('.nav-category-title#' + v.id).after(nesting);
        // });
      });
    });
  }
});
```

# 補足事項
サイトによって調整が必要な部分は、javascriptでデータを取得した後のhtmlを挿入するところですね。
他はわりとそのまま使えるのではと思います。