"Recently Popular" WordPress Plugin
Download the Recently Popular plugin
I’ve used a few different plugins to manage the most popular post display on my sidebar. None of them behaved quite the way I wanted. The two major groups and their issues for me were:
- Post counts last forever: This is a big deal if an article gets Dugg or Slashdotted. That post may live at the top of your most popular list long past its useful lifespan.
- Formula-based: These use some formula of views, comments, and who-knows-what-else to try and derive what is most popular. These also count things into perpetuity, but generally they discount dated items as they age. The fact that views aren’t dated is still a problem.
I knew what I wanted. I wanted a popularity meter that I could tell “Show the posts that have been most viewed over the last 7 days.” Or 3 weeks. Or 12 hours. Or whatever. However I couldn’t find it. So I wrote a plugin (with widget!) to do just that. It records hits to any post or page on your site by any user who isn’t logged in, then allows you to display the most active ones for your defined time period on your sidebar.
The widget can be added to your sidebar more than once, so if you want to show the most popular over the last five days and the most popular over the last month you can.
Output formatting
The widget supports formatting strings for items in the results. These formatting strings accept HTML, so you can be as creative as you want. The template supports the following tags:
- %post_title% – the post’s title
- %post_excerpt% – the post’s excerpt
- %post_url% – the post’s permalink
- %hits% – the number of qualifying views
- %display_name% – the post’s author
- %user_url% – the post author’s URL
- %publish_date% – the post’s publish date
- %category% – the categories the post is in
- %thumbnail_url% – the URL for the post’s thumbnail
To simply show the post titles as links to the post you would use this tag (note: this is the default output format):
<a href="%post_url">%post_title%</a> |
The widget defines this and two other typical tags that you to simply click on and use without having to figure out the templating.
Using in Themes Without Widget Support
To install this plugin in a theme that doesn’t support widgets you add something similar to this to your template:
<ul><?php $rp = new RecentlyPopular(); $rp->get_counts(); ?></ul> |
The get_counts() function takes a single parameter that is an array of the options. The options and their defaults are (default options in bold where applicable):
| Option | Values |
|---|---|
| Description | |
| title | ‘Recently Popular’ |
| Title for the emitted ul. Primarily used by the widget. | |
| enable_categories | true false |
| Determines if category filtering is used. | |
| categories | n/a |
| Category names in single quotes, separated by commas. Ignored if enable_categories is false. | |
| date_format | ‘Y-m-d’ |
| PHP date format to use for date output tags. | |
| default_thumbnail_url | n/a |
| URL to a default thumbnail image to use when no thumbnail is found. Prevents empty images from showing. | |
| display | true false |
| If true the call will emit an unordered list, if false it will return that list from the function call. | |
| interval_type | ‘HOUR’ ‘DAY’ ‘WEEK’ ‘MONTH’ ‘YEAR’ |
| The type of interval to use. | |
| interval_length | 1 |
| Integer value for the number of interval_type to display. | |
| limit | 10 |
| Integer value for the number of results to display. | |
| max_length | 0 |
| Integer value for truncating the title. 0 means no limit. | |
| max_excerpt_length | 0 |
| Integer value for truncating the excerpt. 0 means no limit. | |
| output_format | ‘%post_title%‘ |
| String defining how each result will display. See Output Formatting above. | |
| post_type | RecentlyPopularPostType::ALL RecentlyPopularPostType::PAGES RecentlyPopularPostType::POSTS |
| The type of results to get. | |
| user_type | RecentlyPopularUserType::ALL RecentlyPopularUserType::ANONYMOUS RecentlyPopularUserType::REGISTERED |
| The type of results to get. |
For example, this will show the five most viewed posts (without pages) in the past three weeks by users who weren’t logged in:
<ul><?php $rp = new RecentlyPopular(); $rp->get_counts(array( 'limit' => 5, 'post_type' => RecentlyPopularPostType::POSTS, 'user_type' => RecentlyPopularUserType::ANONYMOUS, 'interval_length' => 3, 'interval_type' => 'WEEK', )); ?></ul> |



