查看: 6|回复: 0

[技术教程] Typecho主题制作总结

[复制链接]
  • 打卡等级:常驻代表
  • 打卡总天数:40
  • 打卡月天数:4
  • 打卡总奖励:341
  • 最近打卡:2025-07-11 08:55:56
发表于 前天 17:22 | 显示全部楼层 |阅读模式
由于 Typecho 相比 WordPress,所提供的接口较少,所以有些地方需要注意下。

首页文章无限加载文章
首先在 functions.php 中加入一段判断 ajax 请求的方法:
  1. function is_ajax()
  2. {
  3.     if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
  4.         if ('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) {
  5.             return true;
  6.         }
  7.     }
  8.     return false;
  9. }
复制代码
然后在首页模板 index.php 中加入判断,if (is_ajax ()): 则不输出 header footer 等信息。
最后一步,再模板公共 js 文件中加入以下代码:
  1. var page = 1;
  2.     var $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body');
  3.     $('#blog_load_more').click(function(event) {
  4.         $(this).hide();
  5.         $('#spinner').show();
  6.         $.ajax({
  7.             type: 'get',
  8.             url: SITE.default_url + '/page/' + parseInt(page + 1),
  9.             success: function(data, textStatus, XMLHttpRequest) {
  10.                 page++;
  11.                 $('.w-blog-list').append(data);
  12.                 $('#spinner').hide();
  13.                 $('#blog_load_more').show();
  14.             },
  15.             error: function(MLHttpRequest, textStatus, errorThrown) {
  16.                 $('#spinner').hide();
  17.                 $.jGrowl('Network Error');
  18.             }
  19.         });
  20.     });
复制代码
其中 #blog_load_more 为需要绑定的加载更多按钮,#spinner 为加载过程中的动画,.w-blog-list 为首页文章列表容器。
由于 Typecho 并没有 Ajax 钩子函数,所以需要在 functions.php 中加入以下代码:
  1. function site_data()
  2. {
  3.     $array = array(
  4.         'site_url'         => Helper::options()->siteUrl,
  5.         'default_url'      => Helper::options()->siteUrl . 'index.php',
  6.         'theme_images_url' => Helper::options()->themeUrl . '/assets/images/',
  7.     );
  8.     echo json_encode($array);
  9. }
复制代码
之后在 footer.php 中引入该数据:
  1. <script type="text/javascript">
  2. var SITE = <?php site_data()?>;
  3. </script>
复制代码
此处的 SITE 就是一个 JSON 对象,可以直接用了。
Typecho实现add_filter功能
比如想把文章中的图片都加上 rel="fancybox" 的属性,WordPress 可能使用的以下方法:
  1. add_filter('the_content', 'fancybox_replace');
  2. function fancybox_replace($content)
  3. {
  4.     global $post;
  5.     $pattern     = "/<a(.*?)href=('|")([^>]*).(bmp|gif|jpeg|jpg|png)('|")(.*?)>(.*?)<\/a>/i";
  6.     $replacement = '<a$1href=$2$3.$4$5 target="_blank" rel="fancybox"$6>$7</a>';
  7.     $content     = preg_replace($pattern, $replacement, $content);
  8.     return $content;
  9. }
复制代码
Typecho 中可以这么写:
  1. function themeInit($archive)
  2. {
  3.     if ($archive->is('single')) {
  4.         $archive->content = fancybox_replace($archive->content);
  5.     }
  6. }
复制代码
获取文章第一张图片
分为 markdown 和 html 两种方式
  1. function get_post_img($archive)
  2. {
  3.     $cid = $archive->cid;
  4.     $db = Typecho_Db::get();
  5.     $rs = $db->fetchRow($db->select('table.contents.text')
  6.                                ->from('table.contents')
  7.                                ->where('cid=?', $cid));
  8.     $text = $rs['text'];
  9.     if (0 === strpos($text, '')) {
  10.         preg_match('/!\[[^\]]*]\([^\)]*\.(png|jpeg|jpg|gif|bmp)\)/i', $text, $img);
  11.         if (empty($img)) {
  12.             return 'none';
  13.         } else {
  14.             preg_match("/(?:\()(.*)(?:\))/i", $img[0], $result);
  15.             $img_url = $result[1];
  16.             return '<img src="' . $img_url . '"/>';
  17.         }
  18.     } else {
  19.         preg_match_all("/\<img.*?src\="(.*?)"[^>]*>/i", $text, $img);
  20.         if (empty($img)) {
  21.             return 'none';
  22.         } else {
  23.             $img_url = $img[1][0];
  24.             return '<img src="' . $img_url . '"/>';
  25.         }
  26.     }
  27. }
