我们前面实现了一个动作,通过追加面包屑链接,我们可以构建完整的面包屑对象了。做到这里,就基本上可以满足大部分实际需要了,只不过配置的过程比较麻烦一些,可能需要为每个内容类型分别配置面包屑。而我们的目标是建立基于分类的面包屑,而且构建起来,通用一些,这样模块的易用性就更高一些。所以我们这里借鉴一下Custom breadcrumbs里面的部分代码,从一个节点上面智能的获取第一个分类术语,然后以它为基础,构建面包屑。
首先,向breadcrumb2_rules_action_info追加一下代码:
/**
* Implements hook_rules_action_info().
*/
function breadcrumb2_rules_action_info() {
$items = array();
…..
$items['breadcrumb2_fetch_lightest_term_from_node'] = array(
'label' => t('Fetch lightest term from node'),
'group' => t('Breadcrumb2'),
'parameter' => array(
'node' => array(
'type' => 'node',
'label' => t('Node'),
'wrapped' => TRUE,
'save' => FALSE,
),
),
'base' => 'breadcrumb2_rules_fetch_lightest_term_from_node',
'access callback' => 'breadcrumb2_rules_integration_access',
'provides' => array(
'lightest_term' => array(
'type' => 'taxonomy_term',
'label' => t('First term'),
),
),
);
return $items;
}
这里,我们定义了一个新的动作,从节点上面获取第一个分类术语,参数只有一个node,动作的逻辑处理函数为breadcrumb2_rules_fetch_lightest_term_from_node;访问控制回调函数还是原来定义的。注意,这里面,我们使用了'provides',用来向rules提供一个新的可用的变量,这个变量的名字为lightest_term,数据类型为taxonomy_term,标签为'First term'(第一个分类术语)。如果动作需要返回一个变量的话,就需要用到这里的'provides',我这是第一次用这个参数。
接下来,我们看一下breadcrumb2_rules_fetch_lightest_term_from_node:
/**
* Action: Fetch lightest term from node.
*/
function breadcrumb2_rules_fetch_lightest_term_from_node(EntityDrupalWrapper $node) {
$term = breadcrumb2_node_get_lightest_term($node->value());
if(!empty($term)){
$term = taxonomy_term_load($term->tid);
}
return array('lightest_term' => $term);
}
这个动作里面的逻辑也非常简单,当然我们这里面,把重活都交给了帮助函数breadcrumb2_node_get_lightest_term。这个函数怎么来的呢?是从custom_breadcrumbs模块中复制过来的,我们只是把函数名的前缀,改成了我们自己的而已。
/********************Helper Function *************************************/
/**
* Returns the lightest term for a given node.
* Copy from custom_breadcrumbs_taxonomy module.
*
* If the term has parents, then the lightest parent's weight is used for the
* term weight. And if the parent has multiple child terms at different depths,
* the deepest child term will be returned. If the child terms have the same
* depth, then the lightest child term is returned.
*
* @param $node
* The node object.
*
* @return
* The taxonomy term object.
*/
function breadcrumb2_node_get_lightest_term($node) {
$terms = breadcrumb2_node_get_terms($node);
if (!empty($terms)) {
if (count($terms) > 1) {
foreach ($terms as $term) {
// Only consider terms in the lightest vocabulary.
if (!isset($vid)) {
$vid = $term->vid;
}
elseif ($term->vid != $vid) {
continue;
}
// If the term has parents, the weight of the term is the weight of the lightest parent.
$parents = taxonomy_get_parents_all($term->tid);
$depth = count($parents);
if ($depth > 0) {
$parent = array_pop($parents);
$weight = $parent->weight;
}
else {
$weight = $term->weight;
}
if ((isset($lweight) && ($weight < $lweight)) || !isset($lweight)) {
$lterm = $term;
$lweight = $weight;
$ldepth = $depth;
}
elseif (isset($lweight) && ($weight == $lweight)) {
// If the node has multiple child terms with the same parent, choose the child with the greatest depth.
if ($depth > $ldepth) {
$lterm = $term;
$ldepth = $depth;
}
elseif ($depth == $ldepth) {
// If the terms have the same depth, pick the term with the lightest weight.
$lterm = ($lterm->weight < $term->weight) ? $lterm : $term;
}
}
}
return $lterm;
}
else {
return array_pop($terms);
}
}
}
/**
* Copy from custom_breadcrumbs_taxonomy module.
* Finds all terms associated with a node.
* This is a D7 Replacement for Drupal 6 taxonomy_node_get_terms.
*/
function breadcrumb2_node_get_terms($node, $key = 'tid') {
static $terms;
if (isset($node->nid) && isset($node->vid)) {
if (!isset($terms[$node->vid][$key])) {
$query = db_select('taxonomy_index', 'r');
$t_alias = $query->join('taxonomy_term_data', 't', 'r.tid = t.tid');
$v_alias = $query->join('taxonomy_vocabulary', 'v', 't.vid = v.vid');
$query->fields( $t_alias );
$query->condition("r.nid", $node->nid);
$query->orderBy('v.weight');
$query->orderBy('t.weight');
$query->orderBy('t.name');
$result = $query->execute();
$terms[$node->vid][$key] = array();
foreach ($result as $term) {
$terms[$node->vid][$key][$term->$key] = $term;
}
}
return $terms[$node->vid][$key];
}
return array();
}
breadcrumb2_node_get_terms负责获取一个节点上面的所有分类术语,breadcrumb2_node_get_lightest_term从这些分类术语当中,按照特定的规则,找出第一个分类术语。在Drupal6里面,有个函数taxonomy_node_get_terms,可以用来获取节点上面的所有术语,但是这个函数在Drupal7里面没有了。另外需要注意的是,我们是从表taxonomy_index中获取数据的,在这个数据库表中,维护了节点分类术语之间的对应关系。我以前使用custom breadcrumbs模块的时候,修改过它们这里的代码,所以就把它们偷过来了。用孔乙己的话说,对程序员来说,这叫借,不叫偷。
好了,现在清除缓存,添加动作,就可以看到这个动作了。选中这个动作,进入配置页面,系统智能的为我们的参数选择了node:
其它都不用修改,注意这里提供的变量,与前面代码的对应关系。保存这里的设置,我们现在就可以使用变量“First term (lightest_term)”了。现在,我们就可以再追加一个面包屑链接了。这是追加的链接:
现在,我们创建一个词汇表(product_category),并添加以下分类术语:
接着创建一个内容类型product,并为其添加一个分类字段,引用的词汇表就是刚刚创建的。接着,我们创建一个产品,分类术语选择A11,这个时候系统会总动的帮助我们创建一个面包屑对象。面包屑的显示效果:
如果这里,能够把A11 的父术语A和A1也都显示出来,效果就完美了。注意,现在面包屑链接中的路径,还没有在内部定义,根据实际需要可以调整。