Insertable, centrally maintained text/markdown snippets

I was wondering if there was any way I could define a string of text in a single place and insert it within posts with a single, short reference.

It’s a bit like the out of the box Admin -> Customize -> Text Content, but for my own custom variables that can be inserted into posts.

My use case was adding a disclaimer for my affiliate links. As the number of affiliate links grew across many posts and Topics I noted that my disclaimers were proliferating along with them. I occasionally like to make improvements to the disclaimers and this gets more onerous as the number grows.

I’m also considering making my affiliate links more generic so I have one centrally managed link for each product link, for example, which appears multiple times. If that product link changes, I only have to change it in one place.

Obviously I might be able to do some kind of rails find & replace, but that’s not as clean/safe nor ‘online’.

So I wanted a place to define & maintain a text string in a single place and have changes immediately reflected everywhere that is used on next page view.

Read on for @Johani’s solution!:

3개의 좋아요

One possible option is to use a theme component.

This goes in header.html

<script type="text/discourse-plugin" version="0.8">
var disclaimer = settings.Disclaimer_text,
  disclaimer_selector = 'div[data-theme="disclaimer"]';

$.fn.disclaimer = function() {
  if (!this.length) {
    return;
  } else {
    this.each(function() {
      $(this).html(disclaimer);
    });
    return this;
  }
};

api.decorateCooked($elem => $elem.children(disclaimer_selector).disclaimer());

// create composer button
let currentLocale = I18n.currentLocale();

I18n.translations[currentLocale].js.disclaimer_button = "Add disclaimer";
I18n.translations[currentLocale].js.composer.disclaimer_prompt = ""; // leave empty

api.onToolbarCreate(function(toolbar) {
  toolbar.addButton({
    trimLeading: true,
    id: "disclaimer-button",
    group: "insertions",
    icon: "exclamation-circle", // change icon
    title: "disclaimer_button",
    perform: function(e) {
      return e.applySurround(
        '<div data-theme="disclaimer">',
        "</div>",
        "disclaimer_prompt"
      );
    }
  });
});
</script>

and this goes into your component’s settings.yml file

Disclaimer_text:
  default: "Lorem ipsum dolor sit amet, ei purto complectitur has, per at quas senserit. Et malis libris eos, vix id pericula dissentiet, aliquid apeirian pro eu. Sed ex viderer inciderint, vitae officiis dissentiet eos no. Omnes percipit singulis in has, ne nam nibh tation inciderint. Quas nulla ei sit, ex eam rebum voluptaria. Id eam altera similique. Ex justo assentior persequeris mea, ei hinc paulo ubique mei. <br><br>Cu nam epicurei torquatos, et accusam accommodare vim. Vis sint saperet officiis et. Ad consequat posidonium mea, et duo paulo quidam maluisset, vel an electram expetendis. An vis repudiare tincidunt, mentitum convenire eloquentiam ut vis, summo partiendo pro ad."
  description:
    en: Enter desired disclaimer text. Use &lt;br&gt; for linebreaks.

You would then have a button in the composer that looks like so:

and clicking the button would add

<div data-theme="disclaimer"></div>

which get’s converted to whatever you set in the component’s settings

and the end result looks like this

and you can use

[data-theme="disclaimer"] {

}

in CSS to style it however you like.

21개의 좋아요

That’s awesome! Thanks @Johani

Added to Tips’n’Tricks.

2개의 좋아요

Hi @merefield - funnily enough I was looking for similar functionality - inserting a standard snippet of text - but rather than a button I wanted a trigger string that would expand out to a piece of markdown. (OK, I suppose alternatively I could modify the button to a dropdown with a few options)

This is probably not a core Discourse feature but a plugin.

Ideal behaviour:

  • I type :stub: (I don’t mind about using something instead of the delimiting : characters, but wondered if hooking into the emoji interface might work since that has the kind of ‘completion’ type behaviour that I’d like)

  • Discourse replaces :stub: with

    > This article is a stub - please improve it by  **editing**  and  **adding links**  and  **detail**  (it’s a ‘wiki’ so any user can edit and add information) or by  **commenting**  below.
    
  • which is rendered as

    This article is a stub - please improve it by editing and adding links and detail (it’s a ‘wiki’ so any user can edit and add information) or by commenting below

  • and there should be somewhere in the UI to configure these snippets, a bit like the Custom Emoji interface

5개의 좋아요

Great idea for a plugin! Would you be ok for the text to appear only in the preview and the final cooked view?

4개의 좋아요

@pacharanero님의 제안은 우리에게도 정말 멋진 아이디어입니다. 우리 경우엔 직원 전용으로 사용할 예정이라 에디터 툴바에 아무것도 표시되길 원하지 않지만, 짧은 코드를 입력해 자동 업데이트되는 블록을 삽입할 수 있다면 정말 훌륭할 것 같습니다 :+1:

1개의 좋아요

현재로서는 Discourse나 cetnrally가 관리하지 않는 방식으로 이 동작을 구현하려면, CopyQ와 같은 크로스 플랫폼 클립보드 관리자를 사용하고 ‘Commands/Global Shortcuts’ 섹션을 설정하여 임의의 텍스트를 클립보드에 삽입할 수 있도록 구성하는 것입니다.

이 스니펫은 CopyQ UI에서 관리하거나, 핫키에 할당하거나, 우클릭 시 나타나는 CopyQ 메뉴에 표시되도록 설정할 수 있습니다. Discourse에 내장된 플러그인만큼은 아니지만, 모든 애플리케이션에서 작동한다는 장점과 이미 존재한다는 이점이 있습니다.

(이 설정을 사용하려는 각 컴퓨터에서 별도로 구성해야 합니다. 이러한 명령과 글로벌 단축키를 파일로 내보내고 가져올 수 있으므로, 여러 기기나 팀 전체에서 동일한 설정을 적용하는 것이 가능합니다)

저로서는 전혀 문제가 되지 않습니다. DiscoTOC와 Placeholders와 달리 미리보기 창에서는 제대로 렌더링되어야 할 것 같지만, 작성기(composer)에서는 단순히 선택한 :slug: 트리거 구문만 표시되면 될 것 같습니다.

답변해 주셔서 감사합니다. CopyQ 솔루션은 제가 원하는 기능을 제공하지 않는 것 같습니다.

예를 들어, 게시글에 스니펫(예: :slug:)을 입력하면, 이 스니펫이 렌더링될 때마다 해당 슬러그의 현재 콘텐츠(마크다운을 포함할 수 있음)가 표시되기를 원합니다. 이 슬러그의 콘텐츠를 변경하면, 이 슬러그를 사용하는 모든 게시글이 즉시 새 콘텐츠로 업데이트되기를 바랍니다(게시글 자체에는 슬러그만 포함되어 있고, 렌더링 시 콘텐츠가 교체되는 방식입니다).

검색이 콘텐츠의 존재를 인식하지 못하는 것은 괜찮습니다(최종 렌더링된 버전만 표시되면 저에게는 좋습니다).

감사합니다.

여기 다른 접근법이 있습니다…

1개의 좋아요