如何自定义嵌入帖子中的文本?

我有一个网站,我会在上面发布各种教程和博客,并且我将 Discourse 用作论坛和评论区(通过嵌入功能)。

这在大多数情况下都运行良好,但有一个问题:当我创建新页面时,所有内容都会被包含在 Discourse 帖子中。我的有些用户甚至不知道主站的存在,因为他们总是在论坛上阅读完整帖子!这是一个问题,因为像嵌入式代码编辑器这样的功能在 Discourse 上无法正常工作,这给他们带来了糟糕的体验。

在理想情况下,Discourse 帖子应该只是一个简短、非常明显的链接,指向主页上的原始帖子。也许是这样的:

在此处查看原始帖子:

https://example.com

对此帖的回复将显示为原始帖子的评论!

我尝试禁用 embed truncate 设置,如此帖子中所述,但这似乎隐藏了“显示完整帖子”按钮,但帖子中仍然显示所有内容。

我也尝试编辑 embed.imported_from 消息,但这只会改变人们似乎已经忽略的底部的微小文字。

我也尝试在 Discourse 创建帖子后手动编辑它,但 Markdown 没有被渲染成 HTML,而是显示为纯文本。这听起来与此问题类似:Customizing the "Embedding" Behavior by Disabling Show Full Post?

我是否遗漏了某个设置,或者有什么其他技巧可以用来自定义自动生成的 Discourse 帖子的文本?也许我可以在主站的 HTML 中包含一些内容来欺骗 Discourse 显示正确的内容?或者,如果能解决 Markdown 渲染问题,我也愿意手动编辑它。

感谢您提供的任何帮助!

1 个赞

抱歉打扰,但如果有人能给我一些建议,我将不胜感激!

凯文,我能确认一下你是在使用 WP Discourse 插件还是 JavaScript 嵌入吗?

1 个赞

感谢您的回复!我正在使用 JavaScript 嵌入。例如,我有这个页面:

其中包含此嵌入代码:

<script type="text/javascript">
DiscourseEmbed = { discourseUrl: location.protocol 
	+ '//forum.happycoding.io/',
	discourseEmbedUrl: location.protocol + '//happycoding.io/tutorials/javascript/react-css' };
	
(function() {
	var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
	d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
	(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
})();
</script>

这会在我的 Discourse 中创建此帖子:

https://forum.happycoding.io/t/css-in-react/1092

如果您点击它,您会看到该帖子包含原始页面的全部文本。

感谢您的澄清。

为什么要在 Discourse 中启用 embed truncate 网站设置?我有点困惑,因为您提到您已禁用它,但您也说您的问题是

embed truncate 设置部分就是为此原因而存在的。这意味着用户在 Discourse 本身中只会看到帖子的部分摘录。

您能否更详细地解释一下您试图避免的具体用户行为,以及您试图鼓励的具体用户行为。

1 个赞

我一直在反复考虑 embed truncate 设置。现在再看一遍,我认为启用它稍微好一些,但我仍然希望有一种方法可以完全避免在 Discourse 中显示原始文章的全文。换句话说,我不想将全文隐藏在按钮点击后面——我根本不想显示全文,只想提供指向原始文章的链接。

我试图避免的行为是用户访问我的 Discourse 并直接在 Discourse 上阅读整篇文章,而不是在原始页面上阅读。这是一个问题,因为 Discourse 上的全文通常包含错误(例如交互式 JS、嵌入式代码等),然后我收到的错误报告会建议停止在 Discourse 上阅读,而是转到“真正的”网站。

换句话说,我试图鼓励的用户行为是在原始页面上阅读整篇文章,而不是在 Discourse 帖子中阅读。

这可能看起来微不足道(从宏观角度来看确实如此),但我担心的是用户会访问我的 Discourse,认为页面的行为存在错误,然后在他们意识到我的“真正”网站上有一个页面应该阅读而不是 Discourse 帖子之前就离开了。

我考虑过的一些可能选项:

  • 是否有某个设置可以告诉 Discourse 只包含链接,而不包含原始帖子的任何内容?
  • 是否有我可以添加到原始 HTML 中的 CSS 类或其他属性,以指示文章的哪个部分应包含(或排除)在 Discourse 帖子中?
  • 也许我可以向 Discourse 添加自定义 CSS 来隐藏“显示完整帖子…”按钮?

谢谢你的解释,凯文。没有专门针对此问题的设置,但你可以通过两种方式解决此问题。

自定义从你的网站提取的 HTML

嵌入的工作方式是它们使用 Readability gem 从网站抓取内容。该 gem 及其输出使用以下选项来过滤抓取了哪些 HTML

opts[:whitelist] = SiteSetting.allowed_embed_selectors if SiteSetting.allowed_embed_selectors.present?
opts[:blacklist] = SiteSetting.blocked_embed_selectors if SiteSetting.blocked_embed_selectors.present?
allowed_embed_classnames = SiteSetting.allowed_embed_classnames if SiteSetting.allowed_embed_classnames.present?

因此,你可以设置站点设置 allowed_embed_selectorsblocked_embed_selectorsallowed_embed_classnames 来限制从你的 HTML 中提取并显示在 Discourse 帖子中的内容,例如,你可以将其限制为不存在的类,这样就不会提取任何内容。

然后,从网站抓取的内容将附加此 HTML:

"\n<hr>\n<small>#{I18n.t('embed.imported_from', link: \"<a href='#{url}'>#{url}</a>\")}</small>\n"

因此,你只需在管理面板中自定义 embed.imported_from 文本,告知用户在博客上阅读内容。请注意,你可以在该文本中插入指向内容的链接,例如,该语言的本地化文本是

这是原始条目的伴随讨论主题,网址为 %{link}

隐藏“显示完整帖子”按钮

正如你所建议的,使用 CSS 隐藏“显示完整帖子”按钮也应该有效。

2 个赞

我很难理解为什么没有选项可以自定义完整的嵌入文本。我不想抓取嵌入式 URL 的任何实际内容,而只是提供一个指向它的链接以及简短的描述(例如,仅摘要)。

现在我通过自动 API 调用来实现这一点,但希望切换到原生嵌入功能。

我尝试在抓取的网站上创建一个隐藏元素,专门供 Discourse 抓取该单个元素,但缺点是链接不会显示 onebox。

自定义 embed.imported_from 也有其局限性,因为它总是被强制放入 \u003csmall\u003e 标签中,不允许任何实际自定义。

听起来你不是想要嵌入,而嵌入的本质就是“嵌入”来自另一个地方的内容。

你为什么要切换?

确实,我只想在发布新博客文章时自动创建帖子。

但是,我也想使用原生的 JS 嵌入功能,在外部网站的博客文章下方显示评论,这也会带来论坛中的嵌入行为。

我目前的自动化存在一些延迟(不是实时的),并且在我们的 CMS 中实现新文章发布时的自动帖子创建会更困难一些,因为它不仅仅是一个博客 CMS,甚至没有一个明确的“发布”事件。

无论如何,JS 嵌入尝试创建帖子和我的自动化之间会出现冲突,前者通常会更快。这就是为什么我想“切换”到只使用 JS 嵌入功能,缺点是帖子每次都需要手动编辑。

欢迎提出建议!:smile:

谢谢你的解释。

好的,如果我理解正确的话:

  1. 你想要 JS 嵌入 的主题创建和评论链接功能;以及
  2. 你只想要一个链接,并在 Discourse 中链接主题的第一个帖子中附带简短描述。

我说得对吗?关于第 2 点,你是否尝试过 embed truncate 站点设置?如果尝试过,你觉得它有什么不满意的地方?我明白你在第一个回复中已经稍微提到了这一点,但能否具体解释一下你遇到的困难?也许举一个例子来说明是什么阻碍了你实现期望的结果(以及那个期望的结果到底是什么)。

1 个赞

是的,你没理解错。

问题出在链接的 onebox(自动预览),它不会显示,因为嵌入内容总是被包裹在 HTML 标签中。:smiley:

我知道这听起来是个小问题(确实如此),但每次都要手动编辑这篇文章的麻烦程度相当大,而且我早就想修复这个问题了。

我希望它看起来是这样的(以 Discourse 博客文章为例):

目前,我必须去摆弄网站上的隐藏元素才能专门抓取 URL 和摘要,即便如此,问题还是 onebox 没有显示。我唯一能比较完整地自定义的是底部的“阅读完整博文…”部分。

我想我要求的是能够向 JS 代码段添加类似这样的内容:

DiscourseEmbed = {
    discourseUrl: 'https://forum.example.com/',
    discourseEmbedUrl: 'https://blog.discourse.org/2024/03/a-warm-welcome-to-spiceworks',
    discourseRaw: 'https://blog.discourse.org/2024/03/a-warm-welcome-to-spiceworks\n\nWe are thrilled to share the move of the Spiceworks community to Discourse! The Spiceworks team has worked closely with our migration team\n\n<small>Read the full blog post on <a href="https://blog.discourse.org/2024/03/a-warm-welcome-to-spiceworks/">discourse.org</a>. This post has been created automatically and replies will be shown on the website.</small>'
};

discourseEmbedRaw 相当于常规 API 请求 /posts.json 中的 raw 值。

但我明白这可能是一个边缘情况的需求,对大多数用户来说并不重要。我想我将尝试通过在 JS 代码段尝试这样做之前通过 API 创建主题来解决这个问题。

我不推荐这样做。

这会导致各种问题。我们暂时把这个问题放在一边。

我很欣赏你希望完全控制一切,但请耐心等待我尝试将你的需求转化为当前系统可能的可行改进。请记住,这些只是建议,我无法控制 Discourse 团队最终是否会接受。

Discourse 中的嵌入式帖子基本上由两部分组成:

  1. “导入自” HTML(即链接)
  2. 来自链接页面的 HTML 内容,可以是完整的或截断的。

1. 控制“导入自” HTML

目前,此 HTML 是硬编码的:

 "
\u003chr\u003e
\u003csmall\u003e#{I18n.t("embed.imported_from", link: "\u003ca href='#{url}'\u003e#{url}\u003c/a\u003e")}\u003c/small\u003e
"

你希望将其自定义为,例如,仅 URL,以便它可以一键生成。我认为一个可行的改进是添加一个站点设置,将其简单地切换为“仅 URL”,这样你就无需让管理员在某处输入 HTML。

2. 控制截断的 HTML 内容

你已经可以做到这一点了。只需将站点设置 allowed embed classnames 设置为你用于包装你网站上所需摘要的元素的类名即可,例如:

在 Discourse 上

设置以下站点设置:

  • embed truncate 为 false
  • allowed embed classnames 为 “discourse-excerpt”

在你的博客页面上

\u003cdiv class="discourse-excerpt"\u003e
我们很高兴地宣布 Spiceworks 社区迁移到 Discourse!Spiceworks 团队与我们的迁移团队密切合作
\u003c/div\u003e

3. 控制“导入自” HTML 和 HTML 内容的顺序

如果我理解正确的话,你希望“导入自”部分(例如仅 URL)出现在 HTML 内容(或截断内容)之前。同样,最简单的方法是添加一个布尔值站点设置,例如 embed imported from above content

所以,总而言之,如果我理解正确的话,通过添加两个新的布尔设置和对 TopicEmbed 类的少量调整,你就可以实现这一点。你会注意到,所有这些更改都针对 discourse/discourse 本身,因为处理必须在那里进行。

如上所述,这些只是我将如何实现你想要的建议。要实现这些或类似的功能,需要 Discourse 团队的同意。

1 个赞

感谢您写下这些内容! :+1:

是的,这正是我尝试过的,问题在于内容会被包装在几个 HTML 标签中,这就是为什么 onebox 不会触发的原因。我尝试用 <br> 标签(以触发 onebox)分隔 URL,但似乎这类内容会自动被修剪掉。

嗯,好吧,为什么呢? :slight_smile:

我当然会设置 embed_url 值。

让您的嵌入式 URL 触发 onebox 是一个单独的问题。仅使用 allowed embed classnames 来设置文本摘要,就像我的示例一样。

因为您实际上是在重新发明轮子,试图规避真正的问题——TopicEmbed 解析问题。这还会带来新的问题,例如,如果您的代码没有按预期顺序执行,例如出现竞态条件或其他中间异常。这类问题在使用外部网站的代码和 WP Discourse 插件的混合体时相对常见。总之,不值得。

您似乎对代码库很熟悉 :)。您实际上需要对这个类进行两个简单的更改。

  1. 在此处插入一个由站点设置控制的条件
  1. 在此处插入另一个由站点设置控制的条件

