Как настроить текст во встроенном посте?

У меня есть сайт, где я публикую различные учебные пособия и блоги, и я использую 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.

Спасибо за любую помощь, которую вы сможете предложить!

Извините за всплытие темы, но я был бы очень признателен, если бы кто-нибудь поделился идеями, которые я мог бы попробовать!

Привет, Кевин, могу я уточнить, используешь ли ты плагин WP Discourse или встраивание через JavaScript?

Спасибо за ответ! Я использую 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

Если вы перейдёте по этой ссылке, то увидите, что тема содержит полный текст оригинальной страницы.

Спасибо за уточнение.

Почему у вас включена настройка сайта embed truncate в Discourse? Я немного запутался, так как вы упоминаете, что отключили её, но при этом говорите, что ваша проблема заключается в следующем:

Настройка embed truncate существует отчасти именно по этой причине. Она означает, что пользователь увидит только частичный отрывок поста непосредственно на Discourse.

Не могли бы вы немного подробнее объяснить, какое именно поведение пользователей вы пытаетесь предотвратить и какое — поощрить?

Я долго колебался насчёт настройки embed truncate. Посмотрев на неё снова, я полагаю, что её включение немного лучше, но я всё ещё надеюсь найти способ вообще не показывать полный текст оригинальной статьи в Discourse. Другими словами, я не хочу скрывать полный текст за кнопкой — я никогда не хочу показывать полный текст, только ссылку на оригинальную статью.

Поведение, которого я пытаюсь избежать, — это когда пользователи приходят в мой Discourse и читают полную статью прямо там, а не на оригинальной странице. Это проблема, потому что полный текст в Discourse часто содержит ошибки (с интерактивным JS, встроенным кодом и т. д.), и тогда я получаю отчёты об ошибках, где решение состоит в том, чтобы перестать читать в Discourse и перейти на «настоящий» сайт.

Другими словами, поведение пользователей, которое я пытаюсь поощрить, — это чтение полной статьи на оригинальной странице, а не в посте Discourse.

Это может показаться незначительным (и в глобальном масштабе так оно и есть), но я боюсь, что пользователи приходят в мой Discourse, думая, что поведение страницы содержит ошибки, и уходят, так и не поняв, что на моём «настоящем» сайте есть страница, которую им следует читать вместо поста в Discourse.

Вот несколько возможных вариантов, которые я рассматривал:

  • Есть ли настройка, которая говорит Discourse включать только ссылку и не включать никакой части оригинального поста?
  • Есть ли CSS-класс или другой атрибут, который я могу добавить к своему исходному HTML, чтобы указать, какая часть статьи должна быть включена (или исключена) в посте Discourse?
  • Может быть, я могу добавить пользовательский CSS в Discourse, чтобы скрыть кнопку Show Full Post...?

Спасибо за объяснение, Кевин. Специальных настроек, направленных именно на эту проблему, нет, но есть два подхода, которые вы можете использовать.

Настройка того, какой 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_selectors, blocked_embed_selectors или allowed_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 также должно сработать.

Мне трудно понять, почему нет возможности настроить весь встроенный текст. Я не хочу извлекать фактический контент из встроенного URL-адреса, а лишь хочу иметь ссылку на него с кратким описанием (например, только мета-описание).

Сейчас я делаю это с помощью автоматического вызова API, но хочу переключиться на встроенную функцию.

Я пробовал создавать скрытый элемент на извлекаемом сайте специально для Discourse, чтобы извлекать только этот один элемент, но недостатком является то, что onebox не будет отображаться для ссылки.

Настройка embed.imported_from также имеет свои ограничения, так как она всегда принудительно помещается в тег <small>, что не позволяет никакой реальной настройки.

Похоже, вам не нужен встраиваемый контент, так как по своей сути это «встраивание» содержимого из другого источника.

Почему вы хотите переключиться?

Верно, я просто хочу, чтобы при публикации новой статьи блога автоматически создавалась тема.

Однако я также хочу использовать встроенную функцию JS для отображения комментариев под статьёй блога на внешнем сайте, что также включает поведение встраивания на форуме.

Моя текущая автоматизация работает с некоторой задержкой (не в реальном времени), а реализация автоматического создания темы в нашей CMS при публикации новой статьи немного сложнее, поскольку это не просто блог-система, и даже нет отдельного события «публикации».

В любом случае, между JS-встраиванием, пытающимся создать тему, и моей автоматизацией возникнут конфликты, причём первое, скорее всего, будет работать быстрее в большинстве случаев. Вот почему я хочу «переключиться» на использование только функции JS-встраивания, несмотря на недостаток необходимости вручную редактировать темы каждый раз.

Буду рад услышать предложения! :smile:

Спасибо за разъяснение.

Хорошо, если я правильно вас понимаю:

  1. вам нужна функциональность создания тем и связывания комментариев, как в JS-вставках; и
  2. вам нужна просто ссылка с кратким описанием в первом посте связанной темы в Discourse.

Правильно ли я понял? По пункту 2: вы пробовали настройку сайта embed truncate? Если да, то что именно вам в ней не понравилось? Я понимаю, что вы немного затрагивали этот вопрос в своём первом ответе, но могли бы вы подробнее объяснить, с чем именно у вас возникают трудности? Возможно, приведёте пример того, что мешает вам достичь желаемого результата (и каков именно этот желаемый результат).

Да, вы правы.

Проблема сводится к превью ссылки (onebox), которое не отображается, потому что встроенный контент всегда оборачивается в HTML-теги. :smiley:

Я понимаю, что это звучит как мелкая придирка (так оно и есть), но неудобство, связанное с необходимостью вручную редактировать это для каждой статьи, значительно и является проблемой, которую я хотел решить уже давно.

Вот как я хочу, чтобы это выглядело (на примере поста в блоге Discourse):

В настоящее время мне пришлось бы возиться со скрытыми элементами на веб-сайте, чтобы иметь возможность извлекать URL и краткое описание, и даже в этом случае проблема заключается в том, что превью ссылки не отображается. Единственное, что я могу более или менее полностью настроить, — это часть «Читать полный пост в блоге…» в конце.

По сути, я прошу о возможности добавить что-то в фрагмент 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\nМы с радостью сообщаем о переходе сообщества Spiceworks на платформу Discourse! Команда Spiceworks тесно сотрудничала с нашей командой по миграции\n\n<small>Читать полный пост в блоге на <a href="https://blog.discourse.org/2024/03/a-warm-welcome-to-spiceworks/">discourse.org</a>. Этот пост был создан автоматически, и ответы будут отображаться на веб-сайте.</small>'
};

discourseEmbedRaw должен быть эквивалентен значению raw в обычном API-запросе к /posts.json.

Но я понимаю, что это может быть требованием для частного случая и не актуально для большинства пользователей. Полагаю, я попробую решить это, создавая темы через API до того, как фрагмент JS попытается это сделать.

Я бы не рекомендовал этого делать.

Это вызовет различные проблемы. Давайте пока оставим это в стороне.

Я понимаю, что в идеале вы хотите полный контроль над всем, однако будьте терпеливы, пока я пытаюсь перевести ваши потребности в то, что может быть реализуемым улучшением текущей системы. Имейте в виду, что это лишь предложения, и я не контролирую то, что будет принято командой Discourse.

Встроенный пост в Discourse по сути состоит из двух элементов:

  1. HTML «импортировано из» (то есть ссылка).
  2. HTML-контент со связанной страницы, полный или обрезанный.

1. Контроль над HTML «импортировано из»

В настоящее время этот HTML зафиксирован как:

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

Вы хотели бы настроить его так, чтобы он содержал, например, только URL, чтобы он отображался в виде onebox. Я считаю, что разумным улучшением здесь будет настройка сайта, которая просто переключает это на «только URL», чтобы вам не приходилось разрешать администраторам вводить HTML где-либо.

