<?php
/*
Plugin Name: Popularity Contest
Plugin URI: http://www.alexking.org/software/wordpress/
Description: This will enable ranking of your posts by popularity; using the behavior of your visitors to determine each post's popularity. You set a value (or use the default value) for every post view, comment, etc. and the popularity of your posts is calculated based on those values. Once you have activated the plugin, you can configure the <a href="options-general.php?page=popularity-contest.php">Popularity Values</a> and <a href="index.php?page=popularity-contest.php">View Reports</a>. You can also use the included <a href="options-general.php?page=popularity-contest.php#akpc_template_tags">Template Tags</a> to display post popularity and lists of popular posts on your blog.
Version: 1.1 sc3
Author: Alex King
Author URI: http://www.alexking.org/

Tweaks by Bennett (http://www.thunderguy.com/semicolon/)
- include Pages as well as Posts in all but date-based reports
- fix incompatibility with Google Sitemaps plugin (and possibly others) for WordPress 1.5.2+
- don't show post popularity by default
*/ 

// Copyright (c) 2005 Alex King. All rights reserved.
// http://www.alexking.org/software/wordpress/
//
// Released under the GPL license
// http://www.opensource.org/licenses/gpl-license.php
//
// This is an add-on for WordPress
// http://wordpress.org/
//
// **********************************************************************
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
// **********************************************************************
//
// Known Issues
// - When spam comments/pingbacks/trackbacks are deleted or marked as
//   spam, their value is not always removed from the posts they were
//   applied to. This is because the hooks in WP do not seem to fire
//   consistently with sufficient data. Hopefully this will be fixed in 
//   a future release of WP.


/* -- INSTALLATION --------------------- */

// Change this to "0" below if you don't want to show each post's popularity with the post content

$ak_show_popularity_with_post 1;

// Chnge this to "0" to disable showing poplarity in home (index.php)

$ak_show_popularity_home 0;

// If you would like to show lists of popular posts in the sidebar, 
// take a look at how it is implemented in the included sidebar.php.

/* ------------------------------------- */


if (!isset($wpdb)) {
    require(
'../../wp-blog-header.php');
}

// Initialization (this function protects itself, only the 1st init will go through)
akpc_init();

load_plugin_textdomain('alexking.org');

// -- MAIN FUNCTIONALITY

class ak_popularity_contest {
    var 
$feed_value;
    var 
$home_value;
    var 
$archive_value;
    var 
$category_value;
    var 
$single_value;
    var 
$comment_value;
    var 
$pingback_value;
    var 
$trackback_value;
    var 
$logged;
    var 
$options;
    var 
$top_ranked;
    var 
$current_posts;
    
    function 
ak_popularity_contest() {
        
$this->options = array(
            
'feed_value'
            
,'home_value'
            
,'archive_value'
            
,'category_value'
            
,'single_value'
            
,'comment_value'
            
,'pingback_value'
            
,'trackback_value'
        
);
        
$this->feed_value 1;
        
$this->home_value 2;
        
$this->archive_value 4;
        
$this->category_value 6;
        
$this->single_value 10;
        
$this->comment_value 20;
        
$this->pingback_value 50;
        
$this->trackback_value 80;
        
$this->logged 0;
        
$this->top_ranked = array();
        
$this->current_posts = array();
    }
    
    function 
get_settings() {
        global 
$wpdb;        
        
$result mysql_query("
            SELECT *
            FROM $wpdb->ak_popularity_options
        "
) or die(mysql_error());
        
        if (!
$result) {
            return 
false;
        }
        
        while (
$data mysql_fetch_object($result)) {
            if (
in_array($data->option_name$this->options)) {
                
$temp $data->option_name;
                
$this->$temp $data->option_value;
            }
        }
        
        return 
true;
    }
    
    function 
install() {
        global 
$wpdb;
        
$result mysql_query("
            CREATE TABLE `$wpdb->ak_popularity_options`
            (
                `option_name` VARCHAR( 50 ) NOT NULL
                , `option_value` VARCHAR( 50 ) NOT NULL
            ) 
        "
) or die(mysql_error());
        
        if (!
$result) {
            return 
false;
        }
    
        
$this->default_values();

        
$result mysql_query("
            CREATE TABLE `$wpdb->ak_popularity`
            (
                `post_id` INT( 11 ) NOT NULL 
                , `total` INT( 11 ) NOT NULL 
                , `feed_views` INT( 11 ) NOT NULL 
                , `home_views` INT( 11 ) NOT NULL 
                , `archive_views` INT( 11 ) NOT NULL 
                , `category_views` INT( 11 ) NOT NULL 
                , `single_views` INT( 11 ) NOT NULL 
                , `comments` INT( 11 ) NOT NULL 
                , `pingbacks` INT( 11 ) NOT NULL 
                , `trackbacks` INT( 11 ) NOT NULL 
                , `last_modified` DATETIME DEFAULT 'NOW' NOT NULL
                , KEY `post_id` ( `post_id` )
            ) 
        "
) or die(mysql_error());
        
        if (!
$result) {
            return 
false;
        }
        
        
$this->mine_data();
        
        return 
true;        
    }
    
