升级Typecho并添加AMP支持
2017年12月1日更新:AMP功能已经做成插件,详情见这里
很不幸,我使用Typecho前段时间爆出非常严重的安全漏洞,好在我之前做过习惯性地加固,install.php相关的文件也删除了,所以即使满大街都是漏洞利用工具,也没受到本次漏洞的伤害。
既然官方已经出了1.1的更新,我也就顺手将博客程序升级了:结果升级一时爽,模板火葬场。因为博客内容经过多个转换程序,而且年久失修,加上原来在模板上做过一些高耦合的hack,所有弊端一次性爆发,导致不得不推到重来一遍。于是乘着这个机会一并解决了一些遗留问题,并顺手增加AMP功能。
HTML转Markdown
由于07年至今用过Boblog,Emlog等博客系统,数据编辑器从UBB到HTML富文本都用过,所以context里的内容鱼目混杂。于是首先要进行内容格式统一:UBB转换成HTML,HTML集体转换为Markdown。UBB转HTML基本没问题,HTML转Markdown建议用html2text完成,基本上格式可以保留,记得设置.body_width =0不主动换行即可。
import pymysql.cursors
import html2text
connection = pymysql.connect(host='localhost',
user='root',
password='password',
db='typecho',
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor)
try:
with connection.cursor() as cursor:
# Read a single record
sql = "SELECT * FROM `typecho_contents`"
cursor.execute(sql)
result = cursor.fetchall()
for x in result:
if(x['text'][0:15]=='<!--markdown-->' or x['type']=='attachment'):
pass
else:
h = html2text.HTML2Text()
h.ignore_links = False
h.body_width =0
md_text='<!--markdown-->'+h.handle(x['text'])
sql="UPDATE `typecho_contents` SET `text` =%s WHERE `cid` = %s ;"
print(x['cid'])
cursor.execute(sql,(md_text,str(x['cid'])))
connection.commit()
finally:
connection.close()
支持AMP
之所以要统一博客内容统一成Markdown,除了强迫症之外,更主要的是为了支持AMP。Typecho至今没有出任何支持AMP的插件或主题,我没去想怎么用插件实现AMP,而是直接通过修改模板的post.php、function.php文件来暴力实现,原则上所有模板都可以用。
效果就是在任何一篇博文的url后面加上amp=1即可访问amp版的页面,例如本文的AMP页面,总之实现起来也很简单。
具体步骤如下:
对模板里的post.php文件做如下修改(后台控制台》外观》编辑当前外观》post.php):
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<?php if (isset($_GET['amp'])){; ?>
<!doctype html>
<html amp lang="zh">
<head>
<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<title><?php $this->title() ?></title>
<link rel="canonical" href="<?php $this->permalink() ?>" />
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "BlogPosting",
"headline": "<?php $this->title(); ?>",
"mainEntityOfPage": "<?php $this->permalink() ?>",
"author": {
"@type": "Person",
"name": "<?php $this->author(); ?>"
},
"datePublished": "<?php $this->date('F j, Y'); ?>",
"dateModified": "<?php $this->date('F j, Y'); ?>",
"image": {
"@type": "ImageObject",
"url": "<?php print_r(get_post_img($this));?>",
"width": 700,
"height": 400
},
"publisher": {
"@type": "Organization",
"name": "Holmesian Blog",
"logo": {
"@type": "ImageObject",
"url": "https://holmesian.org/usr/themes/Holmesian/images/holmesian.png",
"width": 60,
"height": 60
}
},
"description": "<?php $this->excerpt(60, '...'); ?>"
}
</script>
<style amp-custom>*{margin:0;padding:0}html,body{height:100%}body{background:#fff;color:#666;font-size:14px;font-family:"-apple-system","Open Sans","HelveticaNeue-Light","Helvetica Neue Light","Helvetica Neue",Helvetica,Arial,sans-serif}::selection,::-moz-selection,::-webkit-selection{background-color:#2479CC;color:#eee}h1{font-size:1.5em}h3{font-size:1.3em}h4{font-size:1.1em}a{color:#2479CC;text-decoration:none}article{padding:85px 15px 0}article .entry-content{color:#444;font-size:16px;font-family:Arial,'Hiragino Sans GB',冬青黑,'Microsoft YaHei',微软雅黑,SimSun,宋体,Helvetica,Tahoma,'Arial sans-serif';-webkit-font-smoothing:antialiased;line-height:1.8;word-wrap:break-word}article h1.title{color:#333;font-size:2em;font-weight:300;line-height:35px;margin-bottom:25px}article .entry-content p{margin-top:15px}article h1.title a{color:#333;transition:color .3s}article h1.title a:hover{color:#2479CC}article blockquote{background-color:#f8f8f8;border-left:5px solid #2479CC;margin-top:10px;overflow:hidden;padding:15px 20px}article code{background-color:#eee;border-radius:5px;font-family:Consolas,Monaco,'Andale Mono',monospace;font-size:80%;margin:0 2px;padding:4px 5px;vertical-align:middle}article pre{background-color:#f8f8f8;border-left:5px solid #ccc;color:#5d6a6a;font-size:14px;line-height:1.6;overflow:hidden;padding:0.6em;position:relative;white-space:pre-wrap;word-break:break-word;word-wrap:break-word}article table{border:0;border-collapse:collapse;border-spacing:0}article pre code{background-color:transparent;border-radius:0 0 0 0;border:0;display:block;font-size:100%;margin:0;padding:0;position:relative}article table th,article table td{border:0}article table th{border-bottom:2px solid #848484;padding:6px 20px;text-align:left}article table td{border-bottom:1px solid #d0d0d0;padding:6px 20px}article .copyright-info,article .amp-info{font-size:14px}article .expire-tips{background-color:#f5d09a;border:1px solid #e2e2e2;border-left:5px solid #fff000;color:#333;font-size:15px;padding:5px 10px;margin:20px 0px}article .post-info,article .entry-content .date{font-size:14px}article .entry-content blockquote,article .entry-content ul,article .entry-content ol,article .entry-content dl,article .entry-content table,article .entry-content h1,article .entry-content h2,article .entry-content h3,article .entry-content h4,article .entry-content h5,article .entry-content h6,article .entry-content pre{margin-top:15px}article pre b.name{color:#eee;font-family:"Consolas","Liberation Mono",Courier,monospace;font-size:60px;line-height:1;pointer-events:none;position:absolute;right:10px;top:10px}article .entry-content .date{color:#999}article .entry-content ul ul,article .entry-content ul ol,article .entry-content ul dl,article .entry-content ol ul,article .entry-content ol ol,article .entry-content ol dl,article .entry-content dl ul,article .entry-content dl ol,article .entry-content dl dl,article .entry-content blockquote > p:first-of-type{margin-top:0}article .entry-content ul,article .entry-content ol,article .entry-content dl{margin-left:25px}.header{background-color:#fff;box-shadow:0 0 40px 0 rgba(0,0,0,0.1);box-sizing:border-box;font-size:14px;height:60px;padding:0 15px;position:absolute;width:100%}.footer{font-size:.9em;padding:15px 0 25px;text-align:center;width:auto}.header h1{font-size:30px;font-weight:400;line-height:30px;margin:15px 0px}.menu-list li a,.menu-list li span{border-bottom:solid 1px #ededed;color:#000;display:block;font-size:18px;height:60px;line-height:60px;text-align:center;width:86px}.header h1 a{color:#333}.tex .hljs-formula{background:#eee8d5}</style>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
<noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
</head>
<body>
<header class="header"><div class="header-title"><h1><a href="/">Holmesian Blog</a></h1></div></header>
<article class="post"><h1 class="title"><?php $this->title(); ?></h1>
<div class="entry-content">
<?php ampInit($this);?>
<?php $this->content(); ?>
</div>
<p class="expire-tips">当前页面是本站的「<a href="//www.ampproject.org/zh_cn/">Google AMP</a>」版。查看和发表评论请点击:<a href="<?php $this->permalink() ?>#comments">完整版 »</a></p>
</article>
</body>
</html>
<?php } else {?>
\\这里是原模板内容
<?php }?>
接着在functions.php文件末尾添加下列两个函数。
function ampInit($archive)
{
if ($archive->is('single')) {
$archive->content = str_replace('<img','<amp-img width="900" height="675" layout="responsive" ',$archive->content);
$archive->content = str_replace('img>','amp-img>',$archive->content);
$archive->content = str_replace('<!- toc end ->','',$archive->content);
$archive->content = str_replace('#','#',$archive->content);
}
}
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'];
$pattern = '/\<img.*?src\=\"(.*?)\"[^>]*>/i';
$patternMD = '/\!\[.*?\]\((http(s)?:\/\/.*?(jpg|png))/i';
$patternMDfoot = '/\[.*?\]:\s*(http(s)?:\/\/.*?(jpg|png))/i';
if (preg_match($patternMDfoot, $text, $img)) {
$img_url = $img[1];
} else if (preg_match($patternMD, $text, $img)) {
$img_url = $img[1];
} else if (preg_match($pattern, $text, $img)) {
preg_match("/(?:\()(.*)(?:\))/i", $img[0], $result);
$img_url = $img[1];
} else {
$img_url ='https://holmesian.org/usr/themes/Holmesian/images/holmesian.png?type=markdown';
}
return $img_url;
}
最后在header.php中添加下列内容
<?php if ($this->is('post')): ?>
<link rel="amphtml" href="<?php $this->permalink() ?>?amp=1">
<?php endif; ?>
全部修改之后,刷新缓存,就可以访问AMP页面啦。
PS:可以到这里测试你的AMP页面是否正确有效。
PS2:Google大概会在48小时内抓取到AMP页面,并在搜索结果中体现出来。效果如下:
当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »