将最新帖子预告嵌入到你的网站

我们需要将内容从我们的 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 标记部分,因为它很可能需要根据您网站的标记结构进行自定义。

祝您使用愉快!

致谢 @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 个赞