テーマまたはプラグインからの Plugin Outlet コネクタの使用

Discourse には、Discourse UI に新しいコンテンツを注入したり、既存のコンテンツを置換したりするために使用できる数百のプラグインアウトレットが含まれています。コンテキストに基づいてコンテンツをカスタマイズできるよう、「アウトレット引数」が利用可能になっています。

アウトレットの選択

プラグインアウトレットの名前を見つけるには、Discourse コア内で「<PluginOutlet」を検索するか、プラグインアウトレット場所 テーマコンポーネントを使用してください(例:topic-above-posts)。

ラッパーアウトレット

コア内の一部のアウトレットは <PluginOutlet @name="foo" /> のように見えます。これらは新しいコンテンツを注入することを可能にします。他のアウトレットは以下のように既存のコア実装を「ラップ」します。

<PluginOutlet @name="foo">
  コア実装
</PluginOutlet>

この種の「ラッパー」アウトレット用のコネクタを定義すると、コア実装が置き換えられます。ラッパープラグインアウトレットに対してコネクタを提供できるのは、アクティブなテーマまたはプラグインが 1 つだけです。

ラッパープラグインアウトレットの場合、{{yield}} キーワードを使用して元のコア実装をレンダリングできます。これは、特定の条件下でのみコア実装を置き換えたい場合や、何らかの要素でラップしたい場合に役立ちます。

コネクタの定義

アウトレットを選択したら、コネクタの名前を決めてください。これは、特定のコミュニティにインストールされているすべてのテーマ/プラグイン間で一意である必要があります(例:brand-official-topics)。

テーマ/プラグイン内で、以下のようにパス形式で新しい .gjs コネクタを定義します。

:art: {theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs

:electric_plug: {plugin}/assets/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs

これらのファイルの内容は Ember コンポーネントとしてレンダリングされます。Ember と .gjs 形式に関する一般的な情報については、Ember ガイド をご覧ください。

仮想的な「ブランド公式トピック」コネクタの場合、ファイルは以下のようになります。

<template>
  <div class="alert alert-info">
    このトピックは
    <a href="https://discourse.org/team">Discourse チーム</a>
    のメンバーによって作成されました
  </div>
</template>

アウトレット引数の使用

プラグインアウトレットは、@outletArgs を介して周囲のコンテキストに関する情報を提供します。各アウトレットに渡される引数は異なります。引数を確認する簡単な方法は、テンプレートに以下を追加することです。

{{log @outletArgs}}

これにより、引数がブラウザの開発者コンソールにログ出力されます。これらは Proxy オブジェクトとして表示されます。引数のリストを調べるには、プロキシの [[Target]] を展開してください。

topic-above-posts の例では、レンダリングされたトピックは @outletArgs.model で利用可能です。したがって、チームメンバーのユーザー名を以下のように追加できます。

<template>
  <div class="alert alert-info">
    このトピックは
    {{@outletArgs.model.details.created_by.username}}
    によって作成されました
    (
    <a href="https://discourse.org/team">Discourse チーム</a>
    のメンバー)
  </div>
</template>

より複雑なロジックの追加

単純なテンプレートでは不十分な場合があります。コネクタに JavaScript ロジックを追加するには、.gjs ファイルをクラスベースのコンポーネントをエクスポートするようにアップグレードします。これは他のコンポーネント定義と同じように機能し、サービスの注入を含めることができます。

topic-above-posts の例では、「UX でユーザー名を優先する」サイト設定に基づいてユーザーを異なってレンダリングしたい場合があります。.gjs ファイルは以下のようになります。

.../connectors/topic-above-posts/brand-official-topic.gjs:

import Component from "@glimmer/component";
import { service } from "@ember/service";

export default class BrandOfficialTopics extends Component {
  @service siteSettings;

  get displayName() {
    const user = this.args.outletArgs.model.details.created_by;
    if (this.siteSettings.prioritize_username_in_ux) {
      return user.username;
    } else {
      return user.name;
    }
  }

  <template>
    <div class="alert alert-info">
      このトピックは
      {{this.displayName}}
      によって作成されました
      (
      <a href="https://discourse.org/team">Discourse チーム</a>
      のメンバー)
    </div>
  </template>
}

条件付きレンダリング

特定の条件下でのみコンテンツをレンダリングしたい場合、テンプレートをハンドルバーズの {{#if}} ブロックでラップするだけで十分なことが多いです。それでは不十分な場合は、shouldRender フックを使用して、コネクタテンプレートがレンダリングされるかどうかを制御することをお勧めします。

まず、上記で説明したクラスベースの .gjs コネクタを持っていることを確認してください。次に、static shouldRender() 関数を追加します。例を拡張すると以下のようになります。

import Component from "@glimmer/component";

export default class BrandOfficialTopics extends Component {
  static shouldRender(outletArgs, helper) {
    const firstPost = outletArgs.model.postStream.posts[0];
    return firstPost.primary_group_name === "team";
  }
  // ... (その他のロジック)

  <template>{{! ... }}</template>
}

これで、コネクタはトピックの最初の投稿がチームメンバーによって作成された場合のみレンダリングされます。

shouldRender は Glimmer の自動トラッキングコンテキストで評価されます。参照されているプロパティ(例:outletArgs)の将来の変更により、関数が再評価されます。

新しいアウトレットの導入

まだ存在しないアウトレットが必要な場合は、プルリクエストを作成するか、Development でトピックを開いてください。


このドキュメントはバージョン管理されています。変更を GitHub で提案してください。

「いいね!」 39
Using discourse's plugin outlets
What is the best way to integrate member applications?
Add HTML (Link) Next To Logo
Group Semantics
Can I put the search form at the top of our 404 page?
How to show user total post count beside name
Developing Discourse Plugins - Part 2 - Connect to a plugin outlet
Native theme support
Feedback on "on-discourse" javascript for setting up custom JS for each page?
Topic-timeline api.decorateWidget call has stopped working
Developing Discourse Plugins - Part 2 - Connect to a plugin outlet
Developing Discourse Themes & Theme Components
How to add btn before "sign in"
Minimizing Maintenance on Theme Customizations
How to add custom fields to models
Tags at the top of the topic list in a Category
I want to insert images (banner) between the topic answers. How do I start?
How to add a link shortcut to the area under the title
Baidu Search
Add Banner/HTML (Widget) before reply button
Upcoming Header Changes - Preparing Themes and Plugins
Upgrading Discourse to Ember 4
Converting modals from legacy controllers to new DModal component API
Need help integrating code wrote on Edittext to the Discourse
Settings not appearing
Add link to external SSO profile to profile page
How to add a custom button in user profile card?
(not recommended) Overriding Discourse templates from a Theme or Plugin
How to override the site-header.hbs file from custom theme?
Upcoming topic-list changes - how to prepare themes and plugins
Working with .erb templates in a plugin
How to Integrate a Custom Plugin in discourse UI
Templating of my "component" broke. How do I fix it?
Templating of my "component" broke. How do I fix it?
Modernizing inline script tags for templates & JS API
Custom Components -- add button or text at any plugin outlet
(not recommended) Overriding Discourse templates from a Theme or Plugin
Adding "latest topics" header in the main interface
Display Tags inline with thread title, instead of being on the bottom line
How to add a custom button in user profile card?
Discourse view file update does not reflect in browser
Discourse view file update does not reflect in browser
Add likes and views to search display
Using template hbs to add HTML content to a plugin outlet
Adding a billing section in the member section
Adding a billing section in the member section
How to modify the header HTML, but still remaining the default founctions
Removing support for "template overrides" and mobile-specific templates
How can i add image in login and register box
Most “traditional” or classic forum Category listing
Newbie help accessing code
How to add custom html next to logo using discourse plugin methods
Using the DModal API to render Modal windows (aka popups/dialogs) in Discourse
Air Theme
How to create a plugin with backend API calls to populate composer while drafting?
How to add a custom url text link on the login page
Add Text In Header Beside Logo
Split up theme Javascript into multiple files