<?php
/**
- Typecho 主题 functions.php 文件
- 包含主题配置和智能分类显示数量继承功能
*/
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
// ==================== 主题配置部分 ====================
function themeConfig($form)
{
// 站点 LOGO 设置
$logoUrl = new \Typecho\Widget\Helper\Form\Element\Text(
'logoUrl',
null,
null,
_t('站点 LOGO 地址'),
_t('在这里填入一个图片 URL 地址, 以在网站标题前加上一个 LOGO')
);
$form->addInput($logoUrl);
// 侧边栏显示设置
$sidebarBlock = new \Typecho\Widget\Helper\Form\Element\Checkbox(
'sidebarBlock',
[
'ShowRecentPosts' => _t('显示最新文章'),
'ShowRecentComments' => _t('显示最近回复'),
'ShowCategory' => _t('显示分类'),
'ShowArchive' => _t('显示归档'),
'ShowOther' => _t('显示其它杂项')
],
['ShowRecentPosts', 'ShowRecentComments', 'ShowCategory', 'ShowArchive', 'ShowOther'],
_t('侧边栏显示')
);
$form->addInput($sidebarBlock->multiMode());
// 添加分类显示数量设置说明
$categoryDesc = new \Typecho\Widget\Helper\Form\Element\Textarea(
'categoryDesc',
null,
_t("分类显示数量设置说明:\n\n1. news分类及其子分类:10篇/页\n2. technology分类及其子分类:12篇/页\n3. life分类及其子分类:8篇/页\n4. 其他分类使用后台全局设置"),
_t('分类显示数量说明'),
_t('智能继承:子分类自动继承父分类的显示设置,除非单独指定。')
);
$form->addInput($categoryDesc);}
// ==================== 智能分类管理器 ====================
/**
- 分类智能继承管理器
- 功能:自动识别分类层级关系,子分类继承父分类的显示设置
*/
class SmartCategoryManager
{
/**
* 分类显示数量配置
* 格式:['分类标识' => 显示篇数]
* 分类标识可以是:别名 或 ID
*
* 优先级:子分类单独设置 > 继承父分类设置 > 全局设置
*/
private static $categoryConfig = [
// ===== 父分类配置 =====
// 使用分类别名
'news' => 10, // 新闻主分类:10篇
'technology' => 12, // 技术主分类:12篇
'life' => 8, // 生活主分类:8篇
'reviews' => 6, // 评测主分类:6篇
// 使用分类ID(如果不知道别名,可以用ID)
// '1' => 10, // 分类ID为1:10篇
// '2' => 12, // 分类ID为2:12篇
// ===== 子分类单独配置(如果需要特殊设置) =====
'news-mobile' => 15, // news的子分类,但单独显示15篇(不继承)
'tech-android' => 20, // technology的子分类,单独显示20篇
// 其他子分类会自动继承父分类设置
];
/**
* 分类别名到ID的映射缓存
*/
private static $slugToIdCache = [];
/**
* 分类ID到信息的映射缓存
*/
private static $categoryCache = [];
/**
* 获取分类完整信息
*/
private static function getCategoryInfo($identifier)
{
// 先从缓存读取
$cacheKey = $identifier;
if (isset(self::$categoryCache[$cacheKey])) {
return self::$categoryCache[$cacheKey];
}
$db = Typecho_Db::get();
$info = null;
try {
// 尝试作为ID或别名查询
$info = $db->fetchRow($db->select('mid', 'name', 'slug', 'parent')
->from('table.metas')
->where('mid = ?', $identifier)
->orWhere('slug = ?', $identifier)
->limit(1));
if ($info) {
// 缓存映射关系
self::$slugToIdCache[$info['slug']] = $info['mid'];
self::$categoryCache[$info['mid']] = $info;
self::$categoryCache[$info['slug']] = $info;
}
} catch (Exception $e) {
// 出错时返回null
}
return $info;
}
/**
* 获取父分类链(从当前分类到顶级分类)
*/
private static function getParentChain($categoryId)
{
$chain = [];
$currentId = $categoryId;
while ($currentId > 0) {
$info = self::getCategoryInfo($currentId);
if (!$info) break;
$chain[] = $info;
$currentId = $info['parent'];
// 防止无限循环
if (count($chain) > 10) break;
}
return $chain;
}
/**
* 智能获取分类应该显示的数量
* @param string $identifier 分类标识(ID或别名)
* @return int|null 显示数量,null表示使用全局设置
*/
public static function getSmartPageSize($identifier)
{
// 1. 检查是否有直接配置
if (isset(self::$categoryConfig[$identifier])) {
return self::$categoryConfig[$identifier];
}
// 2. 获取分类信息
$categoryInfo = self::getCategoryInfo($identifier);
if (!$categoryInfo) {
return null; // 分类不存在,使用全局设置
}
$categoryId = $categoryInfo['mid'];
$categorySlug = $categoryInfo['slug'];
// 3. 再次检查(可能在缓存中)
if (isset(self::$categoryConfig[$categoryId])) {
return self::$categoryConfig[$categoryId];
}
if (isset(self::$categoryConfig[$categorySlug])) {
return self::$categoryConfig[$categorySlug];
}
// 4. 如果是子分类,尝试继承父分类设置
if ($categoryInfo['parent'] > 0) {
$parentChain = self::getParentChain($categoryId);
foreach ($parentChain as $parent) {
// 检查父分类的ID
if (isset(self::$categoryConfig[$parent['mid']])) {
return self::$categoryConfig[$parent['mid']];
}
// 检查父分类的别名
if (isset(self::$categoryConfig[$parent['slug']])) {
return self::$categoryConfig[$parent['slug']];
}
}
}
// 5. 检查是否是某个配置分类的子分类(通过命名约定)
foreach (self::$categoryConfig as $configSlug => $pageSize) {
// 如果配置的分类名是当前分类名的前缀
if (strpos($categorySlug, $configSlug . '-') === 0) {
return $pageSize;
}
}
// 6. 没有找到配置,使用全局设置
return null;
}
/**
* 获取所有配置信息(用于调试)
*/
public static function getConfigInfo()
{
return [
'config' => self::$categoryConfig,
'cache_size' => count(self::$categoryCache),
'slug_map' => self::$slugToIdCache
];
}
/**
* 添加或更新分类配置(可选功能)
*/
public static function updateConfig($identifier, $pageSize)
{
self::$categoryConfig[$identifier] = $pageSize;
}}
// ==================== 主题初始化 ====================
/**
- 主题初始化函数
*/
function themeInit($archive)
{
// 只在分类页面生效
if ($archive->is('category')) {
// 获取当前分类标识(从URL参数)
$categorySlug = $archive->getArchiveSlug();
if (empty($categorySlug)) {
// 尝试从请求中获取
$categorySlug = $archive->request->get('category');
}
if (!empty($categorySlug)) {
// 获取智能计算后的显示数量
$pageSize = SmartCategoryManager::getSmartPageSize($categorySlug);
if ($pageSize !== null) {
$archive->parameter->pageSize = $pageSize;
// ===== 调试信息(正式使用时注释掉) =====
/*
$debugInfo = SmartCategoryManager::getConfigInfo();
error_log("智能分类设置生效:");
error_log(" 当前分类标识: {$categorySlug}");
error_log(" 设置显示数量: {$pageSize}");
error_log(" 总配置数: " . count($debugInfo['config']));
*/
}
}
}}
// ==================== 调试和辅助功能 ====================
/**
- 调试函数:显示分类层级信息
*/
function debugCategoryHierarchy()
{
if (isset($_GET['debug_category']) && $_GET['debug_category'] == '1') {
$archive = Typecho_Widget::widget('Widget_Archive');
if ($archive->is('category')) {
$categorySlug = $archive->getArchiveSlug();
echo "<!-- ===== 分类调试信息 ===== -->\n";
echo "<!-- 当前分类标识: {$categorySlug} -->\n";
$pageSize = SmartCategoryManager::getSmartPageSize($categorySlug);
echo "<!-- 智能计算显示数量: " . ($pageSize !== null ? $pageSize : '使用全局设置') . " -->\n";
$configInfo = SmartCategoryManager::getConfigInfo();
echo "<!-- 配置总数: " . count($configInfo['config']) . " -->\n";
echo "<!-- 缓存大小: " . $configInfo['cache_size'] . " -->\n";
// 显示配置详情
foreach ($configInfo['config'] as $key => $value) {
echo "<!-- 配置项: {$key} => {$value}篇 -->\n";
}
echo "<!-- ===== 调试信息结束 ===== -->\n";
}
}}
// 注册调试函数(正式使用时注释掉)
// add_action('init', 'debugCategoryHierarchy');
/**
- 简化的分类显示函数(用于模板中调用)
*/
function getCategoryDisplayInfo($categorySlug = null)
{
if ($categorySlug === null) {
$archive = Typecho_Widget::widget('Widget_Archive');
$categorySlug = $archive->getArchiveSlug();
}
$pageSize = SmartCategoryManager::getSmartPageSize($categorySlug);
return [
'slug' => $categorySlug,
'page_size' => $pageSize,
'is_custom' => $pageSize !== null
];}
/**
- 模板函数:在侧边栏显示分类数量设置
*/
function showCategoryPageSizeSettings()
{
echo '<div class="widget category-settings">';
echo '<h3 class="widget-title">分类显示设置</h3>';
echo '<ul>';
$config = [
'news' => 10,
'technology' => 12,
'life' => 8,
'reviews' => 6,
];
foreach ($config as $name => $size) {
echo "<li>{$name}分类: {$size}篇/页</li>";
}
echo '<li>其他分类: 使用全局设置</li>';
echo '<li>子分类自动继承父分类设置</li>';
echo '</ul>';
echo '</div>';}
// ==================== 示例配置说明 ====================
/*
- 如何使用本系统:
- 基本配置:
- 在 SmartCategoryManager::$categoryConfig 中配置父分类
- 例如:'news' => 10 表示news分类显示10篇
- 子分类继承:
- 所有news的子分类会自动继承10篇的设置
- 除非在配置中单独指定
- 单独配置子分类:
- 如果某个子分类需要不同的设置,直接配置:
- 'news-mobile' => 15 // news-mobile显示15篇
- 支持分类ID:
- 如果不知道分类别名,可以用ID:
- '1' => 10 // 分类ID为1显示10篇
- 命名约定继承:
- 如果子分类别名以父分类别名开头,也会继承
- 例如:news-iphone, news-android 都会继承news的设置
- 示例分类结构:
- news (10篇)
- ├── news-mobile (15篇,单独配置)
- ├── news-pc (10篇,自动继承)
- └── news-tablet (10篇,自动继承)
- technology (12篇)
- └── tech-phone (12篇,自动继承)
*/
// ==================== 初始化检查 ====================
/**
- 检查必要函数是否存在
*/
function checkThemeRequirements()
{
if (!function_exists('Typecho_Db::get')) {
error_log('Typecho数据库函数不可用,请检查Typecho安装');
}}
// 执行检查
add_action('init', 'checkThemeRequirements');