为什么自己要写一个主题
一开始我是很排斥 WordPress 的,不过后面发现,WordPress 插件齐全而且主题极其丰富,除了后台访问速度慢真的没什么缺点。去年,多年不写代码的我手痒起来了,觉得为自己写一个只属于自己的主题应该很棒——于是我草草看完 PHP 文档就开始写了。WordPress 提供了很多 Hooks,所以在写主题时要实现某个功能很容易找到解决方案,这也是我觉得 WordPress 很棒的一点。
小站经历
这个小站去年就建好,然后被我扔着吃灰。直到上个月域名过期了,腾讯云打来电话取消我的备案我才想到还有这个小站的存在……只可惜已经晚了,我也懒得再备案了,于是把站迁移到了 $2.5 的 vultr 上,用了点奇淫技巧给 2.5美刀的小鸡上了 IPv4。我原本想继续使用 Docker 部署,后面发现宝塔面板真香!至于这个网站到底要拿来做什么,我写什么放上去,这都是后话,我只是单纯地想给自己写个博客主题,顺便敲敲代码过过瘾而已。
没有设计的苦恼
最开始我使用的是简单的线条分割的三栏式布局,略微支持所谓的响应式,写了不少媒体查询。本来这样就已经结束了,直到后来我开始关注移动端。我发现这种简单的线条分割的方式,在 PC 端看起来似乎勉强可以接受,只要图片和配色得当应该也还看得过去。但是在移动端,这种布局显得混乱不堪。文字过多,色彩过于喧宾夺主,以及缺少明确的区块分割等等问题在移动端完全暴露了出来。这时候我正在做夜间模式,发现夜间模式效果在移动端也非常的混乱。
怎么办?只有改版了,所以怎么改?我做了很多尝试,最后只好求稳使用了大色块进行内容的分割,同时也用上了圆角矩形。背景颜色和高亮色也做了变换,不再使用红色作为高亮色(虽然我很喜欢红色),背景颜色做了略微加深。最后就成了这样!
因为大色块和原本线条风格的 Header 完全不搭,只好重写 Header 的样式,导航的文字也由居中改成了居左。但是文字居左又带来一个问题,就是右边显得太空了。我头像是居中,下面的文字又居左,会显得不搭。于是我加了 hover 效果和右边的箭头图标。
不过,还没有完……
我决定再做一个横向 Header 效果,同时完善了一下夜间模式,防止审美疲劳,所以版面又成了这样。
夜间模式变成了这样。
完成的功能
1.页面
我自己完成了一个时间线页面,一个友链页面和关于页面。这3个页面是单独的文件,我不想让我主题每个页面都千篇一律的样子,所以单独拿出来写了。当然单独实现这些页面其实不复杂,只需要建立 page-about.php
, page-timeline.php
, page-friends.php
这些模板然后分开写就行了。比如说时间线页面:
2.目录功能
目录功能是我很早已经就已经完成的了,由于没有好的参考,只好自己用遍历的方式在 Web 端实现。
interface catalogElement {
el: HTMLElement | Element;
}
interface catalogReturns {
length: number;
[index:number] : { $1th: any, $2th: any}
}
function initCatalog(el:catalogElement['el']):catalogReturns {
/**
* 假定处理过后的hArr 如下:
* [
* {tag: "h3", text: "一级1"},
* {tag: "h5", text: "二级1-1"},
* {tag: "h5", text: "二级1-2"}
* {tag: "h3", text: "一级2"},
* {tag: "h6", text: "二级2-1"},
* {tag: "h6", text: "二级2-2"},
* {tag: "h3", text: "一级3"},
* {tag: "h3", text: "一级4"}
* ]
*
*/
if (!el) throw "el is not a HTMLElement";
let hArr = [];
let els;
if (!el.querySelectorAll) {
els = el.children;
} else {
els = el.querySelectorAll("h1, h2, h3, h4, h5, h6");
}
for (let i = 0; i < els.length; i++) {
// 遍历所给元素el 的所有子节点中是标题标签的节点
if (els[i].nodeType === 1 && /H\d/i.test(els[i].nodeName)) {
// let name = els[i].getElementsByTagName('a')[0].getAttribute('name');
let name = els[i].getAttribute('name');
hArr.push({tag: els[i].nodeName.toLowerCase(), text: els[i].innerText, name: name, el: els[i]});
}
}
if (hArr.length <= 0) {
return []
}
let titles = []; // 存放目录的数组,包含1级和2级目录
let level1tag = hArr[0].tag; // 第一次出现的h标签就是第一层标题对应的标签: 比如第一次出现的是<h3>
let level2tag = ''; // 第二层级的标题对应的标签; 比如可能是任何大于h3的标签,如<h4>,<h5>,<h6>
let $2th:any = []; // 二级标题数组
for (let i = 0; i < hArr.length; i++) {
let obj = { // 每一个第一级标题下面对应了一组第二级标题
$1th: {}, // 第一级标题
$2th: [] // 第二级标题
};
if (hArr[i].tag === level2tag) {
$2th.push(hArr[i]); // 如果当前标题2级标题, 那么将该2级标题push 到 $2th, 并且跳过后面的代码;如果下一个标题还是2级标题, 则继续push并跳过
hArr[i].el.classList.add('catalog-title');
hArr[i].el.classList.add('ct-level2');
continue
} else if (hArr[i].tag === level1tag) {
// 动态确定第二层标题对应的标签 level2Tag; 可能是任何大于<h3>的标签, 如h4, h5, h6
for (let j = i + 1; j < hArr.length; j++) {
if (hArr[j].tag > level1tag) {
level2tag = hArr[j].tag;
break
}
}
obj.$1th = hArr[i];
hArr[i].el.classList.add('catalog-title');
hArr[i].el.classList.add('ct-level1');
$2th = []; // 如果检测到1级的标题, 则置$2th 为空
} else {
// 第三级 及 深层次的目录标题直接忽略
continue
}
obj.$2th = $2th;
titles.push(obj);
}
return titles
}
3.为主题添加支持
我看很多主题在后台都可以自定义,我看着着实羡慕,于是自己也开始着手做了做。前面说到的 Hooks 在这里就很有用了,WordPress 真香!WordPress 提供了 add_theme_support
的钩子函数,于是我参考文档用这个函数让主题支持了一些功能;包括:自定义Logo、缩略图支持、缩略图大小调整和自定义背景图片等
/**
* 添加主题支持
*/
function theme_setup() {
add_theme_support('custom-logo', array(
'width' => 500,
'height' => 500,
'flex-width' => false,
'flex-height' => false
));
add_theme_support( 'post-thumbnails', array('post'));
add_image_size( 'custom-tb-size', get_option('mingof_tb_img_width',600), get_option('mingof_tb_img_height',400));
add_theme_support('custom-background',array(
'default-image'=>'',
'default-position-x'=>'center',
'default-position-y'=>'center',
'default-size'=>'cover',
'default-attachment'=>'fixed'
));
add_theme_support( 'title-tag' );
}
add_action('after_setup_theme', 'theme_setup');
当然这还不够,我还想实现切换“主题色”的功能,还想实现切换“横向 Header” 和“纵向 Header“ 的功能。所以我找到了 WordPress 的 add_action 文档。
add_action( 'customize_register', 'mingof_customize_register');
/**
* 注册自定义功能
* @param $wp_customize
*/
function mingof_customize_register( $wp_customize ) {
// 这里注册设置
$wp_customize->add_setting( 'mingof_style_options[highlight_color]', array(
'default' => '#738fa3',
'type' => 'option',
'capability' => 'edit_theme_options',
'transport' => 'refresh'
));
$wp_customize->add_setting('mingof_style_options[highlight_color_in_dark_mode]',array(
'default'=>'#b18983',
'type'=>'option',
'capability'=>'edit_theme_options',
'transport'=>'refresh'
));
// 这里注册 control
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'highlight_color', array(
/*名字*/
'label' => __( '高亮色(主题色)', 'mingof' ),
/*section属于……*/
'section' => 'colors',
/*对应的settings*/
'settings' => 'mingof_style_options[highlight_color]',
)));
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'highlight_color_in_dark_mode', array(
'label' => __( '夜间模式高亮色', 'mingof' ),
'show_opacity'=>true,
'section' => 'colors',
'settings' => 'mingof_style_options[highlight_color_in_dark_mode]'
)));
}
最终效果就是这样。
最后
主题完工了,一阵空虚……我好像不怎么爱写博客T^T
可以使用公开的QQ接口来获取昵称和头像,免去了a站或头像统一的可能,还能手机QQ😜