    function 
default_values() {
        global 
$wpdb;
        foreach (
$this->options as $option) {
            
$temp $this->$option;
            
$result mysql_query("
                INSERT 
                INTO $wpdb->ak_popularity_options
                VALUES
                (
                    '$option'
                    , '$temp'
                )
            "
) or die(mysql_error());
    
            if (!
$result) {
                return 
false;
            }
        }
        
        return 
true;
    }
    
    function 
update_settings() {
        global 
$wpdb;
        foreach (
$this->options as $option) {
            if (isset(
$_POST[$option])) {
                
$this->$option intval($_POST[$option]);
                
$temp $this->$option;

                
$result mysql_query("
                    UPDATE $wpdb->ak_popularity_options
                    SET option_value = '$temp'
                    WHERE option_name = '$option'
                "
) or die(mysql_error());
                
                if (!
$result) {
                    return 
false;
                }
            }
        }

        
$this->recalculate_popularity();

        
header('Location: '.get_bloginfo('wpurl').'/wp-admin/options-general.php?page=popularity-contest.php&updated=true');
        die();
    }
    
    function 
recalculate_popularity() {
        global 
$wpdb;
        
$result mysql_query("
            UPDATE $wpdb->ak_popularity
            SET total = (home_views * $this->home_value)
                + (feed_views * $this->feed_value)
                + (archive_views * $this->archive_value)
                + (category_views * $this->category_value)
                + (single_views * $this->single_value)
                + (comments * $this->comment_value)
                + (pingbacks * $this->pingback_value)
                + (trackbacks * $this->trackback_value)
        "
) or die(mysql_error());
    }
    
    function 
reset_data() {
        global 
$wpdb;
        
$result mysql_query("
            TRUNCATE $wpdb->ak_popularity
        "
) or die(mysql_error());
        
        if (!
$result) {
            return 
false;
        }

        
$result mysql_query("
            TRUNCATE $wpdb->ak_popularity_options
        "
) or die(mysql_error());

        if (!
$result) {
            return 
false;
        }
        
        
$this->default_values();
        
        return 
true;
    }

    function 
create_post_record($post_ID = -1) {
        global 
$wpdb;
        if (
$post_ID == -1) {
            global 
$post_ID;
        }
        
$result mysql_query("
            SELECT post_id
            FROM $wpdb->ak_popularity
            WHERE post_id = '$post_ID'
        "
);
        if (
mysql_num_rows($result) == 0) {
            
$result mysql_query("
                INSERT 
                INTO $wpdb->ak_popularity
                VALUES
                (
                    '$post_ID'
                    , '0'
                    , '0'
                    , '0'
                    , '0'
                    , '0'
                    , '0'
                    , '0'
                    , '0'
                    , '0'
                    , '"
.date('Y-m-d H:i:s')."'
                )
            "
) or die(mysql_error());
        }
    }
    
    function 
delete_post_record($post_ID = -1) {
        global 
$wpdb;
        if (
$post_ID == -1) {
            global 
$post_ID;
        }
        
$result mysql_query("
            DELETE 
            FROM $wpdb->ak_popularity
            WHERE post_id = '$post_ID'
        "
) or die(mysql_error());

    }
    
    function 
mine_data() {
        global 
$wpdb;
        
        
$posts mysql_query("
            SELECT ID
            FROM $wpdb->posts
            WHERE post_status IN ('publish','static')
        "
) or die(mysql_error());
        
        if (
$posts && mysql_num_rows($posts) > 0) {
            while (
$post mysql_fetch_object($posts)) {
                
$this->create_post_record($post->ID);
                
$this->populate_post_data($post->ID);
            }
        }
        
        return 
true;
    }
    
    function 
mine_gap_data() {
        global 
$wpdb;
        
$posts mysql_query("
            SELECT p.ID
            FROM $wpdb->posts p
            LEFT JOIN $wpdb->ak_popularity pop
            ON p.ID = pop.post_id
            WHERE pop.post_id IS NULL
        "
) or die(mysql_error());
        
        if (
$posts && mysql_num_rows($posts) > 0) {
            while (
$post mysql_fetch_object($posts)) {
                
$this->create_post_record($post->ID);
                
$this->populate_post_data($post->ID);
            }
        }
    }
    