复制代码
评论列表加@
  1. function get_comment_at($coid)
  2. {
  3.     $db   = Typecho_Db::get();
  4.     $prow = $db->fetchRow($db->select('parent')->from('table.comments')
  5.                                  ->where('coid = ? AND status = ?', $coid, 'approved'));
  6.     $parent = $prow['parent'];
  7.     if ($parent != "0") {
  8.         $arow = $db->fetchRow($db->select('author')->from('table.comments')
  9.                                      ->where('coid = ? AND status = ?', $parent, 'approved'));
  10.         $author = $arow['author'];
  11.         $href   = '<a href="#comment-' . $parent . '">@' . $author . '</a>';
  12.         echo $href;
  13.     } else {
  14.         echo '';
  15.     }
  16. }
复制代码
非插件实现文章阅读次数统计
在文章页面引入 get_post_view() 方法。
  1. //get_post_view($this)
  2. function get_post_view($archive)
  3. {
  4.     $cid    = $archive->cid;
  5.     $db     = Typecho_Db::get();
  6.     $prefix = $db->getPrefix();
  7.     if (!array_key_exists('views', $db->fetchRow($db->select()->from('table.contents')))) {
  8.         $db->query('ALTER TABLE `' . $prefix . 'contents` ADD `views` INT(10) DEFAULT 0;');
  9.         echo 0;
  10.         return;
  11.     }
  12.     $row = $db->fetchRow($db->select('views')->from('table.contents')->where('cid = ?', $cid));
  13.     if ($archive->is('single')) {
  14.        $db->query($db->update('table.contents')->rows(array('views' => (int) $row['views'] + 1))->where('cid = ?', $cid));
  15.     }
  16.     echo $row['views'];
  17. }
复制代码
判断移动端访问
  1. function is_mobile()
  2. {
  3.     $user_agent     = $_SERVER['HTTP_USER_AGENT'];
  4.     $mobile_browser = array(
  5.         "mqqbrowser", //手机QQ浏览器
  6.         "opera mobi", //手机opera
  7.         "juc", "iuc", //uc浏览器
  8.         "fennec", "ios", "applewebKit/420", "applewebkit/525", "applewebkit/532", "ipad", "iphone", "ipaq", "ipod",
  9.         "iemobile", "windows ce", //windows phone
  10.         "240x320", "480x640", "acer", "android", "anywhereyougo.com", "asus", "audio", "blackberry",
  11.         "blazer", "coolpad", "dopod", "etouch", "hitachi", "htc", "huawei", "jbrowser", "lenovo",
  12.         "lg", "lg-", "lge-", "lge", "mobi", "moto", "nokia", "phone", "samsung", "sony",
  13.         "symbian", "tablet", "tianyu", "wap", "xda", "xde", "zte",
  14.     );
  15.     $is_mobile = false;
  16.     foreach ($mobile_browser as $device) {
  17.         if (stristr($user_agent, $device)) {
  18.             $is_mobile = true;
  19.             break;
  20.         }
  21.     }
  22.     return $is_mobile;
  23. }
