別のサイトにDiscourseトピックのリストを埋め込む

Discourse の最新ビルドを取得すれば、簡単な JavaScript と HTML を使って、他のサイトにトピック一覧を 埋め込む機能 が利用可能になります。

この機能の一般的なユースケースは、ブログやコンテンツ中心のサイトなどです。画面のサイドにトピック一覧を表示するウィジェットを配置したい場合に便利です。カテゴリ、タグ、または 他の公開されている フィルタオプションのいずれかで絞り込むことができます。

トピック一覧の埋め込み方

まず、embed topics list サイト設定を有効にする必要があります。

次に、HTML に Discourse のトピックを埋め込むために必要な JavaScript を含む <script> タグを追加します。これは通常スクリプトを追加する場所であればどこでも構いません。例:

<script src="http://URL/javascripts/embed-topics.js"></script>

URL は、サブフォルダがある場合はそれを含めたフォーラムのアドレスに置き換えてください。

その後、HTML ドキュメントの <body> 内に、埋め込みたいトピック一覧を示す d-topics-list タグを追加します。ここでも URL をベース URL に置き換える必要があります。

<d-topics-list discourse-url="URL" category="1234" per-page="5"></d-topics-list>

discourse-url(必須)を除く、指定したすべての属性はトピック検索のクエリパラメータに変換されます。したがって、タグでトピックを検索したい場合は、以下のように記述できます。

<d-topics-list discourse-url="URL" tags="cool"></d-topics-list>

クエリパラメータにアンダースコアが含まれている場合は、ダッシュに変換してください。上記の例では、per_pageper-page になっていることに気づかれたかもしれません。

SameSite コンテキスト(つまり、埋め込みサイトとフォーラムが親ドメインを共有している場合)では、Discourse はフォーラムにログインしているかどうかを認識し、その結果を適切に表示します。ログイン時にセキュリティが設定されたカテゴリなどが表示されても驚かないでください。匿名ユーザーには表示されません。

パラメータ一覧

template: complete または basic(デフォルト)。basic はトピックタイトルのリストのみですが、complete はタイトル、ユーザー名、ユーザーのアバター、作成日時、トピックのサムネイル画像を含みます。

per-page: 数値。返すトピックの数を制御します。

category: 数値。トピックを単一のカテゴリに制限します。対象カテゴリの id を指定してください。

allow-create: ブール値。有効にすると、埋め込み部分に「新規トピック」ボタンが表示されます。

tags: 文字列。指定したタグに関連付けられたトピックに制限します。

top_period: all, yearly, quarterly, monthly, weekly, daily のいずれか。有効にすると、その期間の「人気」トピックを返します。

ここにサンプルサイトを作成しました。

https://embed.eviltrout.com

ブラウザでソースを表示してコードを確認できるほか、ソース全体も GitHub にあります。

これは非常に新しい機能ですので、フィードバックや要望をお待ちしています。

リストのスタイリング

既存のテーマ機能を使用して、埋め込みリストにカスタムスタイルを追加できます。

例えば、デフォルトでは complete テンプレートを使用する埋め込みリストは以下のようになります。

これを例えばグリッドのように表示したい場合は、テーマ > Common > Embedded CSS にカスタム SCSS を追加します。

.topics-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  
  .topic-list-item { 
    .main-link {
      border: 1px dotted gray;
      padding: 0;
    }
  
    .topic-column-wrapper {
      flex-direction: column-reverse;
      
      .topic-column.details-column {
        width: 100%;
      }
        
      .topic-column.featured-image-column .topic-featured-image img {
        max-width: initial;
        max-height: initial;
        width: 100%;
      }
    }
  }
}

これにより、以下のように表示されます。

「いいね!」 95

みなさん、こんにちは!リンクを新しいタブで開けるようにしたいと考えています(target=“_parent” ではなく target=“_blank” にする)。iframe を使っている場合、簡単に実現する方法はありますか?

「いいね!」 2

求めているものかどうかはわかりませんが、このような方法であれば、リンクを新しいタブで開くことができます。外部ドメインでは CORS が有効になっている必要があります。ピン留めされたトピックを除外したかったので、この方法で試しました。

// `fetch` にはポリフィルが必要になる場合があります
const targetEl = document.getElementById("forumTopics");

function renderTemplate(topicsArr) {
    const items = topicsArr.map(
        (topic) => `<li><a href="${topic[1]}" target="_blank">${topic[0]}</a></li>`
    );

    targetEl.innerHTML = `<ul>${items.join("\n")}</ul>`;
}

// トピックリストの末尾に `.json` を追加
fetch("https://forum.example.com/latest.json")
    .then((res) => res.json())
    .then((json) => {
        const topics = json.topic_list.topics
            .slice(1, 6)
            .map((t) => [
                t.title,
                `https://forum.example.com/t/${t.slug}/${t.id}`,
            ]);

        renderTemplate(topics);
    });
「いいね!」 3

ありがとうございます!このアイデアは気に入っていますが、こちらの投稿 What are the risks of enabling Cross-origin resource sharing (DISCOURSE_ENABLE_CORS) を踏まえると、CORSを有効にするのは最善の策ではないと考えています。

「いいね!」 2

信頼できるサイトに対してのみ CORS を有効にするべきです。すべてのソースに対して CORS を有効にすると、その目的が損なわれてしまいます。

「いいね!」 6

CORS は、私が管理している他のサイトに対してのみ有効化しています。目的は、フロントエンドのコードを使って、他のサイトでフォーラムのトピック一覧を読み込むことでした。その方法は、ランダムなサイトが投稿を埋め込むことを許可するためにはおそらく機能しないでしょう。

編集: そのコードをコピー/ペーストする際は、.slice(1, 6) に注意してください。これによりトピックの 1 つが削除されてしまいます(おそらく、削除したかった固定トピックだったと思います)。

「いいね!」 3

いいですね、それなら試してみましょう。今はテスト中なので、localhost 以外のサイトを持っていません。そのため、追加するのにためらっていました。でも、場所を持っている人を見つけられれば、試してみることができます。お手伝いいただき、ありがとうございます!

「いいね!」 4

こんにちは @j127 さん

現在、同じ問題に直面しており、リンクを新しいタブで開きたいと考えています。
簡単な質問です。

提供されたコードをどこに配置すればよいでしょうか?

@eviltrout さん、私の場合、CSS スタイルが表示されない理由がわかる方はいますか?

「いいね!」 2

そのコードは一般的なアイデアを簡潔に示す例にすぎません。fetchすべてのブラウザで動作するとは限りません と思います。必要であれば ES5 で書き直すこともできます。

あなたのサイトは WordPress でしょうか、それともヘッドレス WordPress のようなものですか?

「いいね!」 4

すべての_モダン_なブラウザで動作しているようですが、Discourse はもはや IE11 をサポートしていません。

「いいね!」 4

私のサイトはヘッドレスではなく、通常の WordPress です。

「いいね!」 1

この機能を使って、別の Discourse インスタンスにトピックのリストを埋め込むことはできますか?それとも、より賢明な方法があるでしょうか?

私のユースケースは、将来的にこれら 2 つのインスタンスを統合するまでの一時的な措置として、2 つのインスタンス間の「ブリッジ」を構築することです。これを自動化して動的に動作させることができれば理想的です。

「いいね!」 2

IEを気にしないのであれば、そのスニペットは動作するはずです(Discourseの設定で外部ドメインに対するCORSを有効にする必要があります)。

テストするには、このフォーラムの任意のページを開き、ブラウザのコンソールに以下のスニペットを貼り付けてください。ターゲット要素を document.body に変更しているため、ページ全体がフォーラムトピックのリストに置き換わります。実際のサイトでは、ターゲット要素を document.getElementById("#someId") に変更し、ページ内のどこかにそのIDを持つdivを配置してください。スクリプトがそのdivをトピックのリストで埋めます。

// IEを気にしない場合を除き、`fetch`にはポリフィルが必要になる可能性があります
// const targetEl = document.getElementById("forumTopics");

// これは例としてページのbodyを置き換えるものです
const targetEl = document.body;

// 自分のフォーラムでテストするには、ここにフォーラムのURLを入力してください
const baseForumURL = `https://meta.discourse.org`;

// 表示するトピックの数
const numTopics = 6;

function renderTemplate(topicsArr) {
    const items = topicsArr.map(
        (topic) => `<li><a href="${topic[1]}" target="_blank">${topic[0]}</li>`
    );

    targetEl.innerHTML = `<ul>${items.join("\n")}</ul>`;
}

// トピックリストの末尾に `.json` を追加
fetch(`${baseForumURL}/latest.json`)
    .then((res) => res.json())
    .then((json) => {
        const topics = json.topic_list.topics
            .slice(0, numTopics)
            .map((t) => [
                t.title,
                `${baseForumURL}/t/${t.slug}/${t.id}`,
            ]);

        renderTemplate(topics);
    });