    function 
populate_post_data($post_id) {
        global 
$wpdb;
// grab existing comments
        
$result mysql_query("
            SELECT comment_ID
            FROM $wpdb->comments
            WHERE comment_post_ID = '$post_id'
            AND comment_type = ''
            AND comment_approved = '1'
        "
) or die(mysql_error());
        
        
$count mysql_num_rows($result);

        if (
$result && $count 0) {

// increase post popularity
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET comments = comments + $count
                , total = total + "
.($this->comment_value $count)."
                WHERE post_id = '$post_id'
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }

// grab existing trackbacks
        
$result mysql_query("
            SELECT comment_ID
            FROM $wpdb->comments
            WHERE comment_post_ID = '$post_id'
            AND comment_type = 'trackback'
            AND comment_approved = '1'
        "
) or die(mysql_error());
        
        
$count mysql_num_rows($result);

        if (
$result && $count 0) {

// increase post popularity
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET trackbacks = trackbacks + $count
                , total = total + "
.($this->trackback_value $count)."
                WHERE post_id = '$post_id'
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }

// grab existing pingbacks
        
$result mysql_query("
            SELECT comment_ID
            FROM $wpdb->comments
            WHERE comment_post_ID = '$post_id'
            AND comment_type = 'pingback'
            AND comment_approved = '1'
        "
) or die(mysql_error());
        
        
$count mysql_num_rows($result);

        if (
$result && $count 0) {

// increase post popularity
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET pingbacks = pingbacks + $count
                , total = total + "
.($this->pingback_value $count)."
                WHERE post_id = '$post_id'
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }
    }
    
