Typecho文章排行插件实现(按日排行、周排行、月排行、总排行)

时间:2016-05-07
今天起兴,看了下Typecho插件机制,自己也小试了一个,还是很好实现的,ArticleRanks插件主要是为了实现文章按日排行,周排行、月排行,主要也是为了自己用。你可以看到我的博客右侧(PS:我不会UI,丑就别见怪了)

Typecho文章排行插件实现(按日排行、周排行、月排行、总排行)

原理很简单: 要实现文章按日期排行,你就必须记录文章每天的点击率,于是新建数据表是必须的:

CREATE TABLE IF NOT EXISTS `typecho_ranks` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `cid` int(10) NOT NULL,
  `hits` int(10) NOT NULL,
  `date` date NOT NULL,
  PRIMARY KEY (`id`),
  KEY `cid` (`cid`)
) ENGINE=MYISAM  DEFAULT CHARSET=%charset%;

然后就是Plugin文件了,这只是我今天写的原始版,可能还并不是很规范,测试后我会发布该插件:

<?php
/**
 * 实现文章日排行、周排行、月排行、年排行、总排行
 * @package RankPlugin
 * @author Mckee
 * @version 1.0
 * @link http://www.phpddt.com
 */
class ArticleRank_Plugin implements Typecho_Plugin_Interface
{
    /**
     * 激活插件方法,如果激活失败,直接抛出异常
     * 
     * @access public
     * @return void
     * @throws Typecho_Plugin_Exception
     */
    public static function activate()
    {
        $info = ArticleRank_Plugin::installTable();
        Typecho_Plugin::factory('Widget_Archive')->beforeRender = array('ArticleRank_Plugin', 'updateDayCount');
        return _t($info);
    }
 
    /**
     * 禁用插件方法,如果禁用失败,直接抛出异常
     * 
     * @static
     * @access public
     * @return void
     * @throws Typecho_Plugin_Exception
     */
    public static function deactivate()
    {
        /**删除数据表*/
        $info = ArticleRank_Plugin::uninstallTable();
        return _t($info);
    }
    
    /**
     * 获取插件配置面板
     * 
     * @access public
     * @param Typecho_Widget_Helper_Form $form 配置面板
     * @return void
     */
    public static function config(Typecho_Widget_Helper_Form $form){}
 
    /**
     * 个人用户的配置面板
     * 
     * @access public
     * @param Typecho_Widget_Helper_Form $form
     * @return void
     */
    public static function personalConfig(Typecho_Widget_Helper_Form $form){}
    
    /**
     * 插入ranks数据表
     * 
     * @access public 
     * @return void
     */
    public function installTable()
    {
        $installDb = Typecho_Db::get();
		$type = explode('_', $installDb->getAdapterName());
		$type = array_pop($type);
		$prefix = $installDb->getPrefix();
		$scripts = file_get_contents('usr/plugins/ArticleRank/'.$type.'.sql');
		$scripts = str_replace('typecho_', $prefix, $scripts);
		$scripts = str_replace('%charset%', 'utf8', $scripts);
		$scripts = explode(';', $scripts);
		try {
			foreach ($scripts as $script) {
				$script = trim($script);
				if ($script) {
					$installDb->query($script, Typecho_Db::WRITE);
				}
			}
			return '建立ranks数据表,记录文章每天点击量,插件启用成功';
		} catch (Typecho_Db_Exception $e) {
			throw new Typecho_Plugin_Exception('数据表建立失败,请检查原因。错误号:'.$code);	
		}
    }
    
    /**
     * 删除数据表
     * 
     * @access public
     * @return void
     */
    public function uninstallTable()
    {
        $db = Typecho_Db::get();
        $prefix = $db->getPrefix();
        try
        {
            $db->query($db->query('drop table '.$prefix.'ranks'));
            return '删除ranks数据表,插件已禁止';
        } catch (Typecho_Db_Exception $e){
            throw new Typecho_Plugin_Exception('ranks表删除失败');
        }
    
    }
    
    /**
     * 加入 beforeRender,更新文章的该天访问量
     * 
     * @access public
     * @return void
     */
    public static function updateDayCount()
    {
        // 访问计数
        if (Typecho_Widget::widget('Widget_Archive')->is('single')) {
            $db = Typecho_Db::get();
            $cid = Typecho_Widget::widget('Widget_Archive')->cid;
            $date = date("Y-m-d",time());
            $row = $db->fetchRow($db->select('hits')->from('table.ranks')->where('cid = ? AND date = ?', $cid, $date));
            if($row)
            {
                //更新hits即可
                $db->query($db->update('table.ranks')->rows(array('hits' => (int)$row['hits']+1))->where('cid = ?', $cid));
            }
            else
            {
                //如果第一次浏览则要插入
                $db->query($db->insert('table.ranks')->rows(array('cid'=>$cid,'hits'=>1,'date'=>$date)));
            }
        }
    }
 
    /**
     * 获取指定篇数的日排行、周排行、月排行、年排行、总排行文章
     * 
     * 语法:ArticleRank_Plugin::theRankPosts(10,'week');
     * 
     * @access public 
     * @param int $num 默认取10篇文章
     * @param string $type 日排行:day,周排行:week,月排行:month,年排行:year, 总排行: 其它
     */
    public static function theRankPosts($num = 10, $type = '')
    {
        $db = Typecho_Db::get();
        $options = Typecho_Widget::widget('Widget_Options');
        $num = is_numeric($num) ? $num : 10;
        $handle = $db->select('*,sum(hits) as sum')->from('table.ranks')->join('table.contents', 'table.contents.cid = table.ranks.cid');
        if($type == 'day')
        {
            $handle->where('date = curdate()');
        }
        if($type == 'week')
        {
            $handle->where('week(date) = week(now())');
        }
        elseif ($type == 'month') 
        {
            $handle->where('MONTH(date) = MONTH(now())');
        }
        elseif ($type == 'year') 
        {
            $handle->where('YEAR(date) = YEAR(now())');
        }
        $posts = $db->fetchAll(
                $handle->group('table.ranks.cid')
                ->order('sum(hits)', Typecho_Db::SORT_DESC)
                ->limit($num)
                );
        if ($posts) {
            foreach ($posts as $post) {
                $result = Typecho_Widget::widget('Widget_Abstract_Contents')->push($post);
                $post_title = htmlspecialchars($result['title']);
                $permalink = $result['permalink'];
                echo "<li><a href='$permalink' title='$post_title'>$post_title</a></li>\n";
            }
 
        } else {
            echo "<li>N/A</li>\n";
        }
    }
 
}

使用起来就很简单了,如下(输出文章排行前10篇文章):

<?php ArticleRank_Plugin::theRankPosts(10,'week');?>


需要注意的是:

这里的点击是基于新的数据表的,如果你的点击还不到10篇,就不会显示完全,另外,刚使用插件因点击过少会出现日排行,周排行,月排行的数据一样,这病没有错误。

好了,提供原始版本下载(ArticleRank.zip) ,后台直接开启插件即可使用!