diff --git a/public/language/en_GB/recent.json b/public/language/en_GB/recent.json
index ee5a6a3e34..32b31d2666 100644
--- a/public/language/en_GB/recent.json
+++ b/public/language/en_GB/recent.json
@@ -3,5 +3,6 @@
 	"day": "Day",
 	"week": "Week",
 	"month": "Month",
+	"year": "Year",
 	"no_recent_topics": "There are no recent topics."
 }
\ No newline at end of file
diff --git a/public/src/forum/popular.js b/public/src/forum/popular.js
index 658c63b93e..37729dc90b 100644
--- a/public/src/forum/popular.js
+++ b/public/src/forum/popular.js
@@ -3,8 +3,7 @@
 /* globals define, app, socket*/
 
 define('forum/popular', ['forum/recent', 'forum/infinitescroll'], function(recent, infinitescroll) {
-	var Popular = {},
-		active = '';
+	var Popular = {};
 
 	$(window).on('action:ajaxify.start', function(ev, data) {
 		if(data.url.indexOf('recent') !== 0) {
@@ -21,28 +20,7 @@ define('forum/popular', ['forum/recent', 'forum/infinitescroll'], function(recen
 
 		recent.watchForNewPosts();
 
-		active = recent.selectActivePill();
-
-		infinitescroll.init(loadMoreTopics);
-
-		function loadMoreTopics(direction) {
-			if(direction < 0 || !$('#topics-container').length) {
-				return;
-			}
-
-			infinitescroll.loadMore('topics.loadMoreFromSet', {
-				set: 'topics:' + $('.nav-pills .active a').html().toLowerCase(),
-				after: $('#topics-container').attr('data-nextstart')
-			}, function(data, done) {
-				if (data.topics && data.topics.length) {
-					recent.onTopicsLoaded('popular', data.topics, false, done);
-					$('#topics-container').attr('data-nextstart', data.nextStart);
-				} else {
-					done();
-					$('#load-more-btn').hide();
-				}
-			});
-		}
+		recent.selectActivePill();
 	};
 
 	return Popular;
diff --git a/src/controllers/categories.js b/src/controllers/categories.js
index 705ff09612..c127efed69 100644
--- a/src/controllers/categories.js
+++ b/src/controllers/categories.js
@@ -22,17 +22,15 @@ categoriesController.recent = function(req, res, next) {
 
 categoriesController.popular = function(req, res, next) {
 	var uid = req.user ? req.user.uid : 0;
-	var set = 'topics:' + req.params.set;
-	if(!req.params.set) {
-		set = 'topics:posts';
-	}
 
-	topics.getTopicsFromSet(uid, set, 0, 19, function(err, data) {
+	var term = req.params.term || 'daily';
+
+	topics.getPopular(term, uid, function(err, data) {
 		if(err) {
 			return next(err);
 		}
 
-		res.render('popular', data);
+		res.render('popular', {topics: data});
 	});
 };
 
diff --git a/src/routes/index.js b/src/routes/index.js
index 18ba258d06..dd194e8354 100644
--- a/src/routes/index.js
+++ b/src/routes/index.js
@@ -71,8 +71,8 @@ function tagRoutes(app, middleware, controllers) {
 }
 
 function categoryRoutes(app, middleware, controllers) {
-	app.get('/popular/:set?', middleware.buildHeader, controllers.categories.popular);
-	app.get('/api/popular/:set?', controllers.categories.popular);
+	app.get('/popular/:term?', middleware.buildHeader, controllers.categories.popular);
+	app.get('/api/popular/:term?', controllers.categories.popular);
 
 	app.get('/recent/:term?', middleware.buildHeader, controllers.categories.recent);
 	app.get('/api/recent/:term?', controllers.categories.recent);
diff --git a/src/topics.js b/src/topics.js
index 9788c15ea7..fee909801a 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -18,6 +18,7 @@ var async = require('async'),
 	require('./topics/delete')(Topics);
 	require('./topics/unread')(Topics);
 	require('./topics/recent')(Topics);
+	require('./topics/popular')(Topics);
 	require('./topics/fork')(Topics);
 	require('./topics/posts')(Topics);
 	require('./topics/follow')(Topics);
diff --git a/src/topics/popular.js b/src/topics/popular.js
new file mode 100644
index 0000000000..ea75acd125
--- /dev/null
+++ b/src/topics/popular.js
@@ -0,0 +1,46 @@
+
+'use strict';
+
+var async = require('async'),
+	db = require('./../database');
+
+
+module.exports = function(Topics) {
+
+	Topics.getPopular = function(term, uid, callback) {
+		var terms = {
+			daily: 'day',
+			weekly: 'week',
+			monthly: 'month',
+			yearly: 'year'
+		};
+
+		var since = terms[term] || 'day';
+
+		Topics.getLatestTids(0, -1, since, function(err, tids) {
+			if (err) {
+				return callback(err);
+			}
+
+			getTopics(tids, uid, callback);
+		});
+	};
+
+	function getTopics(tids, uid, callback) {
+		var keys = tids.map(function(tid) {
+			return 'topic:' + tid;
+		});
+
+		db.getObjectsFields(keys, ['tid', 'postcount'], function(err, topics) {
+			topics.sort(function(a, b) {
+				return parseInt(b.postcount, 10) - parseInt(a.postcount, 10);
+			});
+
+			topics = topics.slice(0, 20).map(function(topic) {
+				return topic.tid;
+			});
+
+			Topics.getTopicsByTids(topics, uid, callback);
+		});
+	}
+};
diff --git a/src/topics/recent.js b/src/topics/recent.js
index 255c65a388..99ff00107b 100644
--- a/src/topics/recent.js
+++ b/src/topics/recent.js
@@ -20,7 +20,8 @@ module.exports = function(Topics) {
 		var terms = {
 			day: 86400000,
 			week: 604800000,
-			month: 2592000000
+			month: 2592000000,
+			year: 31104000000
 		};
 
 		var since = terms.day;