How do you customize hot topic score algorithm with a plugin?

The built-in Hot sorting algorithm is very simple and might not be suitable for different use cases. From my basic understanding of Discourse codebase, currently there is not user-facing site settings or appropriate plugin injection point for customizing hot sorting algorithm. There is one topic_hot_scores_updated event but it is called after scores are updated, which serves the purpose of notification without the ability to override built-in hot scores. There are two site settings hot_topics_gravity and hot_topics_recent_days but they have hidden: true set and are not visible in admin UI.

We are considering writing a plugin to replace the built-in hot score algorithm. What approach would be better in terms of compatibility and ease of upgrading Discourse in the future? Some of my ideas are listed below:

  • Monkey-patch TopicHotScore and update db according to our custom algorithm.
  • Create a separate table to store topic hot scores and run a separate background job to update them. Add another route (instead of /hot) for our custom hot topic listing.
  • Or maybe the Discourse codebase can be improved to support such use case?
1 Like

Easiest but might be limited depending on what you want to do.

Doable but more complex. Have a look on how TopicQuery implements lists

and specifically

  def list_hot
    create_list(:hot, unordered: true, prioritize_pinned: true) do |topics|
      topics = remove_muted(topics, user, options)
      topics.joins("JOIN topic_hot_scores on topics.id = topic_hot_scores.topic_id").order(
        "topic_hot_scores.score DESC",
      )
    end
  end

You can add an extra one relatively easily although there are quite some moving parts you need to take into account. I did that in my β€˜homepage-filter’ plugin and that might be a good starting point.