FEATURE: Order pinned topics by their `pinned_at` column (#14090)

FEATURE: Order pinned topics by their pinned_at column (#14090)

Currently, pinned topics are ordered by the bumped_at column. This behavior is not desired because it gives admins no control over the order of pinned topics. This PR makes pinned topics ordered by the pinned_at column. A topic that is pinned last appears first in topic lists. If an admin wants an already pinned topic to appear first in the list of pinned topics, they’ll have to unpin that topic and pin it again.

Meta topic: How do I set the order of pinned topics - #23 by sam - feature - Discourse Meta.

diff --git a/lib/topic_query.rb b/lib/topic_query.rb
index b2e2b0c..25362ab 100644
--- a/lib/topic_query.rb
+++ b/lib/topic_query.rb
@@ -390,7 +390,7 @@ class TopicQuery
     end
 
     unpinned_topics = topics.where("NOT ( #{pinned_clause} )")
-    pinned_topics = topics.dup.offset(nil).where(pinned_clause)
+    pinned_topics = topics.dup.offset(nil).where(pinned_clause).reorder(pinned_at: :desc)
 
     per_page = options[:per_page] || per_page_setting
     limit = per_page unless options[:limit] == false
diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb
index fd879b5..cd65957 100644
--- a/spec/components/topic_query_spec.rb
+++ b/spec/components/topic_query_spec.rb
@@ -97,6 +97,63 @@ describe TopicQuery do
         page: 1)
       ).to eq(topics[per_page...num_topics])
     end
+
+    it "orders globally pinned topics by pinned_at rather than bumped_at" do
+      pinned1 = Fabricate(
+        :topic,
+        bumped_at: 3.hour.ago,
+        pinned_at: 1.hours.ago,
+        pinned_until: 10.days.from_now,
+        pinned_globally: true
+      )
+      pinned2 = Fabricate(
+        :topic,
+        bumped_at: 2.hour.ago,
+        pinned_at: 4.hours.ago,
+        pinned_until: 10.days.from_now,
+        pinned_globally: true
+      )
+      unpinned1 = Fabricate(:topic, bumped_at: 2.hour.ago)
+      unpinned2 = Fabricate(:topic, bumped_at: 3.hour.ago)
+
+      topic_query = TopicQuery.new(user)
+      results = topic_query.send(:default_results)
+
+      expected_order = [pinned1, pinned2, unpinned1, unpinned2].map(&:id)
+      expect(topic_query
+        .prioritize_pinned_topics(results, per_page: 10, page: 0)
+        .pluck(:id)
+      ).to eq(expected_order)
+    end
+
+    it "orders pinned topics within a category by pinned_at rather than bumped_at" do
+      cat = Fabricate(:category)
+      pinned1 = Fabricate(
+        :topic,
+        category: cat,
+        bumped_at: 3.hour.ago,
+        pinned_at: 1.hours.ago,
+        pinned_until: 10.days.from_now,
+      )
+      pinned2 = Fabricate(
+        :topic,
+        category: cat,
+        bumped_at: 2.hour.ago,
+        pinned_at: 4.hours.ago,
+        pinned_until: 10.days.from_now,
+      )
+      unpinned1 = Fabricate(:topic, category: cat, bumped_at: 2.hour.ago)
+      unpinned2 = Fabricate(:topic, category: cat, bumped_at: 3.hour.ago)
+
+      topic_query = TopicQuery.new(user)
+      results = topic_query.send(:default_results)
+
+      expected_order = [pinned1, pinned2, unpinned1, unpinned2].map(&:id)
+      expect(topic_query
+        .prioritize_pinned_topics(results, per_page: 10, page: 0, category_id: cat.id)
+        .pluck(:id)
+      ).to eq(expected_order)
+    end
   end
 
   context 'bookmarks' do

GitHub sha: ec352a19697b26a9042bb236180963ed5af627ca

This commit appears in #14090 which was approved by CvX. It was merged by OsamaSayegh.

This commit has been mentioned on Discourse Meta. There might be relevant details there: