Hefta-Gaub Development Blog

March 11, 2007

WPMU- Top Posts Plugin

Filed under: Wordpress plugins, WordpressMU, development — zappoman @ 7:46 am

I’ve hacked together a prototype of a Top Posts plugin for WordPressMU.

The concept is to create a global table that stores the blog_id, post_id, and time for each hit to a post/page, and then allows you to get list of the posts with the most hits. This is an early early version.

You can download it here.

Installation:

Put this php file in your ‘wp-content/mu-plugins’ directory. Sit back and enjoy.

Usage:

The simple version would be to call:

<?php zap_top_posts_html(); ?>

This will return a <ul>…</ul> block of html.

But you can also use this much like you would use get_posts() in any template. For example, the following should also work…

<ul>
 <?php
 $myposts = zap_get_top_posts();
 foreach($myposts as $post) :
 ?>
    <li><a href="<?php echo $post->guid; ?>">
	<?php the_title(); ?></a>
	[<?php zap_the_post_hits(); ?>]</li>
 <?php endforeach; ?>
</ul>

Anyway, this is just a prototype. I haven’t really done that much testing. I have no idea how well it will perform in general. I know there are a couple bugs in there. As I fine tune this, I will post additional updates.

Known issue: You can’t use the get_permalink() and the_permalink() tags becuase they depend on other global variables that are not properly set up with these functions. If you want the link to the post use $post->guid.

22 Comments »

  1. Great idea, though it needs some more developing…
    I tried it, but it didn’t seem to fetch posts from any other blog than the main blog.

    Comment by henry — March 27, 2007 @ 1:02 pm

  2. Henry, Thanks for the heads up, yes I noticed that the the_permalink() template doesn’t always work. I have this code working by using the code below… and it shows the posts from multiple blogs just fine.. I have noticed that sometimes some of the tag templates don’t always work, so if you could tell me more about the code you used it would help me debug it…

    Did you set $post to global?

    here’s an example of what I currently have running…


    <?php

    global $post; /* needs to be global if you want get_permalink() and get_the_title() to work. */

    $top_posts = zap_get_top_posts();

    $html="";

    foreach($top_posts as $post)
    {
    $html.="guid."' title='".$post->guid."'>".get_the_title()."[".$post->post_hits."]";
    }
    $html.="";
    echo $html;
    ?>

    Comment by zappoman — March 27, 2007 @ 3:03 pm

  3. I’ve looked into the issue that Henry mentioned, and it appears as if the the_permalink() and get_permalink() are at least two functions that depend on another deeper global variable inside of wordpressMU called $current_blog. So my original understanding that simply setting the global $post would work does not.

    However, have no fear… if you stick with using $post->guid, you should get the correct link. I’ve changed the example above to reflect this.

    Comment by zappoman — March 27, 2007 @ 5:12 pm

  4. The setup-function collides with creation of new blogs, because the require_once of “upgrade-functions.php” collides with the same line in wpmu_functions.php/install_blog. I commented out the body of that function after the table had been created, but someone a bit more WP-savvy should devise a permanent solution

    Comment by Nis Jorgensen — March 28, 2007 @ 10:26 am

  5. Nis, thanks for the heads up. I will look into this…

    Like I said, I hadn’t tested it extensively, I guess I haven’t created a new blog since adding this. Kinda silly to have not tested that? Eh? ;)

    Comment by zappoman — March 28, 2007 @ 4:46 pm

  6. Changing the setup function as follows will address this problem. I will update a patch to this later… Thanks Nis for pointing this out.


    /******************************************************************
    * Method: setup()
    * Purpose: creates our tracking table if needed.
    *****************************************************************/
    function setup()
    {
    /*
    * make sure the upgrade-functions for maybe_create_table is available
    */
    if (function_exists('maybe_create_table'))
    {
    $table_hits_query = "CREATE TABLE $this->table_hits (
    id int(11) unsigned NOT NULL auto_increment,
    blog_id BIGINT(20) unsigned NOT NULL,
    post_id BIGINT(20) unsigned,
    hit_time int(10) unsigned NOT NULL default '0',
    UNIQUE KEY id (id)
    )";
    maybe_create_table($this->table_hits, $table_hits_query);
    }
    }

    Comment by zappoman — March 28, 2007 @ 4:55 pm

  7. Note, I’ve updated the code to 0.42.1 with the following changes…

    Small bug fix to ‘maybe_create_table’ behavior. Namely, we used to try to load it if this function wasn’t available, and now we simply check that the function is available.

    Added blog_id to the posts returned by get_top_posts. This can be useful in forming correct permalinks to your blog posts.

    Added function zap_setup_post_globals() which in some cases will setup the globals for other wordpressmu templates to work, but this doesn’t always reliably work.

    Comment by zappoman — April 6, 2007 @ 12:49 am

  8. I have commented out the call to “update_post_caches”, since this caches all the posts in the cache for the current blog. I am not sure exactly why we would need to call this, but the comment above it seems to indicate that the author did not consider it too important either.

    Comment by Nis Jorgensen — April 18, 2007 @ 1:53 pm

  9. Hey Zappoman—

    Nice script! I’ve learned some cool things about writing an object-oriented plugin for WordPress.

    I found one bug — the hits for deleted blogs stay in the `top_hits` table, which causes the FK constrain to break. Here’s the patch I wrote for that (tested on my beta site; seems to work ;-) ):

    `
    — wpmu-topposts.php 2007-06-04 16:36:07.000000000 -0700
    +++ wpmu-topposts-fredcode.php 2007-06-04 16:35:10.000000000 -0700
    @@ -685,6 +685,17 @@

    return $html;
    }
    +
    + /*
    + * Method: delete_blog
    + * Purpose: Removes a blog’s entries from the top_hits table.
    + */
    + function delete_blog($blog_id, $drop) {
    + global $wpdb;
    +
    + if ($drop)
    + $wpdb->get_results(“DELETE from $this->table_hits where blog_id=’$blog_id’”);
    + }
    };

    // This will be our main “tracking object” we will keep things nice and
    @@ -698,6 +709,8 @@
    // This hook will be called for every page.
    add_action(’shutdown’, array(&$zap_wpmutp, ‘recordhit’));

    +// This hook will be called when a blog is deleted
    +add_action(‘delete_blog’, array(&$zap_wpmutp, ‘delete_blog’));

    /*
    * Function: zap_get_top_posts()
    `

    Comment by Fredcode — June 5, 2007 @ 5:42 am

  10. Thanks FredCode… that’s a good mod. I actually have made some related changes to the code but it’s not quite ready to release yet.

    The change I made was to “keep trying” to get posts if the posts that come back from the table_hits query are missing. This can happen in the case of posts being deleted (but not the whole blog being deleted) as well.

    My approach was to just keep doing recursive queries until I got enough posts to fulfill the requested $numberposts… But maybe using hooks is a better approach.

    I’ll do a release soon with a bunch of new features including caching.

    Comment by zappoman — June 5, 2007 @ 6:37 am

  11. Yeah, it makes sense to me to make incremental updates to the top_hits table as posts are deleted — a slight overhead at the “front-end” of deleting the post in exchange for less work to fetch the posts.

    However, even doing that, you’ve still got to cover the case where the post / blog has been deleted and your hooks (for whatever reason) didn’t run. I’d suggest throwing in a JOIN to the wp_*_posts tables on the SELECT, but that could be a tedious chore to write and debug.

    Look forward to your next release. Keep on hackin’, dude!

    Comment by Fredcode — June 22, 2007 @ 12:21 am

  12. Hey, i Love this plugin, just a little suggestion, it would be great if the hits had delay, i mean that the if the hit was not counted in the loading moment but 30 second after loading and staying on the page it would bring up more accurate results of popularity and interestingness.

    Just i suggestion, sorry my english i dont speak it very well :) i love youre plugins :)

    *bye*

    Comment by Ana — June 26, 2007 @ 10:45 pm

  13. Installed the Plugin, inserted the PHP tag, and got this:
    [Table 'wordpress.1_posts' doesn't exist]
    SELECT *,’2′ AS ‘post_hits’,'1′ AS ‘blog_id’ FROM 1_posts WHERE ID = 13

    Help?

    Comment by Tomer — July 28, 2007 @ 1:09 pm

  14. Tomer, are you using WordPressMU? This looks like something is broken in the core classes… or as if you are using WordPress instead of WordPressMU.

    Comment by zappoman — July 28, 2007 @ 11:25 pm

  15. Great plugin! Just what I have been searching for. I’ve noticed 1 bug though that is easily fixed. At the end of get_top_blogs_html() you have $html.=$before_list; instead of $html.=$after_list; which results in instead of creating invalid html. Thanks again!

    Comment by FatBits — October 5, 2007 @ 1:28 am

  16. Thanks for sharing FatBits… yes, that’s a bug alright…

    Actually, I’ve significantly changed this plugin since I released it… but I haven’t released a new version in a while. I should really get around to that some day. ;)

    Comment by zappoman — October 5, 2007 @ 3:07 am

  17. [...] Visit [...]

    Pingback by WordPress Plugins Database » Plugin Details » zappo_wpmu_topposts — October 17, 2007 @ 12:36 pm

  18. Hi

    I am using wpmu 1.3, i am using zappo_wpmu_topposts and using the following, the plugin is in the mu-plugin dir;

    I get no results at all,

    Comment by gordo — November 15, 2007 @ 10:33 am

  19. This plugin sounds like what I’m looking for, except that I would love to be able to call get_top_posts() and limit the result to just one blog whose ID I would pass as a parameter.

    Comment by Jacob Share — November 20, 2007 @ 8:58 pm

  20. Great Plugin, tested with wpmu 1.3 fine, couple things

    1. How can i exclude Hello world! posts from showing in results from zap_get_top_posts?
    2. Do you have example of multiple ways i can format the results to show blogname, post name and various ways of showing the results?

    Thanks for the great work

    Comment by gordob — November 22, 2007 @ 7:45 am

  21. Nice script, but it has some problems:

    It doesn’t quite work right with version 2.3.3 of WPMU. I get two blog hits for each view, and sometimes the post_id gets stuck at the same number. I had to use this code to make it work properly:

    $urlRequested = “http://” . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
    $post_id = url_to_postid($urlRequested);

    There’s an easy way to combat potential fraud as well. Just change the timestamp to only use month-day-year, add an ip_addr column, remove the unique key id column, make blog_id+post_id+hit_time+ip_addr the new unique, then finally change your insert to a replace.

    That change will only allow each ip address to count one hit per post per day, and one hit per blog per day.

    Comment by NK5 — March 11, 2008 @ 6:15 am

  22. I found a better, more reliable way to get the correct post id in version 2.3.3:

    global $blog_id,$posts, $single;
    if($single == 1) {
    $post_id=$posts[0]->ID;
    }

    Comment by NK5 — March 12, 2008 @ 5:05 am


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.