Hello,
Version 0.6.2 with WP 3.2.1
I notice when I clear out count entries older than, say, two months, any newer and popular posts are not shown in the listing. The database is updating new views just fine and a routine look at the data shows some of the newer posts are high enough to be easily in the top 3 or so in the rankings.
At first I thought you might be sorting the database in its natural order and new entries might be taking up the space of the deleted entries (weird MySQL thing), however, I see you are sorting, I think, on the timestamp so I don’t know what is going on.
On a separate note, I tried updating to the latest version 0.7.1 using the latest 3.2.1 of WP but it failed the whole site. I restored recently-popular from backups and all it well again… except for the above peculiar behavior.
Apologies in advance if you addressed this issue in some release between 0.6.2 and the latest.
John
There was an earlier bug where it deleted counts newer than instead of older than. Sounds like the problem you’re having. Honestly I’m more interested in why the 0.7 branch failed. Can you get me some error logs?
Hi Eric,
I was wondering if there was a way to call an image or meta key from the post itself along with the link,author,etc.
[...] "Recently Popular" WordPress Plugin [...]
I love your plugin. It works better than any other one I’ve found.
I’m trying to put icons before the posts that the widget lists. I found the excellent Category Icons plugin that allows me to attach icons to categories.
What I want to do is to have the icons show up in the RECENTLY POPULAR widget before the post title.
The Category Icons plugin provides this code that I could use to create my own widget and the code below can be used inside another widet:
$listing_code = ”;
foreach(get_categories(“orderby=count&order=DESC”) as $category) {
$listing_code .=get_cat_icon(“echo=false&cat=”.$category->cat_ID).” “;
}
$listing_code .= ”;
echo $listing_code;
So I want to combine the code that you provide with the Category Icons code. The problem is that I don’t know how to integrate that with your code that you provided:
get_counts(array(
‘limit’ => 5,
‘post_type’ => RecentlyPopularPostType::POSTS,
‘user_type’ => RecentlyPopularUserType::ANONYMOUS,
‘interval_length’ => 3,
‘interval_type’ => ‘WEEK’,
));
?>
The Category Icons code will show Category Icons side by side as detailed in this post:
http://www.category-icons.com/2010/02/how-to-display-category-icons-side-by-side/
I want to put the category icons before the post title.
How would I fit the two together?
@Kegan:
get_counts can return the li’s instead of writing them to the page by passing in ‘display’ => false in your params array. Then you could parse them any way you wanted through your loop and write them into the page yourself.
@Eric,
Thank you for your response.
I’m really trying to learn how to understand PHP and it’s various elements but I am still a little lost.
I have 2 questions for you.
1. What’s the best way for someone who has a basic understanding of PHP to learn more about how to read and code plugins? How did you learn?
2. I am really trying to understand what you wrote in your response, but I just don’t understand all the terminology you used yet. What it sounds like you’re saying is that I can put the code in my theme files so that it shows up on pages/posts themselves. Actually what I am looking to do is show the icons before the post titles both on page and in the sidebars.
The reason I wrote to you here is because I like your plugin, and want the icons to display before the titles of the posts that your plugin displays.
What I really want to do is learn how to create a plugin that would put icons before post titles no matter where they appear: sidebar or in pages themselves. I like the categories icons plugin since I can assign icons to posts.
If you were me, how would you go about learning how to do this?
I really appreciate you taking the time to respond to me originally and thank you for any direction you are able to offer. Thank you.
@Kegan:
To answer question one, one of the problems with PHP as a language is that there are so many ways to do any one thing. Because of that you tend to get people with lots and lots of different coding styles and that can make it very difficult to read other people’s PHP code. I’ve been coding for about 20 years now and done production software in PHP, Python, Java, Perl, C#, C, C++, Visual Basic… you get the idea. I’ve seen PHP code written in the style of all those languages and more. So how do you read other people’s PHP code? Slowly, carefully, and with a lot of Googling.
The answer to question #2 is a longer explanation. When you call the get_counts function of RecentlyPopular it will eventually create one HTML list item (li) for each article in the results. When it’s done creating the list items and doing all of the substitutions it will, by default, echo that result into the page right where the function was called (line 304 of recently-popular.php in version 0.7.2). If you pass in the parameter display=false then 305 executes instead and get_counts returns a string that contains all the HTML it would have otherwise printed into the page., so you could call that like this and get effectively the same result as just calling the function:
So if you replace the “Do some stuff” comment above with code that will modify the output how you’d like it then you’re good to go. Right now Recently Popular only returns category names, so you’ll need to get the category ids for the other plugin with something like this:
So the basic todo list is going to be something like this:
Creating a plugin to always put an icon before a post title, no matter where it appeared, might be a pretty significant undertaking. It’s going to be difficult to parse a large block of text and decide what is or isn’t a page title, and probably pretty cpu-expensive. You’ll need to use a filter to get the text of a page before it’s rendered (something like http://codex.wordpress.org/Plugin_API/Filter_Reference/the_content).
As for learning to do plugins I would recommend a book. If you try to learn by example on the Internet you’re going to probably spend a lot of time trying to figure out what parts are different because of coding styles and what differences are actually important. I own a copy of Professional WordPress Plugin Development and I’ve read a few of the chapters and been pleased. Of course even after you finish any book you’re likely going to develop your own style.
Good luck. If you get your plugin finished let me know.
Hi Eric,
I love your plugin, but may I suggest you some enhancements?
It would be wonderfull that you could add a parameter to the get_counts function to return only the posts. In fact what I say is adding a “return $most_viewed” before the loop where you build the li’s list.
In my case I’d like to use this posts directly on my own loop to get some custom fields that I set on them.
My second enhancement will be the ability to manage custom post types. With this version we only can get either post types “posts/pages” or all the kinds of posts.
Otherwise, I really love your plugin, in fact it fills a concrete need and do it very well.
@David,
I appreciate the suggestions. Kegan’s questions earlier I think reinforce the need to return the unformatted data for sure.
Hi again Eric,
for the custom post type I modified your plugin in a way that suits my needs.
Hope you’ll add my customizations to your code in a near future releases if these are OK for you.
In recently-popular.php I add a new case statement on your switch ($o['post_type'] ) {
case RecentlyPopularPostType::CUSTOM :
if ( !is_array($o['post_type_custom']) )
{
$o['post_type_custom']=explode(‘,’,$o['post_type_custom']);
}
$wc_post_type = ” AND `p`.`post_type` IN ( ‘” . implode( $o['post_type_custom'], “‘,’” ) . “‘ )”;
break;
This allows you to specify concrete custom types as an array/string.
And in include.php I add the CUSTOM constant to the RecentlyPopularUserType class.
I forgot something, add OR conditions when you check for the categories.
if ($o['post_type'] == RecentlyPopularPostType::POSTS )
changes to
if ($o['post_type'] == RecentlyPopularPostType::POSTS || $o['post_type'] == RecentlyPopularPostType::CUSTOM)
That’s all.
Hello Eric
I have noticed that the new week in the plugin starts on Sunday. Can this be changed to start on Monday and if so will it mess up the read counts. Thanks
I’m still not able to add a thumbnail. Where do I add
%thumbnail_url%
to
“%post_url%”>%post_title%
to get a thumbnail to show?
Thanks
I meant
Where do I add
%thumbnail_url%
to
%post_title% (%hits%)
to get a thumbnail to show?
@Marko:
You would need to create an image tag:
<img src=”%thumbnail_url%” /><a href=”%post_url”>%post_title%</a>
If you’re going to use thumbnail_url you should also set the default_thumbnail_url option in the function call (this can also be set in the widget) so that there is a default image to display if one or more of your posts don’t have a thumbnail image.
hi! thanks for this wonderful plugin… I’m just only wondering why it isn’t include post with a title that starts with a number? for example, this post on my blog http://www.organicroomgames.com/2011/10/16/7-wonders-iv-magical-mystery-tour/
I already viewed many times it doesn’t appear in the widget.
hello! I just noticed, It’s showing now… please ignore my previous post. Thanks!
Good to hear. I was trying to figure out what on Earth would cause it to care about numbers as the leading character. My first guess is that you have the widget set to not count views by logged in users so it was ignoring your views.
Is that possible to use a numbering instead of a bullets? If I have 10 popular posts I want the output like this:
1. Post #1
2. Post #5
3. Post #20
4. Post #6
5. Post #3
6. Post #15
7. Post #10
8. Post #9
9. Post #18
10. Post #2
Try wrapping your function call with an <ol> (ordered list) instead of a <ul> (unordered list).
Hi Eric,
I use featured images in all of my blog posts and I wonder if there is any way this plug-in can call these featured images into the recently popular posts.
How can I insert post thumbnail if my theme doesn’t support widgets?
I’ll appreciate your help on this wonderful plug-in.
Best,
Chris.
Hello thanks for the plugin i’m using it on my site.
Just a question : is there a way to get only the posts published in a date range ?
ie: i would like to only have the post published last 7 days to show up.
thanks
OK nevemind I found out with interval_length.
Great plugin.
2 others questions :
1. CACHING : does the plugin supports caching ? I have 150000+ posts and I use W3 Total CACHE. Does it still counts post views when caching is able?
2. PERFORMANCE : is the plugin well optimized for a high load production environnement ?
Thanks again, great plugin!
1. The new versions of the caching plugins all intercept the requests before they even hit WP. Because of that it pretty much screws up any plugins that require hooks, including Recently Popular.
2. The plugin is as optimized as it can be based on how it does things. However, I do *not* recommend using this plugin on high-traffic sites. If you’re getting hundreds of hits per minute then you’d really need to reexamine how to determine what’s popular right now.
I would imaging that on a high-traffic site using W3 Total Cache you’d have to use some sort of AJAX request or somehow inject some code into the htaccess rules to register the views.
arghhh… back to the 1st question.. the “interval_length” is only for the count views, and not for the “post date”…
I need to have only the posts posted last 7 days to show up.. Can I quickly modified a line of your php script to have this working ?
Thanks again!
There’s no simple one liner that you can use to make that change. You’d have to make a change to the SQL query to eliminate older posts.
Hi Eric,
Love your plugin. How can I choose/modify your code to pick or generate smaller thumbnails? eg: 40×40 or 48×48
Thanks
The simplest way is to resize them in the HTML. The longer, correct way is to register a different thumbnail size and change the plugin to use that new size.
http://codex.wordpress.org/Function_Reference/add_image_size
Thanks for providing an excellent plugin.
I have been trying to use your plugin code in theme pages. Because I do not want to use for listing posts, instead I am trying to list them in a layout which I like.
I have read your comments above in trying to help Kegan. Is there any way i can use your SQL query directly into the code?
I have tried this approach with many plugins and was successful. But your SQL query is bit different. If you can please help me modifying it it would be great.
I am trying to apply your code on different content styles in my theme pages. I am trying to retrieve data and then pass it on to a Loop which will layout data the way I want:
This is the query which I have come up after some changes and need your help here. I’m trying to list most read 5 articles from category “4309″ in last two hours?
$sql=”SELECT
`rp`.`hits` AS `hits`,
`rp`.`postid` AS `post_id`,
`p`.`post_title` AS `post_title`,
`p`.`post_excerpt` AS `post_excerpt`,
`p`.`post_date` AS `post_date`,
`p`.`post_type` AS `post_type`,
`u`.`display_name` AS `display_name`,
`u`.`user_url` AS `user_url`,
GROUP_CONCAT(DISTINCT `t`.`name` ORDER BY `t`.`name` SEPARATOR ‘, ‘) AS `category`
FROM ( SELECT
COUNT(`post_id`) AS `hits`,
MIN(`ts`) AS `ts`,
MIN(`user_type`) AS `user_type`,
MIN(`post_id`) AS `postid`
FROM `wp_recently_popular`
WHERE `ts` > (CURRENT_TIMESTAMP() – INTERVAL 2 HOUR)
GROUP BY `post_id`
ORDER BY `hits` DESC
) AS `rp`
LEFT JOIN `wp_posts` AS `p` ON `rp`.`postid` = `p`.`ID`
LEFT JOIN `wp_users` AS `u` ON `p`.`post_author` = `u`.`ID`
LEFT JOIN `wp_term_relationships` AS `tr` ON `p`.`ID` = `tr`.`object_id`
LEFT JOIN `wp_term_taxonomy` AS `tt` ON `tr`.`term_taxonomy_id` = `tt`.`term_taxonomy_id`
LEFT JOIN `wp_terms` AS `t` ON `tt`.`term_id` = `t`.`term_id`
WHERE 1
AND `rp`.`user_type` = ’0′
AND `p`.`post_type` = ‘post’
AND `tt`.`taxonomy` = ‘category’
AND `t`.`name` IN (’4309′)
AND `rp`.`postid` = ”
GROUP BY `rp`.`postid`
ORDER BY `rp`.`hits` DESC, `rp`.`ts` DESC
LIMIT 5″;
Do you think your query can be modified and can be directly used inside the code?
It sounds like you have a pretty specific use-case. You’d probably be better off forking the code and modifying the get_counts() function to work differently.
Thanks for your quick reply.
I also tried your function in body – how are we supposed to filter by category names? I have tried putting category name, slug, id with and without quotes but it’s not filtering it properly.
Could you please tell me how to apply category filter properly?
get_counts(array(
‘enable_categories’ =>true,
‘categories’ => ‘Landscape’,
‘limit’ => 5,
‘post_type’ => RecentlyPopularPostType::POSTS,
‘user_type’ => RecentlyPopularUserType::ANONYMOUS,
‘interval_length’ => 3,
‘interval_type’ => ‘WEEK’,
));
?>
“Category names in single quotes, separated by commas.” So for the call you posted:
get_counts(array(
‘enable_categories’ =>true,
‘categories’ => “‘Landscape’”,
‘limit’ => 5,
‘post_type’ => RecentlyPopularPostType::POSTS,
‘user_type’ => RecentlyPopularUserType::ANONYMOUS,
‘interval_length’ => 3,
‘interval_type’ => ‘WEEK’,
));
Basically all it’s doing is taking what you have in the string and using it as a “where in” clause.
Hi Eric,
I have gone through all the comments. I do not have lots of experience in php. Is it possible to tweak this code to pull an image attached with defined custom field value?
$images =& get_children(‘post_type=attachment&post_mime_type=image&order=ASC&post_parent=’.$post->post_id);
$img = wp_get_attachment_image_src(array_shift(array_keys($images, ‘biggerimage’)));
$img_url = $img[0];
Hello, just testing it and great job you made here. I found maybea bug/problem. Using in ‘output_format’ in php like this :
'%category% (%hits%) %post_title%%publish_date% - %post_excerpt%'
All works except the excerpt. An idea ?
And maybe another question : i am using the add theme support function. Is it possibile to display the thumbnail of the post ? %thumbnail_url% should have which value in this case ? Thansk a lot, & carry on your good work. Wanting this plugin to replace apkc popularity form alex.