K2的相关文章如何限定分类?
K2的文章,自带有相关文章的功能,它是由K2的标签系统来实现的,也就是说,如果都使用了同样的标签,那么相关文章中,就会显示这些文章。
但K2的默认相关文章功能,并不能设定分类,来筛选输出文章。在具体建站项目中,例如产品栏目和技术栏目或新闻栏目,共用了“无线通讯”这个标签,产品详情页面,我想显示相关产品,实际上可能显示新闻文章,这就不合理。或者如果我们需要在产品详情页面,显示“相关产品”、“相关技术”、“相关新闻”,那应该怎样实现呢?
思路有三种,分别是
方法一:使用 K2 Content 模块
这是最简单且灵活的方法(但实际是换个思路和方式,并不是实际解决方式)。你可以不使用item.php自带的相关项目代码,而是通过模块实现:
- 新建模块:进入模块管理器,新建一个K2 Content模块。
- 设置关联模式:在模块设置的“Select items”选项中,选择Retrieve items from categories。
- 限定类别:在分类列表中选择你想要限定的那个“指定类别”,并确保开启Fetch items from children categories(获取子类项目)。
- 开启标签匹配:找到“Item matching”或类似选项,设置为Matching on tags(仅匹配当前页面的标签)。
- 分配位置:将模块分配到项目页面使用的位置(或使用
{loadposition}插入item.php)。
关于如何定制K2 Content 模块,我们之前在《自定义输出mod k2 content模块的文章》的教程中已经有详细介绍。
方法二:修改 K2 模板(Template Override)
如果你想在 item.php 模板中通过代码过滤,可以通过修改数据库查询逻辑来实现。K2 的相关项目数据是通过 $this->relatedItems 传递的。你可以在 item.php 中使用 PHP 对其进行过滤:
在 item.php 中使用的 $this->relatedItems 是 K2 在后台预先查询好的结果(通常默认只取 5 条或 10 条)。如果你在前端用 if 过滤,程序逻辑如下: K2 从数据库抓取了 5 条标签相关的文章。你的代码检查这 5 条。如果这 5 条都不在 ID 10 的分类里,页面上将什么都不显示,即使数据库里其实还有第 6、7 条符合条件的文章。
解决方案:重新构建数据库查询
为了确保能显示出属于指定分类的相关项目,你不能在 PHP 里过滤,而必须在 item.php 中重新向数据库发起一次带条件的请求。
<?php
/**
* 逻辑处理:获取分类ID为1及其所有子类的相关项目
*/
$targetParentCatId = 1; // 指定分类ID
$db = JFactory::getDbo();
// 1. 获取所有子类 ID (包含无限层级)
$allCatIds = array($targetParentCatId);
$query = "SELECT id FROM #__k2_categories WHERE parent = ".(int)$targetParentCatId." AND published = 1";
$db->setQuery($query);
$subCatIds = $db->loadColumn();
if (!empty($subCatIds)) {
$allCatIds = array_merge($allCatIds, $subCatIds);
// 再次尝试获取孙子类 (为了覆盖更深层级)
$query = "SELECT id FROM #__k2_categories WHERE parent IN (".implode(',', $subCatIds).") AND published = 1";
$db->setQuery($query);
$grandChildIds = $db->loadColumn();
if (!empty($grandChildIds)) {
$allCatIds = array_merge($allCatIds, $grandChildIds);
}
}
$allCatIds = array_unique($allCatIds);
$catCondition = implode(',', $allCatIds);
// 2. 获取当前项目标签并查询
$tagIds = array();
if (isset($this->item->tags) && count($this->item->tags)) {
foreach($this->item->tags as $tag) { $tagIds[] = (int)$tag->id; }
}$customRelatedItems = array();
if (!empty($tagIds)) {
$tagIdsCondition = implode(',', $tagIds);
$sql = "SELECT DISTINCT i.*
FROM #__k2_items AS i
INNER JOIN #__k2_tags_xref AS x ON i.id = x.itemID
WHERE x.tagID IN ($tagIdsCondition)
AND i.catid IN ($catCondition)
AND i.id != ".(int)$this->item->id."
AND i.published = 1
AND i.trash = 0
ORDER BY i.created DESC LIMIT 4"; // 根据你的 col-md-3 排版,建议限制为 4 条
$db->setQuery($sql);
$customRelatedItems = $db->loadObjectList();
}
?>
<?php if(count($customRelatedItems)): ?>
<h2 class="itemRelated-title"><span><?php echo JText::_("K2_RELATED_ITEMS_BY_TAG_PRO"); ?></span></h2>
<div class="itemRelated">
<div class="row">
<?php foreach($customRelatedItems as $item):
// 手动构建链接
$item->link = JRoute::_(K2HelperRoute::getItemRoute($item->id.':'.urlencode($item->alias), $item->catid));
// 手动构建图片路径 (MD5 规则),使用中等尺寸 _M (如需小图改 _S)
$imageName = md5("Image".$item->id);
$item->image = JURI::root().'media/k2/items/cache/'.$imageName.'_M.jpg';
?>
<div class="col-md-3 col-sm-6">
<a href="/<?php echo $item->link; ?>" class="uk-thumbnail uk-overlay-toggle">
<img src="/<?php echo $item->image; ?>" alt="<?php echo K2HelperUtilities::cleanHtml($item->title); ?>" />
</a>
<h4><?php echo $item->title; ?></h4>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
方法三:使用第三方扩展插件
如果你的过滤逻辑更复杂(例如需要根据当前项目动态决定类别范围),可以考虑专业的关联项目插件:
- RAXO Related Articles:支持极其精细的过滤条件,包括限定 K2 类别和子类。
- BT Related Items:针对 K2 优化的关联插件。