Typecho主题制作总结
由于 Typecho 相比 WordPress,所提供的接口较少,所以有些地方需要注意下。
首页文章无限加载文章
首先在 functions.php 中加入一段判断 ajax 请求的方法:
function is_ajax()
{
if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
if ('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) {
return true;
}
}
return false;
}
然后在首页模板 index.php 中加入判断,if(is_ajax()): 则不输出 header footer 等信息。
最后一步,再模板公共 js 文件中加入以下代码:
var page = 1;
var $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body');
$('#blog_load_more').click(function(event) {
$(this).hide();
$('#spinner').show();
$.ajax({
type: 'get',
url: SITE.default_url + '/page/' + parseInt(page + 1),
success: function(data, textStatus, XMLHttpRequest) {
page++;
$('.w-blog-list').append(data);
$('#spinner').hide();
$('#blog_load_more').show();
},
error: function(MLHttpRequest, textStatus, errorThrown) {
$('#spinner').hide();
$.jGrowl('Network Error');
}
});
});
其中 #blog_load_more 为需要绑定的加载更多按钮,#spinner 为加载过程中的动画,.w-blog-list 为首页文章列表容器。
由于 Typecho 并没有 Ajax 钩子函数,所以需要在 functions.php 中加入以下代码:
function site_data()
{
$array = array(
'site_url' => Helper::options()->siteUrl,
'default_url' => Helper::options()->siteUrl . 'index.php',
'theme_images_url' => Helper::options()->themeUrl . '/assets/images/',
);
echo json_encode($array);
}
之后在 footer.php 中引入该数据:
<script type="text/javascript">
var SITE = <?php site_data()?>;
</script>
此处的 SITE 就是一个 JSON 对象,可以直接用了。
WordPress 的 add_filter 很好用,Typecho 也可以实现类似的功能:
比如想把文章中的图片都加上 rel="fancybox" 的属性,WordPress 可能使用的以下方法:
add_filter('the_content', 'fancybox_replace');
function fancybox_replace($content)
{
global $post;
$pattern = "/<a(.*?)href=('|\")([^>]*).(bmp|gif|jpeg|jpg|png)('|\")(.*?)>(.*?)<\/a>/i";
$replacement = '<a$1href=$2$3.$4$5 target="_blank" rel="fancybox"$6>$7</a>';
$content = preg_replace($pattern, $replacement, $content);
return $content;
}
Typecho 中可以这么写:
function themeInit($archive)
{
if ($archive->is('single')) {
$archive->content = fancybox_replace($archive->content);
}
}
获取文章第一张图片
分为 markdown 和 html 两种方式
function get_post_img($archive)
{
$cid = $archive->cid;
$db = Typecho_Db::get();
$rs = $db->fetchRow($db->select('table.contents.text')
->from('table.contents')
->where('cid=?', $cid));
$text = $rs['text'];
if (0 === strpos($text, '<!--markdown-->')) {
preg_match('/!\[[^\]]*]\([^\)]*\.(png|jpeg|jpg|gif|bmp)\)/i', $text, $img);
if (empty($img)) {
return 'none';
} else {
preg_match("/(?:\()(.*)(?:\))/i", $img[0], $result);
$img_url = $result[1];
return '<img src="' . $img_url . '"/>';
}
} else {
preg_match_all("/\<img.*?src\=\"(.*?)\"[^>]*>/i", $text, $img);
if (empty($img)) {
return 'none';
} else {
$img_url = $img[1][0];
return '<img src="' . $img_url . '"/>';
}
}
}
评论列表加 @
function get_comment_at($coid)
{
$db = Typecho_Db::get();
$prow = $db->fetchRow($db->select('parent')->from('table.comments')
->where('coid = ? AND status = ?', $coid, 'approved'));
$parent = $prow['parent'];
if ($parent != "0") {
$arow = $db->fetchRow($db->select('author')->from('table.comments')
->where('coid = ? AND status = ?', $parent, 'approved'));
$author = $arow['author'];
$href = '<a href="#comment-' . $parent . '">@' . $author . '</a>';
echo $href;
} else {
echo '';
}
}
非插件实现文章阅读次数统计
在文章页面引入 get_post_view() 方法。
//get_post_view($this)
function get_post_view($archive)
{
$cid = $archive->cid;
$db = Typecho_Db::get();
$prefix = $db->getPrefix();
if (!array_key_exists('views', $db->fetchRow($db->select()->from('table.contents')))) {
$db->query('ALTER TABLE `' . $prefix . 'contents` ADD `views` INT(10) DEFAULT 0;');
echo 0;
return;
}
$row = $db->fetchRow($db->select('views')->from('table.contents')->where('cid = ?', $cid));
if ($archive->is('single')) {
$db->query($db->update('table.contents')->rows(array('views' => (int) $row['views'] + 1))->where('cid = ?', $cid));
}
echo $row['views'];
}
判断移动端访问
function is_mobile()
{
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$mobile_browser = array(
"mqqbrowser", //手机QQ浏览器
"opera mobi", //手机opera
"juc", "iuc", //uc浏览器
"fennec", "ios", "applewebKit/420", "applewebkit/525", "applewebkit/532", "ipad", "iphone", "ipaq", "ipod",
"iemobile", "windows ce", //windows phone
"240x320", "480x640", "acer", "android", "anywhereyougo.com", "asus", "audio", "blackberry",
"blazer", "coolpad", "dopod", "etouch", "hitachi", "htc", "huawei", "jbrowser", "lenovo",
"lg", "lg-", "lge-", "lge", "mobi", "moto", "nokia", "phone", "samsung", "sony",
"symbian", "tablet", "tianyu", "wap", "xda", "xde", "zte",
);
$is_mobile = false;
foreach ($mobile_browser as $device) {
if (stristr($user_agent, $device)) {
$is_mobile = true;
break;
}
}
return $is_mobile;
}
ajax 评论
AjaxComments 有小 bug,不太好用,直接食用以下的修改版代码,在公共 js 中调用 ajaxComments() 方法即可
function ajaxComment() {
var selector = {
commentMainFrame: '#comment',
commentList: '#commentlist',
commentNumText: '#comment h3',
commentReplyButton: '#comment span.reply',
submitForm: '#commentform',
submitTextarea: '#textarea',
submitButton: '#submit',
};
var parentId = '';
bindCommentReplyButton();
$(selector.submitTextarea).after('<div style="display:none;" id="ajaxCommentMsg"><\/div>');
$msg = $('#ajaxCommentMsg');
$(document).on('submit', selector.submitForm, function() {
$msg.empty();
$(selector.submitButton).val('发射中哦=A=');
$(selector.submitButton).attr('disabled', true).fadeTo('slow', 0.5);
if ($(selector.submitForm).find('#author')[0]) {
if ($(selector.submitForm).find('#author').val() == '') {
message('昵称没填呢QAQ');
enableCommentButton();
return false;
}
if ($(selector.submitForm).find('#mail').val() == '') {
message('邮箱没填呢QAQ');
enableCommentButton();
return false;
}
var filter = /^[^@\s<&>]+@([a-z0-9]+\.)+[a-z]{2,4}$/i;
if (!filter.test($(selector.submitForm).find('#mail').val())) {
message('邮箱地址不正确呢QAQ');
enableCommentButton();
return false;
}
}
if ($(selector.submitForm).find(selector.submitTextarea).val() == '') {
message('评论似乎什么也没写呢QAQ');
enableCommentButton();
return false;
}
$.ajax({
url: $(this).attr('action'),
type: $(this).attr('method'),
data: $(this).serializeArray(),
error: function() {
message('发射失败,请重试!');
setTimeout(NProgress.done, 500)
enableCommentButton();
return false;
},
success: function(data) {
if (!$(selector.commentList, data).length) {
errorMsg = data.match(/.+/g).join().match(/\<div.+\>.+\<\/div\>/g).join().match(/[^\,]+/g);
$msg.html(errorMsg[0] + errorMsg[1] + errorMsg[2]);
enableCommentButton();
return false;
} else {
userCommentId = $(selector.commentList, data).html().match(/id=\"?comment-\d+/g).join().match(/\d+/g).sort(function(a, b) {
return a - b;
}).pop();
commentLi = '<li id="comment-' + userCommentId + '" class="comment">' + $('#comment-' + userCommentId, data).html(); + '<\/li>';
if (parentId) {
if ($('#' + parentId).find(".comment-children").length <= 0) {
$('#' + parentId).append("<ul class='children'></ul>");
}
$('#' + parentId + " .children:first").append(commentLi);
parentId = ''
$body.animate({
scrollTop: $('#comment-' + userCommentId).offset().top - 450
}, 900);
} else {
$(selector.commentList).prepend(commentLi)
$body.animate({
scrollTop: $('#comment-' + userCommentId).offset().top - 200
}, 900);
}
//$('#comment-' + userCommentId).slideDown('slow');
//console.log(userCommentId);
$(selector.commentNumText).length ? (n = parseInt($(selector.commentNumText).text().match(/\d+/)), $(selector.commentNumText).html($(selector.commentNumText).html().replace(n, n + 1))) : 0;
TypechoComment.cancelReply();
$(selector.submitTextarea).val('');
$(selector.commentReplyButton + ' b, #cancel-comment-reply-link').unbind('click');
bindCommentReplyButton();
enableCommentButton();
}
}
});
return false;
});
function bindCommentReplyButton() {
$(document).on('click', selector.commentReplyButton, function() {
parentId = $(this).parents('li.comment').attr("id");
$(selector.submitTextarea).focus();
});
$(document).on('click', '#cancel-comment-reply-link', function() {
parentId = '';
});
}
function enableCommentButton() {
$(selector.submitButton).attr('disabled', false).fadeTo('', 1);
$(selector.submitButton).val('发射=A=');
}
function message(msg) {
$msg.hide();
$msg.html(msg).slideToggle('fast');
}
}
无限嵌套评论
function themeInit($archive)
{
Helper::options()->commentsMaxNestingLevels = 999;
}
非插件实现路由
function themeInit($archive)
{
if ($archive->is('archive', 404))
{
$path_info = trim($archive->request->getPathinfo(), '/');
if ($path_info == 'i/redirect')
{
$url = urldecode($archive->request->url);
$archive->response->redirect($url);
exit;
}
}
}
作者:https://kotori.love/archives/typecho-theme-tips.html
@jrotty:add_filter 那个 typecho 的代码没搞懂,我想给文章里的图片加上个 class
@そら 其实你直接用 jQuery 加会更好
function themeInit($archive)
{
if ($archive->is('single'))
{
$archive->content = image_class_replace($archive->content);
}
}
function image_class_replace($content)
{
$content = preg_replace('#<img(.*?)src="([^"]*/)?(([^"/]*)\.[^"]*)"([^>]*?)>#',
'<img$1src="$2$3" class="your-class">', $content);
return $content;
}
作者:https://kotori.love/archives/typecho-theme-tips.html
@围观群众:空樱酱 能跟我说说文章阅读统计到底是怎么弄的么?
@ そら:把 get_post_view 放到 functions.php 里,需要统计的页面 (post.php/page.php) 对应的位置(共有 x 次访问的地方)写上<?php get_post_view($this);?>
:D 少女祈祷中...