您甚至不需要构建 discourse 应用程序。只需先编写两个 rspec 测试,然后进行更改,一旦它们正常工作,就可以提交一个 PR :slight_smile:

1 个赞

就我而言,这是我最终的做法:

  1. 在我的博客上,我有一个 <div>,其 ID 为 forum-excerpt,它被 display:none 隐藏了,但包含我想在 Discourse 帖子中显示的 HTML。(我使用了一些 Jekyll / Liquid 逻辑来实现这一点,但这似乎并不重要。)

  2. 在我的 Discourse 上,我将 CSS 选择器,用于允许嵌入的元素 设置为 #forum-excerpt。虽然该 div 在我的实际页面上是隐藏的,但内容会显示在论坛上。

  3. 我还取消选中 截断嵌入的帖子

  4. 嵌入的 CSS 部分,我为 .button 设置了更大的字体。这是一个小改动,但它使添加评论的按钮变大了。

  5. 我还自定义了 embed.continueembed.start_discussionembed.imported_from 文本,这会更改我的网站评论部分显示的内容。

这意味着我对显示在论坛帖子中的 HTML 拥有完全的控制权。我提供给它的 HTML 基本上相当于一个 OneBox——它是一个大缩略图和一个指向主帖子的链接。

这对我来说几乎完美地奏效,迟到的感谢您的帮助!

2 个赞

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.