[alt type="info"]由于需要Join,不推荐数据量大的博客使用自定义字段存储浏览次数[/alt]
前提
好几年前我在打造SimpX主题的时候撸了下面的浏览次数统计代码。
/*
* 获取浏览次数(改进版)
*/
function getViewsStr($widget, $format = "{views} 次浏览") {
$fields = unserialize($widget->fields);
if (array_key_exists('views', $fields))
$views = (!empty($fields['views'])) ? intval($fields['views']) : 0;
else
$views = 0;
//增加浏览次数
if ($widget->is('single')) {
$vieweds = Typecho_Cookie::get('contents_viewed');
if (empty($vieweds))
$vieweds = array();
else
$vieweds = explode(',', $vieweds);
if (!in_array($widget->cid, $vieweds)) {
$views = $views + 1;
$widget->setField('views', 'str', strval($views), $widget->cid);
$vieweds[] = $widget->cid;
$vieweds = implode(',', $vieweds);
Typecho_Cookie::set("contents_viewed",$vieweds);
}
}
return str_replace("{views}", $views, $format);
}
需求
这次在整poRebuild主题的时候发现原来的调用方式不太合适我这次的输出需求,改造成在themeInit函数里自动增加浏览次数,无论页面是否展示都能自动统计。当然了,还是利用自定义字段,不动数据库结构。
同时我新弄的主题还需要热门文章输出的功能,一并把代码撸了。
代码
浏览次数查询
先给出查询浏览次数的代码,为了方便拓展(比如输出点赞次数),自定义字段都是可变参数,同时支持控制直接输出或者返回。
function views($widget, $format0 = "%d", $format1 = "%d", $formats = "%d", $return = false, $field = 'views')
{
$fields = unserialize($widget->fields);
if (array_key_exists($field, $fields)) {
$fieldValue = (!empty($fields[$field])) ? intval($fields[$field]) : 0;
} else {
$fieldValue = 0;
}
if ($fieldValue == 0) {
$fieldValue = sprintf($format0, $fieldValue);
} else if ($fieldValue == 1) {
$fieldValue = sprintf($format1, $fieldValue);
} else {
$fieldValue = sprintf($formats, $fieldValue);
}
if ($return) {
return $fieldValue;
} else {
echo $fieldValue;
}
}
在展示的地方调用
<?php views($this); ?>
浏览次数统计
/**
* 增加浏览次数
* 使用方法: 在<code>themeInit</code>函数中添加代码
* <pre>if($archive->is('single') || $archive->is('page')){ viewsCounter($archive);}</pre>
*
* @param Widget_Archive $widget
* @return boolean
*/
function viewsCounter($widget, $field = 'views')
{
if (!$widget instanceof Widget_Archive) {
return false;
}
$fieldValue = views($widget, "%d", "%d", "%d", true, $field);
$fieldRecords = Typecho_Cookie::get('__typecho_' . $field);
if (empty($fieldRecords)) {
$fieldRecords = array();
} else {
$fieldRecords = explode(',', $fieldRecords);
}
if (!in_array($widget->cid, $fieldRecords)) {
$fieldValue = $fieldValue + 1;
$widget->setField($field, 'str', strval($fieldValue), $widget->cid);
$fieldRecords[] = $widget->cid;
$fieldRecords = implode(',', $fieldRecords);
Typecho_Cookie::set('__typecho_' . $field, $fieldRecords);
return true;
}
return false;
}
调用方式,需要在主题themeInit函数中调用
funciton themeInit() {
if($archive->is('single') || $archive->is('page')){ viewsCounter($archive);}
}
输出热门文章
/**
* 获取热门文章
*
* @access public
* @param int $pageSize 限制热门文章输出数量
* @param int $fieldName 排序关键自定义字段
* @since 1.0
* @return Widget_Archive
*/
function hotspots($pageSize = -1, $fieldName = "views") {
//2020.04.22默认遵循默认 pageSize
$pageSize = $pageSize === -1 ? Helper::options()->postsListSize : $pageSize;
$db = Typecho_Db::get();
// 2020.04.19 修复排列顺序不正常 1 10 100 2 20 3 4 5
$tableFields = $db->getPrefix() . 'fields';
$tableContents = $db->getPrefix() . 'contents';
// 2020.04.27 修复 Pdo_MySQL 不能用
$castType = ($db->getAdapterName() === "MySQL" || $db->getAdapterName() === "Pdo_Mysql") ? "UNSIGNED" : "INT";
$sql = "SELECT *,CAST(${tableFields}.str_value as ${castType}) order1 FROM ${tableFields},${tableContents} WHERE ${tableFields}.cid = ${tableContents}.cid AND ${tableFields}.name = '${fieldName}' AND ${tableContents}.type = 'post' AND ${tableContents}.status = 'publish' AND ${tableContents}.created < " . time() . " ORDER BY order1 DESC LIMIT $pageSize";
$result = $db->fetchAll($sql);
// 2020.08.11 修复没有浏览记录时空白
if (count($result) < $pageSize) {
$select = $db->select()->from('table.contents')->where('table.contents.status = ? AND table.contents.created < ? AND table.contents.type = ?', 'publish', time(), 'post');
foreach ($result as $row) {
$select = $select->where('table.contents.cid <> ?', $row['cid']);
}
$select->order('table.contents.created', Typecho_Db::SORT_DESC)->limit($pageSize - count($result));
$_result = $db->fetchAll($select);
foreach ($_result as $row) {
$result[] = $row;
}
}
// 2020.04.27 修复作者页报错
$archive = Typecho_Widget::widget('Widget_Archive@hotposts-' . $pageSize, 'type=index');
// 2020.07.04 临时修复没有views字段引起的死循环
if (count($result)) {
$archive->row = [];
$archive->stack = [];
$archive->length = 0;
foreach ($result as $hotpost) {
$archive->push($hotpost);
}
$archive->setTotal(count($result));
}
return $archive;
}
直接调用和主题调用文章列表是一样的
<?php $widget = hotspots(); ?>
<?php while($widget->next()): ?>
<?php $widget->title(); ?>
<?php endwhile;?>
最后
当然,别忘了你的主题或者插件新增了 views 字段,删掉
ALTER TABLE `typecho_contents` DROP `views`;
表情太少了
表情太少了
再来看看啊啊啊
做个笔记,统计函数里面的Stat::这个关键字需要删除,有两处,一处在函数本身内,一处在调用的那段代码里,然后获取热门文章,hotspots();这个函数支持两个参数,第一个是需要输出的文章数量,第二个不清楚,然后在while循环里面,博主漏写了变量符号,使用会报错,所有数据都要基于$widget这个变量,比如标题:$widget->title(); 链接:$widget->permalink()
第二个参数是操作字段名,比如我想用 llcs 这个字段来存储浏览次数,调用形式就类似
viewsCounter($archive, 'llcs')
,views($this, 'llcs')
<<<<<<来看看>>>>>>
看不了啊,我敲
不知道你对回复可见做了什么
怎么控制标题字数
0是起始位置,10是长度
就是这个主题的热门文章调用里的标题怎么控制?
$post_title = htmlspecialchars($result['title']);
是这里吗?
看看啊啊啊
啊
隐藏内容:
啊啊啊啊啊
表情太少了