Нашёл от старого проекта (2008-й год) файлы. Переопределял там меню. Структура:
<?php defined('_JEXEC') or die('Restricted access');
jimport('joomla.base.tree');
jimport('joomla.utilities.simplexml');
class WebmodMainMenuHelper
{
function WebbuildXML($params)
{
$menu = new WebJMenuTree($params);
$items = &JSite::getMenu();
// Get Menu Items
$rows = $items->getItems('menutype', $params->get('menutype'));
$maxdepth = $params->get('maxdepth',10);
// Build Menu Tree root down (orphan proof - child might have lower id than parent)
$user =& JFactory::getUser();
$ids = array();
$ids[0] = true;
$last = null;
$unresolved = array();
// pop the first item until the array is empty if there is any item
if ( is_array($rows)) {
while (count($rows) && !is_null($row = array_shift($rows)))
{
if (array_key_exists($row->parent, $ids)) {
$row->ionly = $params->get('menu_images_link');
$menu->addNode($params, $row);
// record loaded parents
$ids[$row->id] = true;
} else {
// no parent yet so push item to back of list
// SAM: But if the key isn't in the list and we dont _add_ this is infinite, so check the unresolved queue
if(!array_key_exists($row->id, $unresolved) || $unresolved[$row->id] < $maxdepth) {
array_push($rows, $row);
// so let us do max $maxdepth passes
// TODO: Put a time check in this loop in case we get too close to the PHP timeout
if(!isset($unresolved[$row->id])) $unresolved[$row->id] = 1;
else $unresolved[$row->id]++;
}
}
}
}
return $menu->toXML();
}
function &getXML($type, &$params, $decorator)
{
static $xmls;
if (!isset($xmls[$type])) {
$cache =& JFactory::getCache('mod_mainmenu');
$string = $cache->call(array('WebmodMainMenuHelper', 'WebbuildXML'), $params);
$xmls[$type] = $string;
}
// Get document
$xml = JFactory::getXMLParser('Simple');
$xml->loadString($xmls[$type]);
$doc = &$xml->document;
$menu = &JSite::getMenu();
$active = $menu->getActive();
$start = $params->get('startLevel');
$end = $params->get('endLevel');
$sChild = $params->get('showAllChildren');
$path = array();
// Get subtree
if ($start)
{
$found = false;
$root = true;
if(!isset($active)){
$doc = false;
}
else{
$path = $active->tree;
for ($i=0,$n=count($path);$i<$n;$i++)
{
foreach ($doc->children() as $child)
{
if ($child->attributes('id') == $path[$i]) {
$doc = &$child->ul[0];
$root = false;
break;
}
}
if ($i == $start-1) {
$found = true;
break;
}
}
if ((!is_a($doc, 'JSimpleXMLElement')) || (!$found) || ($root)) {
$doc = false;
}
}
}
if ($doc && is_callable($decorator)) {
$doc->map($decorator, array('end'=>$end, 'children'=>$sChild));
}
return $doc;
}
function render(&$params, $callback)
{
switch ( $params->get( 'menu_style', 'list' ) )
{
default :
// Include the new menu class
$xml = WebmodMainMenuHelper::getXML($params->get('menutype'), $params, $callback);
if ($xml) {
$class = $params->get('class_sfx');
$xml->addAttribute('class', 'menu'.$class);
if ($tagId = $params->get('tag_id')) {
$xml->addAttribute('id', $tagId);
}
$result = JFilterOutput::ampReplace($xml->toString((bool)$params->get('show_whitespace')));
$result = str_replace(array('<ul/>', '<ul />'), '', $result);
echo $result;
}
break;
}
}
}
class WebJMenuTree extends JTree
{
/**
* Node/Id Hash for quickly handling node additions to the tree.
*/
var $_nodeHash = array();
/**
* Menu parameters
*/
var $_params = null;
/**
* Menu parameters
*/
var $_buffer = null;
function __construct(&$params)
{
$this->_params =& $params;
$this->_root = new JMenuNode(0, 'ROOT');
$this->_nodeHash[0] =& $this->_root;
$this->_current =& $this->_root;
$this->_ment = & $params->get( 'menu_style' );
if (
($this->_ment == "horiz_flat") and
(
stristr($_SERVER['HTTP_USER_AGENT'], 'MSIE 6.0') or
stristr($_SERVER['HTTP_USER_AGENT'], 'MSIE 7.0')
)
)
{$m_style = 'm_table';}
else {$m_style = 'm_list';}
if (
($this->_ment == "horiz_flat") and
(
stristr($_SERVER['HTTP_USER_AGENT'], 'MSIE 6.0') or
stristr($_SERVER['HTTP_USER_AGENT'], 'MSIE 7.0')
)
)
{$m_style = 'm_table';}
if ($this->_ment == "list_flat")
{$m_style = 'm_link';}
if ($this->_ment == "list")
{$m_style = 'm_list';}
$this->_m_style = $m_style;
}
function addNode(&$params, $item)
{
// Get menu item data
$data = $this->_getItemData($params, $item);
// Create the node and add it
$node = new JMenuNode($item->id, $item->name, $item->access, $data);
if (isset($item->mid)) {
$nid = $item->mid;
} else {
$nid = $item->id;
}
$this->_nodeHash[$nid] =& $node;
$this->_current =& $this->_nodeHash[$item->parent];
if ($item->type == 'menulink' && !empty($item->query['Itemid'])) {
$node->mid = $item->query['Itemid'];
}
if ($this->_current) {
$this->addChild($node, true);
} else {
// sanity check
JError::raiseError( 500, 'Orphan Error. Could not find parent for Item '.$item->id );
}
}
function toXML()
{
// Initialize variables
$this->_current =& $this->_root;
// Recurse through children if they exist
while ($this->_current->hasChildren())
{
if ( $this->_m_style == "m_table") {
$this->_buffer .= '<table><tr>';
foreach ($this->_current->getChildren() as $child)
{
$this->_current = & $child;
$this->_getLevelXML(0);
}
$this->_buffer .= '</tr></table>';
};
if ( $this->_m_style == "m_list") {
$this->_buffer .= '<ul>';
foreach ($this->_current->getChildren() as $child)
{
$this->_current = & $child;
$this->_getLevelXML(0);
}
$this->_buffer .= '</ul>';
};
if ( $this->_m_style == "m_link") {
$this->_buffer .= '<div>';
foreach ($this->_current->getChildren() as $child)
{
$this->_current = & $child;
$this->_getLevelXML(0);
}
$this->_buffer .= '</div>';
};
}
return $this->_buffer;
}
function _getLevelXML($depth)
{
$depth++;
// Start the item
$rel = (!empty($this->_current->mid))? ' rel="'.$this->_current->mid.'"' : '';
if (( $this->_m_style == "m_table") and ($depth==1)) {
$this->_buffer .= '<td access="'.$this->_current->access.'" level="'.$depth.'" id="'.$this->_current->id.'"'.$rel.'>';};
if ($this->_m_style == "m_list") {
$this->_buffer .= '<li access="'.$this->_current->access.'" level="'.$depth.'" id="'.$this->_current->id.'"'.$rel.'>';};
if ($this->_m_style == "m_link") {
$this->_buffer .= '';};
// Append item data
$this->_buffer .= $this->_current->link;
foreach ($this->_current->getChildren() as $child)
while ($this->_current->hasChildren())
{
$this->_buffer .= '<ul>';
foreach ($this->_current->getChildren() as $child)
{
$this->_current = & $child;
$this->_getLevelXML($depth);
}
$this->_buffer .= '</ul>';
}
// Finish the item
if (( $this->_m_style == "m_table") and ($depth==1)) {
$this->_buffer .= '</td>';};
if ($this->_m_style == "m_list") {
$this->_buffer .= '</li>';};
if ($this->_m_style == "m_link") {
$this->_buffer .= '';};
}
function do_translit($st) {
$replacement = array(
"й"=>"i","ц"=>"c","у"=>"u","к"=>"k","е"=>"e","н"=>"n",
"г"=>"g","ш"=>"sh","щ"=>"sh","з"=>"z","х"=>"x","ъ"=>"",
"ф"=>"f","ы"=>"i","в"=>"v","а"=>"a","п"=>"p","р"=>"r",
"о"=>"o","л"=>"l","д"=>"d","ж"=>"zh","э"=>"ie","ё"=>"e",
"я"=>"ya","ч"=>"ch","с"=>"c","м"=>"m","и"=>"i","т"=>"t",
"ь"=>"","б"=>"b","ю"=>"yu",
"Й"=>"I","Ц"=>"C","У"=>"U","К"=>"K","Е"=>"E","Н"=>"N",
"Г"=>"G","Ш"=>"SH","Щ"=>"SH","З"=>"Z","Х"=>"X","Ъ"=>"",
"Ф"=>"F","Ы"=>"I","В"=>"V","А"=>"A","П"=>"P","Р"=>"R",
"О"=>"O","Л"=>"L","Д"=>"D","Ж"=>"ZH","Э"=>"IE","Ё"=>"E",
"Я"=>"YA","Ч"=>"CH","С"=>"C","М"=>"M","И"=>"I","Т"=>"T",
"Ь"=>"","Б"=>"B","Ю"=>"YU",
" "=>"-","№"=>"",","=>"","!"=>"","»"=>"","«"=>"","/"=>"",
);
foreach($replacement as $i=>$u)
{
$st = mb_eregi_replace($i,$u,$st);
}
return $st;
}
function _getItemData(&$params, $item)
{
$data = null;
$tname = array($item->name, $st);
// Menu Link is a special type that is a link to another item
if ($item->type == 'menulink')
{
$menu = &JSite::getMenu();
if ($newItem = $menu->getItem($item->query['Itemid'])) {
$tmp = clone($newItem);
$tmp->name = '<span><![CDATA['.$item->name.']]></span>';
$tmp->mid = $item->id;
$tmp->parent = $item->parent;
} else {
return false;
}
} else {
$tmp = clone($item);
$tmp->name = '<span><![CDATA['.$item->name.']]></span>';
//$tmp->name = '<span class="'.$this->do_translit($item->name).'"><![CDATA['.$item->name.']]></span>';
}
$pos1=mb_strpos($item->name,'::');
if ($pos1>0) {
$name1 = mb_substr($item->name,0,$pos1);
$tmp->name = '<span><![CDATA['.$name1.']]></span>';
$tmp->title = mb_substr($item->name,$pos1+2);}
else { $tmp->title = $item->name;}
$iParams = new JParameter($tmp->params);
if ($params->get('menu_images') && $iParams->get('menu_image') && $iParams->get('menu_image')!= -1) {
switch ($params->get('menu_images_align', 0)){
case 0 :
$imgalign='align="left"';
break;
case 1 :
$imgalign='align="right"';
break;
default :
$imgalign='';
break;
}
$image = '<img src="'.JURI::base(true).'/images/stories/'.$iParams->get('menu_image').'" '.$imgalign.' alt="'.$item->alias.'" />';
if($tmp->ionly){
$tmp->name = null;
}
} else {
$image = null;
}
switch ($tmp->type)
{
case 'separator' :
return '<span class="separator">'.$image.$tmp->name.'</span>';
break;
case 'url' :
if ((strpos($tmp->link, 'index.php?') === 0) && (strpos($tmp->link, 'Itemid=') === false)) {
$tmp->url = $tmp->link.'&Itemid='.$tmp->id;
} else {
$tmp->url = $tmp->link;
}
break;
default :
$router = JSite::getRouter();
$tmp->url = $router->getMode() == JROUTER_MODE_SEF ? 'index.php?Itemid='.$tmp->id : $tmp->link.'&Itemid='.$tmp->id;
break;
}
// Print a link if it exists
if ($tmp->url != null)
{
// Handle SSL links
$iSecure = $iParams->def('secure', 0);
if ($tmp->home == 1) {
$tmp->url = JURI::base();
} elseif (strcasecmp(substr($tmp->url, 0, 4), 'http') && (strpos($tmp->link, 'index.php?')!== false)) {
$tmp->url = JRoute::_($tmp->url, true, $iSecure);
} else {
$tmp->url = str_replace('&', '&', $tmp->url);
}
switch ($tmp->browserNav)
{
default:
case 0:
// _top
$data = '<a class="'.$this->do_translit($item->name).'" title="'.$tmp->title.'" href="'.$tmp->url.'">'.$image.$tmp->name.'</a>';
break;
case 1:
// _blank
$data = '<a title="'.$tmp->title.'" href="'.$tmp->url.'" target="_blank">'.$image.$tmp->name.'</a>';
break;
case 2:
// window.open
$attribs = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,'.$this->_params->get('window_open');
// hrm...this is a bit dickey
$link = str_replace('index.php', 'index2.php', $tmp->url);
$data = '<a title="'.$tmp->title.'" href="'.$link.'" onclick="window.open(this.href,\'targetWindow\',\''.$attribs.'\');return false;">'.$image.$tmp->name.'</a>';
break;
}
} else {
$data = '<a title="'.$tmp->title.'" >'.$image.$tmp->name.'</a>';
}
return $data;
}
}
/**
* Main Menu Tree Node Class.
*
* @package Joomla
* @subpackage Menus
* @since 1.5
*/
class WebJMenuNode extends JNode
{
/**
* Node Title
*/
var $title = null;
/**
* Node Link
*/
var $link = null;
/**
* CSS Class for node
*/
var $class = null;
function __construct($id, $title, $access = null, $link = null, $class = null)
{
$this->id = $id;
$this->title = $title;
$this->access = $access;
$this->link = $link;
$this->class = $class;
}
}
Там много лишнего в файлах, собственные поделки какие-то, выкосите не забудьте.