    function 
record_view() {
        if (
$this->logged 0) {
            return 
true;
        }
        global 
$wpdb$posts;
        
        if (!isset(
$posts) || !is_array($posts) || count($posts) == || is_admin()) {
            return;
        }
        
        
$ids = array();
        
$ak_posts $posts;
        foreach (
$ak_posts as $post) {
            
$ids[] = $post->ID;
        }
        
        if (
is_feed()) {
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET feed_views = feed_views + 1
                , total = total + $this->feed_value
                WHERE post_id IN ("
.implode(','$ids).")
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }
        else if (
is_home()) {
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET home_views = home_views + 1
                , total = total + $this->home_value
                WHERE post_id IN ("
.implode(','$ids).")
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }
        else if (
is_archive() && !is_category()) {
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET archive_views = archive_views + 1
                , total = total + $this->archive_value
                WHERE post_id IN ("
.implode(','$ids).")
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }
        else if (
is_category()) {
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET category_views = category_views + 1
                , total = total + $this->category_value
                WHERE post_id IN ("
.implode(','$ids).")
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }
        else if (
is_single() || is_page()) {
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET single_views = single_views + 1
                , total = total + $this->single_value
                WHERE post_id = '"
.$ids[0]."'
            "
) or die(mysql_error());

            if (!
$result) {
                return 
false;
            }
        }
        
        
$this->logged++;

        return 
true;
    }
    
    function 
record_feedback($type$action '+') {
        global 
$wpdb$comment_post_ID;
        switch (
$type) {
            case 
'trackback':
                
$result mysql_query("
                    UPDATE $wpdb->ak_popularity
                    SET trackbacks = trackbacks $action 1
                    , total = total $action $this->trackback_value
                    WHERE post_id = '$comment_post_ID'
                "
) or die(mysql_error());
    
                if (!
$result) {
                    return 
false;
                }
                break;
            case 
'pingback':
                
$result mysql_query("
                    UPDATE $wpdb->ak_popularity
                    SET pingback_views = pingback_views $action 1
                    , total = total $action $this->pingback_value
                    WHERE post_id = '$comment_post_ID'
                "
) or die(mysql_error());
    
                if (!
$result) {
                    return 
false;
                }
                break;
            default:
                
$result mysql_query("
                    UPDATE $wpdb->ak_popularity
                    SET comments = comments $action 1
                    , total = total $action $this->comment_value
                    WHERE post_id = '$comment_post_ID'
                "
) or die(mysql_error());
    
                if (!
$result) {
                    return 
false;
                }
                break;
        }

        return 
true;
    }
    
    function 
edit_feedback($comment_id$action) {
        global 
$wpdb$comment_post_ID;
        switch (
$action) {
            case 
'delete':
                if (!isset(
$comment_post_ID) || empty($comment_post_ID)) {
                    
// Often, this data isn't set for us - without it there is no joy
                    
return;
                }
                else {
                    
// Unfortunately, this hook happens after the comment
                    // is already out of the DB, so we don't know what type it was.
                    // Assuming it was a comment (not a trackback or pingback) is
                    // the safest solution.
                    
$this->record_feedback('''-');
                }
                break;
            case 
'status':
                
$result mysql_query("
                    SELECT comment_post_ID, comment_type, comment_approved
                    FROM $wpdb->comments
                    WHERE comment_ID = '$comment_id'
                "
) or die(mysql_error());
                
                if (
$result) {
                    while (
$data mysql_fetch_object($result)) {
                        if (
$data->comment_approved == 'spam') {
                            
$comment_post_ID $data->comment_post_ID;
                            
$this->record_feedback($data->comment_type'-');
                            return;
                        }
                    }
                }
        }
    }
    
    function 
recount_feedback() {
        global 
$wpdb;
        
$posts mysql_query("
            SELECT ID
            FROM $wpdb->posts
            WHERE post_status IN ('publish','static')
        "
) or die(mysql_error());

        if (
$posts && mysql_num_rows($posts) > 0) {
            
$result mysql_query("
                UPDATE $wpdb->ak_popularity
                SET comments = 0
                , trackbacks = 0
                , pingbacks = 0
            "
) or die(mysql_error());

            while (
$post mysql_fetch_object($posts)) {
                
$this->populate_post_data($post->ID);
            }
        }

        
$this->recalculate_popularity();

        
header('Location: '.get_bloginfo('wpurl').'/wp-admin/options-general.php?page=popularity-contest.php&updated=true');
        die();
    }
    
    function 
options_form() {
        
$temp = new ak_popularity_contest;
        print(
'
            <style type="text/css">
            </style>
            <div class="wrap">
                <h2>'
.__('Popularity Contest Options''alexking.org').'</h2>
                <form name="ak_popularity" action="'
.get_bloginfo('wpurl').'/wp-content/plugins/popularity-contest.php" method="post">
                    <fieldset class="options">
                        <legend>'
.__('Popularity Values''alexking.org').'</legend>
                        <p>'
.__('Adjust the values below as you see fit. When you save the new options the <a href="index.php?page=popularity-contest.php"><strong>popularity rankings</strong></a> for your posts will be automatically updated to reflect the new values you have chosen.''alexking.org').'</p>
                        <table width="100%" cellspacing="2" cellpadding="5" class="editform"> 
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="single_value">'
.__('Permalink Views:''alexking.org').'</label></th> 
                                <td><input type="text" name="single_value" id="single_value" value="'
.$this->single_value.'" /> '.__("(default: $temp->single_value)"'alexking.org').'</td> 
                            </tr>
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="home_value">'
.__('Home Views:''alexking.org').'</label></th> 
                                <td><input type="text" name="home_value" id="home_value" value="'
.$this->home_value.'" /> '.__("(default: $temp->home_value)"'alexking.org').'</td> 
                            </tr>
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="archive_value">'
.__('Archive Views:''alexking.org').'</label></th> 
                                <td><input type="text" name="archive_value" id="archive_value" value="'
.$this->archive_value.'" /> '.__("(default: $temp->archive_value)"'alexking.org').'</td> 
                            </tr>
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="category_value">'
.__('Category Views:''alexking.org').'</label></th> 
                                <td><input type="text" name="category_value" id="category_value" value="'
.$this->category_value.'" /> '.__("(default: $temp->category_value)"'alexking.org').'</td> 
                            </tr>
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="feed_value">'
.__('Feed Views (full content only):''alexking.org').'</label></th> 
                                <td><input type="text" name="feed_value" id="feed_value" value="'
.$this->feed_value.'" /> '.__("(default: $temp->feed_value)"'alexking.org').'</td> 
                            </tr>
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="comment_value">'
.__('Comments:''alexking.org').'</label></th> 
                                <td><input type="text" name="comment_value" id="comment_value" value="'
.$this->comment_value.'" /> '.__("(default: $temp->comment_value)"'alexking.org').'</td> 
                            </tr>
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="pingback_value">'
.__('Pingbacks:''alexking.org').'</label></th> 
                                <td><input type="text" name="pingback_value" id="pingback_value" value="'
.$this->pingback_value.'" /> '.__("(default: $temp->pingback_value)"'alexking.org').'</td> 
                            </tr>
                            <tr valign="top"> 
                                <th width="33%" scope="row"><label for="trackback_value">'
.__('Trackbacks:''alexking.org').'</label></th> 
                                <td><input type="text" name="trackback_value" id="trackback_value" value="'
.$this->trackback_value.'" /> '.__("(default: $temp->trackback_value)"'alexking.org').'</td> 
                            </tr>
                        </table>
                        <h3>'
.__('Example''alexking.org').'</h3>
                        <ul>
                            <li>'
.__('Post #1 receives 11 Home Page Views (11 * 2 = 22), 6 Permalink Views (6 * 10 = 60) and 3 Comments (3 * 20 = 60) for a total value of: <strong>142</strong>''alexking.org').'</li>
                            <li>'
.__('Post #2 receives 7 Home Page Views (7 * 2 = 14), 10 Permalink Views (10 * 10 = 100), 7 Comments (7 * 20 = 140) and 3 Trackbacks (3 * 80 = 240) for a total value of: <strong>494</strong>''alexking.org').'</li>
                        </ul>
                        <input type="hidden" name="ak_action" value="update_popularity_values" />
                    </fieldset>
                    <p class="submit">
                        <input type="submit" name="submit" value="'
.__('Update Popularity Values''alexking.org').'" />
                        <input type="button" name="recount" value="'
.__('Reset Comments/Trackback/Pingback Counts''alexking.org').'" onclick="location.href=\''.get_bloginfo('wpurl').'/wp-content/plugins/popularity-contest.php?ak_action=recount_feedback\';" />
                    </p>
                </form>
                <div id="akpc_template_tags">
                    <h2>'
.__('Popularity Contest Template Tags''alexking.org').'</h2>
                    <dl>
                        <dt><code>akpc_the_popularity()</code></dt>
                        <dd>
                            <p>'
.__('Put this tag within <a href="http://codex.wordpress.org/The_Loop">The Loop</a> to show the popularity of the post being shown. The popularity is shown as a percentage of your most popular post. For example, if the popularity total for Post #1 is 500 and your popular post has a total of 1000, this tag will show a value of <strong>50%</strong>.''alexking.org').'</p>
                            <p>Example:</p> 
                            <ul>
                                <li><code>&lt;?php akpc_the_popularity(); ?></code></li>
                            </ul>
                        </dd>
                        <dt><code>akpc_most_popular($limit = 10, $before = &lt;li>, $after = &lt;/li>)</code></dt>
                        <dd>
                            <p>'
.__('Put this tag outside of <a href="http://codex.wordpress.org/The_Loop">The Loop</a> (perhaps in your sidebar?) to show a list (like the archives/categories/links list) of your most popular posts. All arguments are optional, the defaults are included in the example above.''alexking.org').'</p>
                            <p>Examples:</p> 
                            <ul>
                                <li><code>&lt;?php akpc_most_popular(); ?></code></li>
                                <li><code>
                                    &lt;li>&lt;h2>Most Popular Posts&lt;/h2><br />
                                    &nbsp;&nbsp;    &lt;ul><br />
                                    &nbsp;&nbsp;    &lt;?php akpc_most_popular(); ?><br />
                                    &nbsp;&nbsp;    &lt;/ul><br />
                                    &lt;/li>
                                </code></li>
                            </ul>
                        </dd>
                        <dt><code>akpc_most_popular_in_cat($limit = 10, $before = &lt;li>, $after = &lt;/li>, $cat_ID = current category)</code></dt>
                        <dd>
                            <p>'
.__('Put this tag outside of <a href="http://codex.wordpress.org/The_Loop">The Loop</a> (perhaps in your sidebar?) to show a list of the most popular posts in a specific category. You may want to use this on category archive pages. All arguments are''alexking.org').'</p>
                            <p>Examples:</p> 
                            <ul>
                                <li><code>&lt;?php akpc_most_popular_in_cat(1); ?></code></li>
                                <li><code>&lt;php if (is_category()) { akpc_most_popular_in_cat(); } ?></code></li>
                                <li><code>
                                    &lt;?php if (is_category()) { ?><br />
                                    &lt;li>&lt;h2>Most Popular in \'&lt;?php single_cat_title(); ?>\'&lt;/h2><br />
                                    &nbsp;&nbsp;    &lt;ul><br />
                                    &nbsp;&nbsp;    &lt;?php akpc_most_popular_in_cat(); ?><br />
                                    &nbsp;&nbsp;    &lt;/ul><br />
                                    &lt;/li><br />
                                    &lt;?php } ?>
                                </code></li>
                            </ul>
                        </dd>
                        <dt><code>akpc_most_popular_in_month($limit, $before, $after, $m = YYYYMM)</code></dt>
                        <dd>