diff --git a/admin/manage-categories.php b/admin/manage-categories.php
index 0851f875..e588cb02 100644
--- a/admin/manage-categories.php
+++ b/admin/manage-categories.php
@@ -66,8 +66,8 @@ Typecho_Widget::widget('Widget_Metas_Category_Admin')->to($categories);
- children > 0): ?>
- children); ?>
+ children) > 0): ?>
+ children)); ?>
diff --git a/var/Typecho/Db/Query.php b/var/Typecho/Db/Query.php
index b09b0a52..3a6f45d9 100644
--- a/var/Typecho/Db/Query.php
+++ b/var/Typecho/Db/Query.php
@@ -171,6 +171,26 @@ class Typecho_Db_Query
return $this->filterColumn(implode(' , ', $fields));
}
+ /**
+ * 转义参数
+ *
+ * @param array $values
+ * @access protected
+ * @return array
+ */
+ protected function quoteValues(array $values)
+ {
+ foreach ($values as &$value) {
+ if (is_array($value)) {
+ $value = '(' . implode(',', array_map(array($this->_adapter, 'quoteValue'), $value)) . ')';
+ } else {
+ $value = $this->_adapter->quoteValue($value);
+ }
+ }
+
+ return $values;
+ }
+
/**
* 获取查询字串属性值
*
@@ -215,7 +235,7 @@ class Typecho_Db_Query
} else {
$args = func_get_args();
array_shift($args);
- $this->_sqlPreBuild['where'] .= $operator . ' (' . vsprintf($condition, array_map(array($this->_adapter, 'quoteValue'), $args)) . ')';
+ $this->_sqlPreBuild['where'] .= $operator . ' (' . vsprintf($condition, $this->quoteValues($args)) . ')';
}
return $this;
@@ -239,7 +259,7 @@ class Typecho_Db_Query
} else {
$args = func_get_args();
array_shift($args);
- $this->_sqlPreBuild['where'] .= $operator . ' (' . vsprintf($condition, array_map(array($this->_adapter, 'quoteValue'), $args)) . ')';
+ $this->_sqlPreBuild['where'] .= $operator . ' (' . vsprintf($condition, $this->quoteValues($args)) . ')';
}
return $this;
@@ -353,7 +373,7 @@ class Typecho_Db_Query
} else {
$args = func_get_args();
array_shift($args);
- $this->_sqlPreBuild['having'] .= $operator . ' (' . vsprintf($condition, array_map(array($this->_adapter, 'quoteValue'), $args)) . ')';
+ $this->_sqlPreBuild['having'] .= $operator . ' (' . vsprintf($condition, $this->quoteValues($args)) . ')';
}
return $this;
diff --git a/var/Typecho/Router/Parser.php b/var/Typecho/Router/Parser.php
index de93ae48..3f1a715c 100644
--- a/var/Typecho/Router/Parser.php
+++ b/var/Typecho/Router/Parser.php
@@ -60,7 +60,7 @@ class Typecho_Router_Parser
'digital'=> '([0-9]%s)',
'alpha' => '([_0-9a-zA-Z-]%s)',
'alphaslash' => '([_0-9a-zA-Z-/]%s)',
- 'split' => '((:?[^/]+/)%s)',
+ 'split' => '((?:[^/]+/)%s[^/]+)',
);
}
diff --git a/var/Widget/Abstract/Contents.php b/var/Widget/Abstract/Contents.php
index 88d41e3d..b4cf541d 100644
--- a/var/Widget/Abstract/Contents.php
+++ b/var/Widget/Abstract/Contents.php
@@ -617,10 +617,13 @@ class Widget_Abstract_Contents extends Widget_Abstract
->join('table.relationships', 'table.relationships.mid = table.metas.mid')
->where('table.relationships.cid = ?', $value['cid'])
->where('table.metas.type = ?', 'category')
- ->order('table.metas.order', Typecho_Db::SORT_ASC), array($this->widget('Widget_Abstract_Metas'), 'filter'));
+ ->order('table.metas.order', Typecho_Db::SORT_ASC), array($this->widget('Widget_Metas_Category_List'), 'filter'));
/** 取出第一个分类作为slug条件 */
- $value['category'] = current(Typecho_Common::arrayFlatten($value['categories'], 'slug'));
+ $value['category'] = $value['categories'][0]['slug'];
+
+ $value['directory'] = $this->widget('Widget_Metas_Category_List')->getAllParents($value['category']['mid']);
+ $value['directory'][] = $value['category'];
$value['date'] = new Typecho_Date($value['created']);
@@ -638,8 +641,10 @@ class Widget_Abstract_Contents extends Widget_Abstract
$tmpSlug = $value['slug'];
$tmpCategory = $value['category'];
+ $tmpDirectory = $value['directory'];
$value['slug'] = urlencode($value['slug']);
$value['category'] = urlencode($value['category']);
+ $value['directory'] = implode('/', array_map('urlencode', $value['directory']));
/** 生成静态路径 */
$value['pathinfo'] = $routeExists ? Typecho_Router::url($type, $value) : '#';
@@ -683,6 +688,7 @@ class Widget_Abstract_Contents extends Widget_Abstract
$value['slug'] = $tmpSlug;
$value['category'] = $tmpCategory;
+ $value['directory'] = $tmpDirectory;
/** 处理密码保护流程 */
if (!empty($value['password']) &&
diff --git a/var/Widget/Archive.php b/var/Widget/Archive.php
index 582731bb..19f2affb 100644
--- a/var/Widget/Archive.php
+++ b/var/Widget/Archive.php
@@ -789,7 +789,9 @@ class Widget_Archive extends Widget_Abstract_Contents
$select->limit(1);
$this->query($select);
- if (!$this->have() || (isset($this->request->category) && $this->category != $this->request->category)) {
+ if (!$this->have()
+ || (isset($this->request->category) && $this->category != $this->request->category)
+ || (isset($this->request->directory) && $this->request->directory != implode('/', $this->directory))) {
if (!$this->_invokeFromOutside) {
/** 对没有索引情况下的判断 */
throw new Typecho_Widget_Exception(_t('请求的地址不存在'), 404);
@@ -869,21 +871,31 @@ class Widget_Archive extends Widget_Abstract_Contents
$categorySelect->where('slug = ?', $this->request->slug);
}
- $category = $this->db->fetchRow($categorySelect,
- array($this->widget('Widget_Abstract_Metas'), 'filter'));
+ if (isset($this->request->directory)) {
+ $directory = explode('/', $this->request->directory);
+ $categorySelect->where('slug = ?', $directory[count($directory) - 1]);
+ }
- if (!$category) {
+ $category = $this->db->fetchRow($categorySelect,
+ array($this->widget('Widget_Metas_Category_List'), 'filter'));
+
+ if (!$category
+ || (isset($directory) && ($this->request->directory != implode('/', $category['directory'])))) {
throw new Typecho_Widget_Exception(_t('分类不存在'), 404);
}
+ $children = $this->widget('Widget_Metas_Category_List')->getAllChildren($category['mid']);
+ $children[] = $category['mid'];
+
/** fix sql92 by 70 */
$select->join('table.relationships', 'table.contents.cid = table.relationships.cid')
- ->where('table.relationships.mid = ?', $category['mid'])
+ ->where('table.relationships.mid IN ?', $children)
->where('table.contents.type = ?', 'post');
/** 设置分页 */
$this->_pageRow = array_merge($category, array(
- 'slug' => urlencode($category['slug'])
+ 'slug' => urlencode($category['slug']),
+ 'directory' => implode('/', array_map('urlencode', $category['directory']))
));
/** 设置关键词 */
diff --git a/var/Widget/Comments/Archive.php b/var/Widget/Comments/Archive.php
index 5e6dd719..c3d64971 100644
--- a/var/Widget/Comments/Archive.php
+++ b/var/Widget/Comments/Archive.php
@@ -324,7 +324,6 @@ class Widget_Comments_Archive extends Widget_Abstract_Comments
/** 重载push函数,使用coid作为数组键值,便于索引 */
$this->stack[$value['coid']] = $value;
$this->length ++;
- $this->row = $value;
return $value;
}
diff --git a/var/Widget/Metas/Category/Admin.php b/var/Widget/Metas/Category/Admin.php
index 057f7ee9..c52d8d33 100644
--- a/var/Widget/Metas/Category/Admin.php
+++ b/var/Widget/Metas/Category/Admin.php
@@ -3,25 +3,13 @@
/**
* Widget_Metas_Category_Admin
*
- * @uses Widget_Abstract_Metas
+ * @uses Widget_Metas_Category_List
* @copyright Copyright (c) 2012 Typecho Team. (http://typecho.org)
* @author Joyqi
* @license GNU General Public License 2.0
*/
-class Widget_Metas_Category_Admin extends Widget_Abstract_Metas
+class Widget_Metas_Category_Admin extends Widget_Metas_Category_List
{
- /**
- * 子评论
- *
- * @access protected
- * @return array
- */
- protected function ___children()
- {
- return $this->size($this->db->sql()
- ->where('type = ? AND parent = ?', 'category', $this->mid));
- }
-
/**
* 执行函数
*
@@ -30,11 +18,11 @@ class Widget_Metas_Category_Admin extends Widget_Abstract_Metas
*/
public function execute()
{
- $select = $this->select()->where('type = ?', 'category');
+ $select = $this->db->select('mid')->from('table.metas')->where('type = ?', 'category');
$select->where('parent = ?', $this->request->parent ? $this->request->parent : 0);
- $this->db->fetchAll($select->order('table.metas.order', Typecho_Db::SORT_ASC),
- array($this, 'push'));
+ $this->stack = $this->getCategories(Typecho_Common::arrayFlatten(
+ $this->db->fetchAll($select->order('table.metas.order', Typecho_Db::SORT_ASC)), 'mid'));
}
/**
diff --git a/var/Widget/Metas/Category/Edit.php b/var/Widget/Metas/Category/Edit.php
index d36a4fcf..0095b16a 100644
--- a/var/Widget/Metas/Category/Edit.php
+++ b/var/Widget/Metas/Category/Edit.php
@@ -137,8 +137,8 @@ class Widget_Metas_Category_Edit extends Widget_Abstract_Metas implements Widget
/** 父级分类 */
$options = array(0 => _t('不选择'));
- $parents = $this->widget('Widget_Metas_Category_List@options', 'levelWalk=1'
- . (isset($this->request->mid) ? '&ignore=' . $this->request->mid : ''));
+ $parents = $this->widget('Widget_Metas_Category_List@options',
+ (isset($this->request->mid) ? 'ignore=' . $this->request->mid : ''));
while ($parents->next()) {
$options[$parents->mid] = $parents->nameByLevel;
@@ -258,13 +258,24 @@ class Widget_Metas_Category_Edit extends Widget_Abstract_Metas implements Widget
}
/** 取出数据 */
+ $current = $this->fetchRow($this->select()->where('mid = ?', $category['mid']));
$category = $this->request->from('name', 'slug', 'description', 'parent');
$category['slug'] = Typecho_Common::slugName(empty($category['slug']) ? $category['name'] : $category['slug']);
$category['type'] = 'category';
$category['mid'] = $this->request->mid;
- if ($this->fetchObject($this->select()->where('mid = ?', $category['mid']))->parent != $category['parent']) {
- $category['order'] = $this->getMaxOrder('category', $category['parent']) + 1;
+ if ($current['parent'] != $category['parent']) {
+ $parent = $this->fetchRow($this->select()->where('mid = ?', $category['parent']));
+
+ if ($parent['mid'] == $category['mid']) {
+ $category['order'] = $parent['order'];
+ $this->update(array(
+ 'parent' => $current['parent'],
+ 'order' => $current['order']
+ ), $this->db->sql()->where('mid = ?', $parent['mid']));
+ } else {
+ $category['order'] = $this->getMaxOrder('category', $category['parent']) + 1;
+ }
}
/** 更新数据 */
@@ -299,7 +310,7 @@ class Widget_Metas_Category_Edit extends Widget_Abstract_Metas implements Widget
$parent = $this->fetchObject($this->select()->where('mid = ?', $category))->parent;
if ($this->delete($this->db->sql()->where('mid = ?', $category))) {
- $this->db->query($this->db->sql()->delete('table.relationships')->where('mid = ?', $category));
+ $this->db->query($this->db->delete('table.relationships')->where('mid = ?', $category));
$this->update(array('parent' => $parent), $this->db->sql()->where('parent = ?', $category));
$deleteCount ++;
}
diff --git a/var/Widget/Metas/Category/List.php b/var/Widget/Metas/Category/List.php
index 93cacd43..e67a05b2 100644
--- a/var/Widget/Metas/Category/List.php
+++ b/var/Widget/Metas/Category/List.php
@@ -44,12 +44,36 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
private $_singleCategoryOptions = NULL;
/**
- * 原始的stack备份
+ * 顶层分类
*
* @var array
* @access private
*/
- private $_stack = array();
+ private $_top = array();
+
+ /**
+ * 所有分类哈希表
+ *
+ * @var array
+ * @access private
+ */
+ private $_map = array();
+
+ /**
+ * 所有子节点列表
+ *
+ * @var array
+ * @access private
+ */
+ private $_children = array();
+
+ /**
+ * 所有父节点列表
+ *
+ * @var array
+ * @access private
+ */
+ private $_parents = array();
/**
* 构造函数,初始化组件
@@ -63,12 +87,38 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
public function __construct($request, $response, $params = NULL)
{
parent::__construct($request, $response, $params);
- $this->parameter->setDefault('ignore=0&levelWalk=0');
+ $this->parameter->setDefault('ignore=0');
/** 初始化回调函数 */
if (function_exists('treeViewCategories')) {
$this->_customTreeViewCategoriesCallback = true;
}
+
+ $select = $this->select()->where('type = ?', 'category');
+ if ($this->parameter->ignore) {
+ $select->where('mid <> ?', $this->parameter->ignore);
+ }
+
+ $categories = $this->db->fetchAll($select->order('table.metas.order', Typecho_Db::SORT_ASC));
+ foreach ($categories as $category) {
+ $category['levels'] = 0;
+ $this->_map[$category['mid']] = $category;
+ }
+
+ // 读取数据
+ foreach ($this->_map as $mid => $category) {
+ $parent = $category['parent'];
+
+ if (0 != $parent && isset($this->_map[$parent])) {
+ $this->_treeViewCategories[$parent][] = $mid;
+ } else {
+ $this->_top[] = $mid;
+ }
+ }
+
+ // 预处理深度
+ $this->levelWalkCallback($this->_top);
+ $this->_map = array_map(array($this, 'filter'), $this->_map);
}
/**
@@ -80,13 +130,6 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
*/
private function treeViewCategoriesCallback()
{
- $levels = $this->levels;
- if (0 != $this->parent && isset($this->_stack[$this->parent]) && !$this->parameter->levelWalk) {
- $levels = $this->_stack[$this->parent]['levels'] + 1;
- $this->levels = $levels;
- $this->_stack[$this->mid]['levels'] = $levels;
- }
-
$singleCategoryOptions = $this->_singleCategoryOptions;
if ($this->_customTreeViewCategoriesCallback) {
return treeViewCategories($this, $singleCategoryOptions);
@@ -134,23 +177,30 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
* @access private
* @return void
*/
- private function levelWalkCallback(array $categories)
+ private function levelWalkCallback(array $categories, $parents = array())
{
- foreach ($categories as $mid => $category) {
- $parent = $category['parent'];
-
- if (0 != $parent && isset($this->stack[$parent])) {
- $levels = $this->stack[$parent]['levels'] + 1;
- $this->stack[$mid]['levels'] = $levels;
- $this->_treeViewCategories[$parent][$mid]['levels'] = $levels;
-
- if (isset($this->_stack[$mid])) {
- $this->_stack[$mid]['levels'] = $levels;
- }
+ foreach ($parents as $parent) {
+ if (!isset($this->_children[$parent])) {
+ $this->_children[$parent] = array();
}
+ $this->_children[$parent] = array_merge($this->_children[$parent], $categories);
+ }
+
+ foreach ($categories as $mid) {
+ $parent = $this->_map[$mid]['parent'];
+
+ if (0 != $parent && isset($this->_map[$parent])) {
+ $levels = $this->_map[$parent]['levels'] + 1;
+ $this->_map[$mid]['levels'] = $levels;
+ }
+
+ $this->_parents[$mid] = $parents;
+
if (!empty($this->_treeViewCategories[$mid])) {
- $this->levelWalkCallback($this->_treeViewCategories[$mid]);
+ $new = $parents;
+ $new[] = $mid;
+ $this->levelWalkCallback($this->_treeViewCategories[$mid], $new);
}
}
}
@@ -163,8 +213,8 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
*/
protected function ___children()
{
- return !empty($this->_treeViewCategories[$this->mid])
- ? $this->_treeViewCategories[$this->mid] : array();
+ return isset($this->_treeViewCategories[$this->mid]) ?
+ $this->getCategories($this->_treeViewCategories[$this->mid]) : array();
}
/**
@@ -175,7 +225,7 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
*/
protected function ___nameByLevel()
{
- return str_repeat(' ', $this->levels) . $this->name;
+ return str_repeat(' ', $this->levels) . $this->name;
}
/**
@@ -186,31 +236,7 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
*/
public function execute()
{
- $select = $this->select()->where('type = ?', 'category');
- if ($this->parameter->ignore) {
- $select->where('mid <> ?', $this->parameter->ignore);
- }
-
- $this->db->fetchAll($select->order('table.metas.order', Typecho_Db::SORT_ASC),
- array($this, 'push'));
-
- // 读取数据
- foreach ($this->stack as $mid => $category) {
- $parent = $category['parent'];
-
- if (0 != $parent && isset($this->stack[$parent])) {
- $this->_treeViewCategories[$parent][$mid] = $category;
- } else {
- $this->_stack[$mid] = $category;
- }
- }
-
- // 预处理深度
- if ($this->parameter->levelWalk) {
- $this->levelWalkCallback($this->_stack);
- }
-
- reset($this->stack);
+ $this->stack = $this->_map;
}
/**
@@ -265,15 +291,12 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
'feedTemplate' => 'RSS'
));
- // 存储原始数据方便树状访问
- $outputCategories = $this->_stack;
- $this->_stack = $this->stack;
- $this->stack = $outputCategories;
-
// 插件插件接口
$this->pluginHandle()->trigger($plugged)->listCategories($this->_singleCategoryOptions, $this);
if (!$plugged) {
+ $this->stack = $this->getCategories($this->_top);
+
if ($this->have()) {
echo '<' . $this->_singleCategoryOptions->wrapTag . (empty($this->_singleCategoryOptions->wrapClass)
? '' : ' class="' . $this->_singleCategoryOptions->wrapClass . '"') . '>';
@@ -282,6 +305,8 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
}
echo '' . $this->_singleCategoryOptions->wrapTag . '>';
}
+
+ $this->stack = $this->_map;
}
}
@@ -307,19 +332,82 @@ class Widget_Metas_Category_List extends Widget_Abstract_Metas
* @param array $value 每行的值
* @return array
*/
- public function push(array $value)
+ public function filter(array $value)
{
- $value = $this->filter($value);
-
- /** 计算深度 */
- $value['levels'] = 0;
+ $value['directory'] = $this->getAllParents($value['mid']);
+ $value['directory'][] = $value['slug'];
+
+ $tmpCategoryTree = $value['directory'];
+ $value['directory'] = implode('/', array_map('urlencode', $value['directory']));
+
+ $value = parent::filter($value);
+ $value['directory'] = $tmpCategoryTree;
- /** 重载push函数,使用coid作为数组键值,便于索引 */
- $this->stack[$value['mid']] = $value;
- $this->length ++;
- $this->row = $value;
-
return $value;
}
+
+ /**
+ * 获取某个分类下的所有子节点
+ *
+ * @param mixed $mid
+ * @access public
+ * @return array
+ */
+ public function getAllChildren($mid)
+ {
+ return isset($this->_children[$mid]) ? $this->_children[$mid] : array();
+ }
+
+ /**
+ * 获取某个分类所有父级节点
+ *
+ * @param mixed $mid
+ * @access public
+ * @return array
+ */
+ public function getAllParents($mid)
+ {
+ $parents = array();
+
+ if (isset($this->_parents[$mid])) {
+ foreach ($this->_parents[$mid] as $parent) {
+ $parents[] = $this->_map[$parent]['slug'];
+ }
+ }
+
+ return $parents;
+ }
+
+ /**
+ * 获取单个分类
+ *
+ * @param integer $mid
+ * @access public
+ * @return mixed
+ */
+ public function getCategory($mid)
+ {
+ return isset($this->_map[$mid]) ? $this->_map[$mid] : NULL;
+ }
+
+ /**
+ * 获取多个分类
+ *
+ * @param mixed $mids
+ * @access public
+ * @return array
+ */
+ public function getCategories($mids)
+ {
+ $result = array();
+
+ if (!empty($mids)) {
+ foreach ($mids as $mid) {
+ $result[] = $this->_map[$mid];
+ }
+ }
+
+ return $result;
+ }
}
diff --git a/var/Widget/Options/Permalink.php b/var/Widget/Options/Permalink.php
index 0439de79..44b1f9f9 100644
--- a/var/Widget/Options/Permalink.php
+++ b/var/Widget/Options/Permalink.php
@@ -29,8 +29,8 @@ class Widget_Options_Permalink extends Widget_Abstract_Options implements Widget
*/
protected function encodeRule($rule)
{
- return str_replace(array('{cid}', '{slug}', '{category}', '{category_parents}', '{year}', '{month}', '{day}', '{mid}'),
- array('[cid:digital]', '[slug]', '[category]', '[category_parents:split:0]',
+ return str_replace(array('{cid}', '{slug}', '{category}', '{directory}', '{year}', '{month}', '{day}', '{mid}'),
+ array('[cid:digital]', '[slug]', '[category]', '[directory:split:0]',
'[year:digital:4]', '[month:digital:2]', '[day:digital:2]', '[mid:digital]'), $rule);
}
@@ -103,7 +103,7 @@ class Widget_Options_Permalink extends Widget_Abstract_Options implements Widget
*/
public function checkCategoryPattern($value)
{
- return strpos($value, '{slug}') !== false || strpos($value, '{mid}') !== false;
+ return strpos($value, '{slug}') !== false || strpos($value, '{mid}') !== false || strpos($value, '{directory}') !== false;
}
/**
@@ -243,7 +243,7 @@ RewriteRule . {$basePath}index.php [L]
$patterns['custom'] = _t('个性化定义') . ' ';
$postPattern = new Typecho_Widget_Helper_Form_Element_Radio('postPattern', $patterns,
- $postPatternValue, _t('自定义文章路径'), _t('可用参数: {cid} 日志 ID, {slug} 日志缩略名, {category} 分类, {category_parents} 父级分类, {year} 年, {month} 月, {day} 日')
+ $postPatternValue, _t('自定义文章路径'), _t('可用参数: {cid} 日志 ID, {slug} 日志缩略名, {category} 分类, {directory} 多级分类, {year} 年, {month} 月, {day} 日')
. ' ' . _t('选择一种合适的文章静态路径风格, 使得你的网站链接更加友好.')
. ' ' . _t('一旦你选择了某种链接风格请不要轻易修改它.'));
if ($customPatternValue) {
@@ -258,7 +258,7 @@ RewriteRule . {$basePath}index.php [L]
$form->addInput($pagePattern->addRule(array($this, 'checkPagePattern'), _t('独立页面路径中没有包含 {cid} 或者 {slug} ')));
/** 分类页面 */
- $categoryPattern = new Typecho_Widget_Helper_Form_Element_Text('categoryPattern', NULL, $this->decodeRule($this->options->routingTable['category']['url']), _t('分类路径'), _t('可用参数: {mid} 分类 ID, {slug} 分类缩略名, {category_parents} 父级分类')
+ $categoryPattern = new Typecho_Widget_Helper_Form_Element_Text('categoryPattern', NULL, $this->decodeRule($this->options->routingTable['category']['url']), _t('分类路径'), _t('可用参数: {mid} 分类 ID, {slug} 分类缩略名, {directory} 多级分类')
. ' ' . _t('请在路径中至少包含上述的一项参数.'));
$categoryPattern->input->setAttribute('class', 'mono w-60');
$form->addInput($categoryPattern->addRule(array($this, 'checkCategoryPattern'), _t('分类路径中没有包含 {mid} 或者 {slug} ')));
|