复制代码
ajax评论
AjaxComments有小bug,不太好用,直接食用以下的修改版代码,在公共js中调用 ajaxComments() 方法即可。
  1. function ajaxComment() {
  2.     var selector = {
  3.         commentMainFrame: '#comment',
  4.         commentList: '#commentlist',
  5.         commentNumText: '#comment h3',
  6.         commentReplyButton: '#comment span.reply',
  7.         submitForm: '#commentform',
  8.         submitTextarea: '#textarea',
  9.         submitButton: '#submit',
  10.     };
  11.     var parentId = '';
  12.     bindCommentReplyButton();
  13.     $(selector.submitTextarea).after('<div style="display:none;" id="ajaxCommentMsg"><\/div>');
  14.     $msg = $('#ajaxCommentMsg');
  15.     $(document).on('submit', selector.submitForm, function() {
  16.         $msg.empty();
  17.         $(selector.submitButton).val('发射中哦=A=');
  18.         $(selector.submitButton).attr('disabled', true).fadeTo('slow', 0.5);
  19.         if ($(selector.submitForm).find('#author')[0]) {
  20.             if ($(selector.submitForm).find('#author').val() == '') {
  21.                 message('昵称没填呢QAQ');
  22.                 enableCommentButton();
  23.                 return false;
  24.             }
  25.             if ($(selector.submitForm).find('#mail').val() == '') {
  26.                 message('邮箱没填呢QAQ');
  27.                 enableCommentButton();
  28.                 return false;
  29.             }
  30.             var filter = /^[^@\s<&>]+@([a-z0-9]+\.)+[a-z]{2,4}$/i;
  31.             if (!filter.test($(selector.submitForm).find('#mail').val())) {
  32.                 message('邮箱地址不正确呢QAQ');
  33.                 enableCommentButton();
  34.                 return false;
  35.             }
  36.         }
  37.         if ($(selector.submitForm).find(selector.submitTextarea).val() == '') {
  38.             message('评论似乎什么也没写呢QAQ');
  39.             enableCommentButton();
  40.             return false;
  41.         }
  42.         $.ajax({
  43.             url: $(this).attr('action'),
  44.             type: $(this).attr('method'),
  45.             data: $(this).serializeArray(),
  46.             error: function() {
  47.                 message('发射失败,请重试!');
  48.                 setTimeout(NProgress.done, 500)
  49.                 enableCommentButton();
  50.                 return false;
  51.             },
  52.             success: function(data) {
  53.                 if (!$(selector.commentList, data).length) {
  54.                     errorMsg = data.match(/.+/g).join().match(/\<div.+\>.+\<\/div\>/g).join().match(/[^\,]+/g);
  55.                     $msg.html(errorMsg[0] + errorMsg[1] + errorMsg[2]);
  56.                     enableCommentButton();
  57.                     return false;
  58.                 } else {
  59.                     userCommentId = $(selector.commentList, data).html().match(/id="?comment-\d+/g).join().match(/\d+/g).sort(function(a, b) {
  60.                         return a - b;
  61.                     }).pop();
  62.                     commentLi = '<li id="comment-' + userCommentId + '" class="comment">' + $('#comment-' + userCommentId, data).html(); + '<\/li>';
  63.                     if (parentId) {
  64.                         if ($('#' + parentId).find(".comment-children").length <= 0) {
  65.                             $('#' + parentId).append("<ul class='children'></ul>");
  66.                         }
  67.                         $('#' + parentId + " .children:first").append(commentLi);
  68.                         parentId = ''
  69.                         $body.animate({
  70.                             scrollTop: $('#comment-' + userCommentId).offset().top - 450
  71.                         }, 900);
  72.                     } else {
  73.                         $(selector.commentList).prepend(commentLi)
  74.                         $body.animate({
  75.                             scrollTop: $('#comment-' + userCommentId).offset().top - 200
  76.                         }, 900);
  77.                     }
  78.                     //$('#comment-' + userCommentId).slideDown('slow');

  79.                     //console.log(userCommentId);
  80.                     $(selector.commentNumText).length ? (n = parseInt($(selector.commentNumText).text().match(/\d+/)), $(selector.commentNumText).html($(selector.commentNumText).html().replace(n, n + 1))) : 0;
  81.                     TypechoComment.cancelReply();
  82.                     $(selector.submitTextarea).val('');
  83.                     $(selector.commentReplyButton + ' b, #cancel-comment-reply-link').unbind('click');
  84.                     bindCommentReplyButton();
  85.                     enableCommentButton();

  86.                 }
  87.             }
  88.         });
  89.         return false;
  90.     });

  91.     function bindCommentReplyButton() {
  92.         $(document).on('click', selector.commentReplyButton, function() {
  93.             parentId = $(this).parents('li.comment').attr("id");
  94.             $(selector.submitTextarea).focus();
  95.         });
  96.         $(document).on('click', '#cancel-comment-reply-link', function() {
  97.             parentId = '';
  98.         });
  99.     }

  100.     function enableCommentButton() {
  101.         $(selector.submitButton).attr('disabled', false).fadeTo('', 1);
  102.         $(selector.submitButton).val('发射=A=');
  103.     }

  104.     function message(msg) {
  105.         $msg.hide();
  106.         $msg.html(msg).slideToggle('fast');
  107.     }
  108. }
复制代码
无限嵌套评论
  1. function themeInit($archive)
  2. {
  3.     Helper::options()->commentsMaxNestingLevels = 999;
  4. }
复制代码
非插件实现路由
  1. function themeInit($archive)
  2. {
  3.     if ($archive->is('archive', 404))
  4.     {
  5.         $path_info = trim($archive->request->getPathinfo(), '/');
  6.         if ($path_info == 'i/redirect')
  7.         {
  8.             $url = urldecode($archive->request->url);
  9.             $archive->response->redirect($url);
  10.             exit;
  11.         }
  12.     }
  13. }
复制代码
原文地址:https://kotori.love/archives/typecho-theme-tips
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表