2. Контроль над обрезанным HTML-контентом

Вы уже можете это сделать. Просто установите настройку сайта allowed embed classnames в имя класса элемента, которым вы обернули отрывок, который хотите отображать на своем сайте, например:

На Discourse

Установите следующие настройки сайта:

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

На странице вашего блога

<div class="discourse-excerpt">
Мы рады сообщить о переходе сообщества Spiceworks на Discourse! Команда Spiceworks тесно работала с нашей командой миграции
</div>

3. Контроль над порядком HTML «импортировано из» и HTML-контента

Если я правильно понял, вы хотите, чтобы часть «импортировано из» (например, только URL) шла перед HTML-контентом (или обрезанным контентом). Опять же, самый простой способ сделать это — добавить булеву настройку сайта, например embed imported from above content.

Итак, коротко: если я правильно понял, вы можете достичь этого, добавив две новые булевы настройки и внеся небольшие изменения в класс TopicEmbed. Обратите внимание, что все эти изменения касаются самого репозитория discourse/discourse, так как обработка должна происходить там.

Как я уже упоминал выше, это лишь предложения о том, как я бы реализовал то, что вы хотите сделать. Чтобы эти или аналогичные изменения были реализованы, необходимо согласие команды Discourse.

Спасибо, что записали это! :+1:

Да, именно с этим я и экспериментировал. Проблема в том, что контент оборачивается в несколько HTML-тегов, из-за чего onebox не срабатывает. Я пробовал разделять URL тегами <br> (чтобы активировать onebox), но такие элементы, похоже, автоматически удаляются.

Хм, хорошо, почему? :slight_smile:

Я бы, конечно, установил значение embed_url.

Настройка вашего URL для встраивания под onebox — это отдельный вопрос. Используйте allowed embed classnames, чтобы установить только текстовый отрывок, как в моём примере.

Потому что вы по сути будете изобретать велосипед, пытаясь обойти проблему парсинга TopicEmbed. Это также откроет новый набор проблем: например, что если ваш код выполнится не в том порядке, как вы ожидаете, из-за состояния гонки или другого исключения. Такие проблемы довольно часто возникают при взаимодействии кода на внешнем сайте с плагином WP Discourse. Короче говоря, это того не стоит.

Похоже, вы хорошо разбираетесь в кодовой базе :slight_smile: Вам нужно всего лишь внести два простых изменения в этот класс.

  1. Добавьте условный оператор, управляемый настройкой сайта, здесь:
  1. Добавьте ещё один условный оператор, управляемый настройкой сайта, здесь:

Вам даже не понадобится собирать приложение Discourse. Сначала напишите два теста на rspec, затем внесите изменения, и как только они заработают — создайте PR :slight_smile:

На всякий случай вот что я в итоге сделал:

  1. В моём блоге есть <div> с идентификатором forum-excerpt, который скрыт с помощью display:none, но содержит HTML, который я хочу отображать в посте Discourse. (Я делаю это с помощью логики Jekyll / Liquid, но это не должно иметь особого значения.)

  2. В настройках Discourse я указал CSS-селектор для элементов, разрешённых во встраиваемых блоках как #forum-excerpt. Хотя div скрыт на моей реальной странице, его содержимое отображается на форуме.

  3. Я также снял галочку с параметра Обрезать встраиваемые посты.

  4. В разделе Встроенный CSS я увеличил шрифт для .button. Это небольшое изменение, но оно делает кнопку добавления комментария больше.

  5. Кроме того, я настроил тексты embed.continue, embed.start_discussion и embed.imported_from, что меняет то, что отображается в разделе комментариев на моём сайте.

Это означает, что у меня есть полный контроль над HTML, который отображается в посте форума. HTML, который я передаю, по сути эквивалентен OneBox — это большая миниатюра и ссылка на основной пост.

Для меня это работает практически идеально. Спасибо за помощь, пусть и с опозданием!