在开发typecho主题的时候,typecho本身已经提供了封装好的设置项类,常见的例如有:Checkbox
、Radio
、Select
、Text
、Textarea
等等。我们很方便的就能通过调用相关类来添加主题设置项,这也是最常见的一种方式。虽然够用,但这也带来了一些局限性,相比较于Wordpress,灵活度还是不够高。
为了解决上述问题,我们可以通过配合插件来从底层自己创建自定义的设置项页面。大致流程有:
- 通过插件添加相关路由
- 创建自定义的设置项表
- 封装相关数据库语句
- 创建全局变量以便于读取设置项
下面详细叙述各个流程:
创建插件并添加路由
创建一个插件目录,例如"YourPlugin",并在该目录下创建一个"Plugin.php"文件。接着就是添加插件基本方法以及需要继承的类,可以参考官方的HelloWorld插件来写。
在activate()
方法中,使用Helper
中的addRoute
添加路由:
const widgetName = 'TypechoPlugin\Furry\Router';
// 激活插件方法,如果激活失败,直接抛出异常
public static function activate()
{
Helper::addRoute('furry_options','/furry/options', self::widgetName, 'furryOptionsPageFunc');
Helper::addRoute('furry_options_api','/furry/api/options', self::widgetName, 'furryOptionsApiFunc');
}
这里我添加了/furry/options
以及/furry/api/options
两个路由。前者用来承接设置页的路由,后者用来加载数据库中的设置项,以json
形式返回给前端。
记得在Action
中实现furryOptionsPageFunc
以及furryOptionsApiFunc
两个方法,如果对于这一块不是很明白的可以参考Typecho的插件开发教程,网上有很多例子。这里我提供furryOptionsPageFunc
的例子:
// 渲染设置页
public function furryOptionsPageFunc()
{
if (User::alloc()->hasLogin()) {
include_once 'options/index.php';
} else {
Helper::options()->response->redirect('/admin/login.php');
}
}
当用户登录时,访问/furry/options
会加载options
文件夹中的index.php
。否则就会重定向到登录页面,这是一个简单的 鉴权。
创建相关数据表
通过上面的分析,我们还知道,需要创建一张表,专门用来存放设置的数据,同样的,可以使用Typecho提供的数据库操作类来实现,对Typecho数据库Api不熟悉的可以参考我的另一篇文章: Typecho数据库常用API 。我这里给出我的例子:
// 创建设置表
private static function createFurryOptionsTable()
{
$db = Db::get();
$prefix = $db->getPrefix();
$tableName = $prefix . 'furry_options';
if (!$db->fetchRow("SHOW TABLES LIKE '$tableName'")) {
$db->query('CREATE TABLE `' . $tableName . '` (
`name` varchar(100) NOT NULL COMMENT \'设置名\',
`type` varchar(20) NOT NULL COMMENT \'所属分类名\',
`value` text COMMENT \'设置值\',
PRIMARY KEY (`name`)
)');
}
}
在插件激活时,可以调用这个方法,就会创建一张表:
包括name设置名、type所属分类名、value设置值三个字段。这样,后面我们就可以存储自己的设置项了,即使切换主题也不会丢失,因为保存在了数据库中。
初始化设置项
表有了,下一步就是往里面写入数据。这里我们可以用一个数组来作为初始化的数据。接着用循环语句通过insert
方法来插入数据,我这里举个例子:
// 初始化options数据
private static function initOptions()
{
$arr = [
// 全局设置
["type" => "global", "name" => "AuthKey", "value" => ""],
["type" => "global", "name" => "BuildSiteTime", "value" => ""],
["type" => "global", "name" => "Favicon", "value" => ""],
["type" => "global", "name" => "ICP", "value" => ""],
["type" => "global", "name" => "Police", "value" => ""],
// 旁侧边栏
["type" => "sidebar", "name" => "LeftSide", "value" => "true"],
["type" => "sidebar", "name" => "RightSide", "value" => "true"],
];
$db = Db::get();
$prefix = $db->getPrefix();
$tableName = $prefix . 'furry_options';
foreach ($arr as $item) {
$insert = $db->insert($tableName)->rows($item);
$db->query($insert);
}
}
同样的,也是在插件激活的时候执行,就会得到初试的所有数据啦:
查询设置项并在主题中使用
前三小节都是在插件中完成,这里,我们就需要返回主题文件夹中操作了。我们都知道,在Typecho中,themeInit
函数是一个用于主题开发的钩子函数。它在每次加载主题时被调用,可以用来执行一些初始化操作和自定义功能。所以我们可以将这一步放入初始化函数中执行。也就是查询设置项并保存到全局变量中。
在functions.php
中添加下面的函数来读取设置项,并定义一个全局变量用于保存:
// 设置项全局变量
function furryThemeOptions()
{
$db = Db::get();
$prefix = $db->getPrefix();
$tableName = $prefix . 'furry_options';
$results = $db->fetchAll($db->select()->from($tableName));
$newArray = array();
foreach ($results as $item) {
$newArray[$item['name']] = $item['value'];
}
@define('__FurryOptions__', $newArray);
}
然后记得将这个函数在themeInit
函数中调用。这样,在主题模板文件中,就可以这样使用:
<aside class="col-span-3 px-8">
<!--加载设置项开始-->
<?php echo __FurryOptions__['AuthKey'] ?>
<!--加载设置项结束-->
<?php $this->need('inc/left/left.php'); ?>
</aside>
总结
至此,就完成了通过插件实现构建自定义设置页的教程,至于设置页的UI都可以通过自己的想法实现,甚至采用目前流行的前后端分离的方式去构建设置页。这样就能将现代前端的生态对接到typecho的管理当中。
感谢分享
很不错