最新の投稿 teaser をあなたのウェブサイトに埋め込む

Discourse フォーラム(labs.daemon.com.au)のコンテンツを、当社の公開ウェブサイト(www.daemon.com.au/labs)に動的に読み込む必要がありました。

コードは、Discourse から選択されたカテゴリの最新コンテンツを取得し、当社のウェブサイトに適合するマークアップでラップしてからページに挿入します。その後、コードをより汎用的にするためのいくつかの変更を加え、異なる Discourse フォーラムからのコンテンツを異なるウェブサイトに読み込む際に簡単に再利用できるようにしました。

Discourse フォーラムには多数のデータエンドポイントが存在します。例えば、最新トピック にアクセスすると、そのページに必要なデータを返す latest.json エンドポイントが読み込まれます。これにより、Discourse のコンテンツを独自のウェブサイトで表示することが可能になります。

開始前に

Discourse からリモートでコンテンツを読み込むには、Discourse のエンドポイントを当社のウェブサイトから利用可能にする必要があります。これは Discourse の「管理」設定で行うことができます。

管理者権限を持つアカウントで Discourse にログインし、「管理」パネルの「設定」タブに移動します。

左側のナビゲーションから「セキュリティ」を見つけてください。その後、右側の「cors origins」フィールドを探します。Discourse のコンテンツを表示するウェブサイトの URL をこのフィールドに追加します(今回の場合:http://www.daemon.com.au/)。変更を保存してください。

エンドポイント

Discourse は無数のデータエンドポイントを生成するため、リモートで表示したいコンテンツに応じて適切なエンドポイントを見つけることが重要です。カテゴリページの URL の末尾に /l/latest.json を追加すると、そのカテゴリの最新投稿を含むエンドポイントが表示されます。例えば、https://labs.daemon.com.au/c/design/l/latest.jsonhttps://labs.daemon.com.au/c/design のエンドポイントです。

HTML & JavaScript

必要なエンドポイントが揃ったので、次にサイトがそのエンドポイントを読み取れるようにし、有用な情報を取得して正しく表示できるようにします。この例では、「デザイン」カテゴリからユーザー #1、#2、#3 のいずれかが投稿した最新の 3 件の投稿を、当社のサイトの #div 内に表示することを目指します。また、「デザインカテゴリについて」の投稿は表示しないようにします。

参考:この例では、デモ用に必要なスタイルを提供するため、デフォルトの Bootstrap v4.0.0-beta.2 を使用していますが、使用は完全に任意です。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta content="ie=edge" http-equiv="x-ua-compatible">
    <meta content="initial-scale=1.0, shrink-to-fit=no, width=device-width" name="viewport">
    <title>Discourse 埋め込み</title>

    <!-- デモ用の基本スタイルのための Bootstrap CSS -->
    <link crossorigin="anonymous" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" rel="stylesheet">
  </head>
  <body>
    <div class="container">
      <div class="card-deck" id="div"></div>
    </div>

    <!-- jQuery -->
    <script crossorigin="anonymous" integrity="sha384-p7RDedFtQzvcp0/3247fDud39nqze/MUmahi6MOWjyr3WKWaMOyqhXuCT1sM9Q+l" src="https://code.jquery.com/jquery-3.2.1.js"></script>

    <!-- JavaScript -->
    <script>
      (function ($) {
        'use strict'

        $(function () {
          $.ajax('https://labs.daemon.com.au/c/design/l/latest.json').then(function (result) {
            // Discourse からコンテンツを生成するためにデータを解析:
            // * Discourse エンドポイント、つまり `result`、
            // * サイトに表示する投稿数、例:`3`、
            // * オプションのユーザー ID 配列(ホワイトリスト)
            //   サイトに表示したい投稿が特定のユーザーによって投稿されたものに限られる場合、例:`[1, 2, 3]`。
            console.log(result);
            $('#div').discourse(result, 3, [1, 2, 3]);
          });

          $.fn.discourse = function (feed, numToShow, whitelist) {
            var feedLength = feed.topic_list.topics.length;

            // 表示する投稿が十分にあるか確認します。
            if (numToShow > feedLength) {
              numToShow = feedLength;
            }

            for (var i = 0; i < numToShow; i++) {
              var content = '';

              // Discourse エンドポイント内の URL はすべて相対 URL(例:topic.image_url)です。
              // サイトに表示されるリンクが正しい場所を指すようにするためにこれが必要です。
              // お使いの Discourse フォーラムの URL に変更してください。
              var discourseURL = 'http://labs.daemon.com.au/';

              // Discourse 投稿データの用変数。
              var post          = feed.topic_list.topics[i],
                  postAuthor    = post.posters[0].user_id,
                  postDate      = new Date(post.created_at),
                  postLink      = discourseURL + 't/' + post.slug + '/' + post.id,
                  postThumbnail = discourseURL + post.image_url;

              // ホワイトリストが存在する場合、投稿者が検証済みユーザーか確認します。
              if (typeof whitelist !== 'undefined') {
                var verifiedUser = false;

                for (var n = 0; n < whitelist.length; n++) {
                  if (postAuthor === whitelist[n]) {
                    verifiedUser = true;
                    break;
                  }
                }

                // 投稿者がホワイトリストに含まれていない場合、
                // この反復処理を中断し、ループ内の次の反復処理に進みます。
                if (!verifiedUser) {
                  // 可能な場合、表示する投稿数を増やして
                  // 除外された投稿を補います。
                  if (numToShow < feedLength) {
                    numToShow++;
                  }

                  continue;
                }
              }

              // 以下のコードブロックはオプションです。
              // 「X カテゴリについて」の投稿を無視する目的です。
              // サイトに表示したくない場合があるためです。
              if (post.title.substring(0, 10) === "About the " && post.title.substring(post.title.length - 9) === ' category') {
                // 可能な場合、表示する投稿数を増やして
                // 除外された投稿を補います。
                if (numToShow < feedLength) {
                  numToShow++;
                }

                continue;
              }

              // 投稿にサムネイルがない場合、
              // デフォルトのプレースホルダー画像をその投稿のサムネイルとして使用します。
              // サイトのプレースホルダー画像を使用するように変更してください。
              if (post.image_url === null) {
                postThumbnail = 'http://placehold.it/320x180';
              }

              // サイト用の HTML を生成します。
              // このコード部分は、サイトのマークアップに合わせて
              // 必要に応じて変更する必要がある場合があります。
              content += '<div class="card" style="max-width: 20rem;">';
                content += '<img alt="' + post.fancy_title + '" class="card-img-top" src="' + postThumbnail + '">';
                content += '<div class="card-body">';
                  content += '<h4 class="card-title">' + post.fancy_title + '</h4>';
                  content += '<p class="card-text"><small>' + postDate.getDate() + '/' + postDate.getMonth() + '/' + postDate.getFullYear() + '</small></p>';
                  // 以下の行は、抜粋をそのまま表示するだけでなく、
                  // 抜粋内の `<a>` タグを `<em>` タグに置き換えるため、
                  // サイト上でリンクとして表示されないようにします。
                  // これはオプションですが、特定の状況下では必要になる場合があります。
                  content += '<p class="card-text">' + post.excerpt.replace(/<a/g, '<em').replace(/<\/a/g, '</em') + '</p>';
                  content += '<a href="' + postLink + '">続きを読む</a>';
                content += '</div>';
              content += '</div>';

              $(this).append(content);
            }
          };
        });
      }(jQuery));
    </script>
  </body>
</html>

完成例

この JavaScript は汎用性が高く、異なるウェブサイトで再利用できます。ただし、ご自身のニーズに合わせて一歩一歩調整することをお勧めします。特に HTML マークアップ部分は、お持ちのサイトのマークアップに合わせてカスタマイズする必要がある可能性が非常に高いです。

お楽しみください!

h/t @sesemaya Embed latest topics from Discourse on your website - development - Daemon Labs

「いいね!」 18

I have to say thanks for this how-to; it was very helpful in getting started on our own implementation and I wanted to share our version back with the community for future reference. I slightly refactored your code to better fit our needs and we’re using Mustache templates to handle the markup more flexibly.

Our actual implementation is rather different, but I’ve published a pen of your original demo built with our model:

N.B.
The included API key is for a temporary TL0 user to enable access as our instance has login required while it’s under development

「いいね!」 4