例: WP サイト上のどこかにあるターゲットdivが以下のようになっている場合

<div id="forumTopics">
    <!-- フォーラムの投稿がここに表示されます -->
</div>

JavaScript は以下のようにその ID をターゲットにできます:

// 私が以前投稿した元の例のこの行を探してください
const targetEl = document.getElementById("forumTopics");
「いいね!」 4

それは最初の投稿にあるコードのことですか、それとも投稿 50 のスニペットのことですか?いいえ、IE は気にしません。あの恐竜に合わせる必要はありません :。
私の場合、どのブラウザでもスニペットの CSS が読み込まれていません。

つまり、これは JavaScript であり、WordPress に実装する際にこれを <script> タグで囲む必要がある、ということで合っていますか?

「いいね!」 2

WordPress を使ってから時間が経ちましたね。これはテーマの HTML に追加するものですか?もしそうなら、私のコードを script タグで囲み、投稿を表示させたい場所に div を配置してください。

以下のコードを、投稿を表示させたい WordPress テンプレートの HTML にそのまま貼り付けることができると思います。フォロムの URL が書かれた行を更新することを忘れないでください。動作しない場合は教えてください。(未検証です。)

コードはこちら
<div id="forumTopics"></div>
<script>
// ご自身のフォロムでテストするには、ここにフォロムの URL を入れてください
const baseForumURL = `https://forum.example.com`;

// 表示したいトピックの数
const numTopics = 6;

const targetEl = document.getElementById("forumTopics");
// 何らかの理由で投稿が読み込まれない場合、フォロムへのリンクを表示することもできます
targetEl.innerHTML = `<a class="link-to-discourse" href="${baseForumURL}/">最新のフォロム投稿を見る</a>`;

function renderTemplate(topicsArr) {
    const items = topicsArr.map(
        (topic) => `<li><a href="${topic[1]}" target="_blank">${topic[0]}</a></li>`
    );

    targetEl.innerHTML = `<ul>${items.join("\n")}</ul>`;
}

// トピックリストの末尾に `.json` を追加
fetch(`${baseForumURL}/latest.json`)
    .then((res) => res.json())
    .then((json) => {
        const topics = json.topic_list.topics
            .slice(0, numTopics)
            .map((t) => [
                t.title,
                `${baseForumURL}/t/${t.slug}/${t.id}`,
            ]);

        renderTemplate(topics);
    });
</script>
「いいね!」 3

ありがとうございます、スニペット全体を共有してくれて助かりました

最初のテストではリンクのみが表示されましたが、CORSが無効になっていると思うので、ホスティング先に有効化を依頼する予定です。
その間、スクリプトを特定のタグと特定のカテゴリの投稿のみを表示するようにするにはどうすればよいですか?

「いいね!」 2

はっきりはしませんが、フォーマットは以下のようになっていると思います。
https://forum.example.com/tags/c/<category_name>/<tag_name>

例: カテゴリが “support” でタグが “css” の場合:
https://meta.discourse.org/tags/c/support/css

これを JSON に変換するには、末尾に .json を追加します:
https://meta.discourse.org/tags/c/support/css.json

したがって、fetch 関数では /latest.json の代わりに、/tags/c/support/css.json のようなパスを使用してください。

(未検証。)

「いいね!」 3

そして、Discourse インスタンス自体に 5 つのトピックを埋め込みたい場合はどうすればよいでしょうか?

トピックを作成し、それをウィキとして設定します。それをページとして公開します。特定のカテゴリやタグから最新の 5 つのトピックを埋め込む方法、またはこの機能でサポートされているテンプレートを使用する方法を教えてください。

ありがとうございます。

「いいね!」 1

トップトピックのクエリパラメータは何ですか?order="top"を試しましたが、特定の期間に基づいてフォーラムと同じようにトップトピックを返していません。フォーラムのフィルター結果をどのように再現できますか?Discourseのフィルターオプションが受け取る属性値はどこで確認できますか?ありがとうございます!

「いいね!」 2

埋め込みコンテンツのフォントスタイルを変更することは可能でしょうか?d-topics-list iframe html .topics-list .topic-list-item のような CSS セレクターを試してみましたが、うまくいきませんでした。ご教示をよろしくお願いいたします!

「いいね!」 2