На сайте стоит модуль Superfish, позволяющий создавать красивые выпадающие меню. Для пунктов меню он генерирует HTML-код такого вида (разбил на строки для наглядности):
<a href="/foo" title="bar">Menu Item</a>
</li>
Из соображений темизации необходимо привести этот код к такому виду:
<a href="/foo" title="bar">
<span class="back"><span class="bg1"></span>
Menu Item
<span class="foreground"></span></span>
</a>
</li>
Т.е. добавить несколько тегов span вокруг, до и после текста ссылки, но внутри тега < a >.
В коде модуля я нашёл такие строки:
$children = theme('superfish_build', $id, $menu_item['below'], $depth, $trail);
$parent_class = $children ? 'menuparent ' : '';
$output .= '<li id="menu-'. $mlid .'-'. $id .'"';
if (!empty($parent_class) || !empty($class)) {
$output .= ' class="'. $parent_class . $class .'"';
}
$output .= '>'. theme('menu_item_link', $menu_item['link']);
if ($menu_item['link']['depth'] <= $depth || $depth == -1) {
if ($children) {
$output .= "<ul>\n $children \n</ul>\n";
}
}
$output .= "</li>\n";
}
else {
$output .= '<li id="menu-'. $mlid .'-'. $id .'"';
if (!empty($class)) {
$output .= ' class="'. $class .'"';
}
$output .= '>'. theme('menu_item_link', $menu_item['link']) .'</li>'."\n";
}
Как я понял, код самого текста ссылки получается вот здесь:
Однако, поскольку я php владею ооочень поверхностно, я не понимаю, что это за theme('menu_item_link', $menu_item['link']), и как его изменить (да, я пытался разобраться в API - но только больше запутался).
Поэтому обращаюсь с вопросом:
можно ли только средствами темизации (не модифицируя файлы самого друпала) изменить код, возвращаемый этим выражением, и как это сделать?
Насколько смог, попытался разобраться сам. Похоже, что это то ли какая-то процедура, то ли функция - но где она находится и как её изменить файлами tpl.php - простите, не знаю.
Комментарии
Отчаянные времена требуют отчаянных мер. Даже не верится, что залез так глубоко...
Насколько я разобрался, в данном коде ссылка формируется за счёт обращения к функции theme_menu_item_link, которая может быть перекрыта аналогичной phptemplate_menu_item_link в файле template.php темы.
Однако такое решение нехорошо - т.к. искомый код будет добавлен вообще ко всем менюхам на сайте, а не только к нужной. Стал копать дальше.
Выяснил, что при обращении к функции theme_menu_item_link в качестве аргумента передаётся массив. Стало быть, мы можем перекрыть саму функцию модуля superfish, чтобы отправляемая в качестве текста ссылки переменная уже имела всю "обёртку" тегами span. В template.php вставляю изменённую функцию:
...
$menu_item['link']['title'] = '<span class="back"><span class="hover"></span></span><span class="text">' . $menu_item['link']['title'] . '</span><span class="front"></span>';
...
}
Сделал. Даже получилось. Однако все пункты меню Superfish стали в качестве текста ссылки выдавать то, что по идее должно обрабатываться как код внутри тега < a >. Посмотрел на итоговый html - все символы открывающей и закрывающей скобок в добавленной "обёртке" заменены на их HTML-коды.
Похоже на то, что это дело где-то прогоняется через фильтр ввода, потому что когда попробовал поменять в функции theme_menu_item_link - primary и secondary links, которые вызываются из темы напрямую, отобразились нормально.
Теперь загвоздка в следующем: как можно изменить фильтр ввода для не-php блоков (тех, которые предоставляются модулями)? Тут уж сам не смог найти - как ни искал.
Ночь почти не спал... зато получилось.
Сделал по аналогии с этим (вместо вызова функции menu_item_link() обращаюсь напрямую к l() ).
Вот код, вставляемый в template.php (для Superfish 6.x-1.3)
function phptemplate_superfish_build($id, $menu, $depth = -1, $trail = NULL) {
$output = '';
foreach ($menu as $menu_item) {
$mlid = $menu_item['link']['mlid'];
if ($menu_item['link']['hidden'] == 0) {
if ($trail && in_array($mlid, $trail)) {
$class = ' active-trail';
}
// Wrap necessary span code around anchor text.
$menu_item['link']['title'] = '<span class="back"><span class="hover"></span></span><span class="text">' . check_plain($menu_item['link']['title']) . '</span><span class="front"></span>';
// Define $menu_item['link'] array as that which contains HTML code.
$menu_item['link']['html'] = TRUE;
if ((!empty($menu_item['link']['has_children'])) && (!empty($menu_item['below'])) && $depth != 0) {
$children = theme('superfish_build', $id, $menu_item['below'], $depth, $trail);
$parent_class = $children ? 'menuparent ' : '';
$output .= '<li id="menu-'. $mlid .'-'. $id .'"';
if (!empty($parent_class) || !empty($class)) {
$output .= ' class="'. $parent_class . $class .'"';
}
/*
Generate menu link using core l() function directly instead of
theme('menu_item_link', $menu_item['link']) to prevent converting
"<" and ">" characters to their HTML code.
*/
$output .= '>'. l($menu_item['link']['title'], $menu_item['link']['href'], $menu_item['link']);
if ($menu_item['link']['depth'] <= $depth || $depth == -1) {
if ($children) {
$output .= "<ul>\n $children \n</ul>\n";
}
}
$output .= "</li>\n";
}
else {
$output .= '<li id="menu-'. $mlid .'-'. $id .'"';
if (!empty($class)) {
$output .= ' class="'. $class .'"';
}
// The same replacing with l() function one more time.
$output .= '>'. l($menu_item['link']['title'], $menu_item['link']['href'], $menu_item['link']) .'</li>'."\n";
}
}
}
return $output;
}
P.S.: Похоже, что за эти 2 дня я освоил столько инфы, сколько, наверное, за последние полгода не перерабатывал. Надеюсь, мой опыт пригодится.
P.P.S.: указания на кривость кода приветствуются! Попутный вопрос: в чём разница в перекрывании функции через phptemplate_функция и МояТема_функция?
О, спасибо, что расписал весь процесс познания, понял теперь что такое хуки и зачем они нужны. Об этом почему-то никто нигде не пишет.
Благодаря тому, что я не забил на полурешённую проблему, и идентичную issue [##741528]открыл к модулю на друпал.орге[/##], теперь надобность в этом хуке отпала: автор сделал интерфейс к этому хуку, я подправил кой-какой баг, и в версии 1.6 модуль уже может вставлять кастомный код "из коробки".
Можно сказать, что это какой-никакой, но мой первый contribution.
P.S.: Вообще, автор молодец. После того, как я обратил его внимание на решение моей частной проблемы, он сам в новой версии не только закопипастил решение, но и добавил несколько других фич, имеющих отношение к темизации: зебра, первый/последний, id...