I have copied some code from Bartik and simplified to the following:

<div id="menu">
  <?php echo theme('links__system_main_menu', array('links' => $main_menu)); ?>
</div>

This generates the expected HTML list - however I now need to override some of that HTML so I much prefer having 100% control of the output. I'm not sure I understand how or what to override, having read the following:

http://api.drupal.org/api/drupal/includes--theme.inc/function/theme/7

1. How do I create a custom template for the "main menu" only? I assume I need a template file named something like: links__main_menu.tpl.php

2. Secondly, this main menu actually links to sub-domains (which I entered as external URI). These menus work, but obviously no page data is loaded according to sub-domain (something I will figure out later and hack in) and the menu items don't change "active" status. So to solve this issue I wonder if it's possible to implement a function hook and check the sub-domain in the hook and set the proper flag accordingly. I am guessing I could do this in the template itself but to keep things clean I'd rather use a template for rendering and a hook_x() for activating the menu item based on the sub-domain selected.

Cheers,
Alex

Comments

betarobot’s picture

A very different approach to your second question: came up with it when I needed a slight color modifications for subdomain colors/style (served from single codebase). Add a server name as class to your body classes (in template.php):

function yourtheme_preprocess_html(&$variables) {
  // Add a class that gives us a domain/server name. A very handy solution in altering domain based style.
  $variables['classes_array'][] = str_replace('.', '-', $_SERVER['SERVER_NAME']);
}

Then you can use a CSS something like that:

a.active, 
.subdomain-name .menu-111 a
{
color: #333;
}

Might be handy in other situations as well of course.

GarbageXAY1979’s picture

So your basically adding the sub-domain as a class to all elements which might be styled differently per sub-domain? That could be a useful of changing the background :)

Still confused over the template file naming convention though.

I'm asking the theme() funciton to load a theme function or a template with the name: links__system_main_menu

links__xxx as I understand allows Drupal to fall back to a default theme as opposed to an override I may provide. How do I name my template if my theme is called 'basic'

links__basic_main_menu???

Where does the "main_menu" come from? How would I use/call a template file called main-menu.tpl.php


EDIT | I am starting to think Drupal does not support template overrides for *everything* especially menus - seems function hooks can be provided but not templates???

betarobot’s picture

Nonono, of course I don't add sub-domain class to all elements with this code. Only to body tag, i.e.

<body class="... sub-domain ...">
  ...
    <li class="active">
  ...
</body>

I'm not quite sure yet if there is a .tpl.php for menus in D7 at all. For overriding menus I use preprocess or override functions in template.php:
http://api.drupal.org/api/drupal/includes--menu.inc/group/menu/7

GarbageXAY1979’s picture

Digging through the theme.inc file and reading the API on various theme_xxx() functions it seems to me that template override is not a default behavior, at least for menus. Seems I must use a function instead...BAH

Cheers,
Alex

roger.ajith’s picture

You can customize your theme's some functionality in template.php
Some default functions are there in drupal. If you print the function argument, you will get full page details by array format.
You customize external module field also.
for eg:
We can change the user login text-field label if you written code for this in your theme.

bitspike’s picture

Hi alex,
I am new in the whole durpal thing and I had the same question few days back. Here is the solution I found. Please correct me if I got something wrong.

HYPOTHESIS:

  1. I want to override the links__system_main_menu theme
  2. I want to do it through a custom module called mymenu

SOLUTION:

  1. Create the module folder for the module mymenu and all the necessary files in it.
  2. Implement the hook_theme as follows. Probably you will do that in the mymenu.tpl.php:
    function mymenu_theme($existing, $type, $theme, $path) {
      return array(
        'links__system_main_menu' => array( //Override the main menu theme
          'variables' => array(),
          'template' => 'links__system_main_menu', //Note that the template name defined here has no .tpl.php extension.
        ),
      );
    }
    
  3. Create your custom template for your links in the module folder. In our case the template file will be called links__system_main_menu. Here is a sample template (do not use on a live site.)
    <div>
      <ul>
      <?php
        foreach ($links as $link) {
          echo '<li>'.l($link['title'], $link['path'], $link).'</li>';
        }
      ?>
      </ul>
    </div>
    
  4. Activate your module, clear the cache and check the results. Remember to clear your cache every time you make changes to your module.

NOTES:

  1. In your implementation of hook_theme you may use the function key instead of the template one and write a custom function to return your HTML. e.g.: 'function' => 'your_function_callback'
  2. You can probably do all the things above, in the scope of a theme without having to implement a new module, but I don't know the way to do it yet.
  3. For the other newcomers to drupal world (like me) out there, I would like to note that hook_theme(http://api.drupal.org/api/drupal/modules--system--system.api.php/functio...) is used to register a theme while theme(http://api.drupal.org/api/drupal/includes--theme.inc/function/theme/7) is used to use a registered theme.
bitspike’s picture

Hi, I am reporting back from the Drupal documentation trenches. ;-)
I found a more elegant solution to your first problem, here it is...

HYPOTHESIS:

  1. I want to override the links__system_main_menu theme
  2. I want to do it through a custom theme called mytheme

SOLUTION:

  1. Create the theme folder for the theme mytheme and all the necessary files in it. And make it default theme.
  2. Implement the hook_links__system_main_menu as follows. Probably you will do that in the template.php file in your theme folder.:
    function mytheme_links__system_main_menu($variables) {
      $html = "<div>\n";
      $html .= "  <ul>\n";  
      foreach ($variables['links'] as $link) {
        $html .= "<li>".l($link['title'], $link['path'], $link)."</li>";
      }
      $html .= "  </ul>\n";
      $html .= "</div>\n";
    
      return $html;
    }
    

NOTES:

  1. It is possible to implement your theme in a template file. To do that you have to implement the hook_theme hook in the teplate.php (see my previous comment for sample code on hook_theme implementation).
pavelsof’s picture

This is a very nice solution, exactly what I needed. Just a small change: $link['path'] should be replaced with $link['href'].

Cheers,
Pavel

quiptime’s picture

function MYTHEME_links__system_main_menu(&$vars) {
  if (drupal_is_front_page()) {
    return '';
  }

  return theme('links', $vars);
}
ancubero’s picture

Hello.

I'm using Drupal 7 and I trying to override the links__system_main_menu function, and I already make everything on this page but the menu is not showing at all.

here is the code I am using in the template.php

/**Override Menu theme */
function Vida_links__system_main_menu(array $variables) {
       $html = "  <ul class=\"menu\">\n"; 
	
	foreach ($variables['links'] as $link) {
		$html .= "<li>".l($link['title'], $link['path'], $link)."</li>\n";
	}

	$html .= "  </ul>\n";

	
	return $html;
}

and this is how I try to call it from the page.tpl.php

print theme('Vida_links__system_main_menu', array('links' => $main_menu, 'attributes' => array('id' => 'main-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Main menu')));

Can some one help me please.

markovica’s picture

Not 100% sure, but this should work

<?php print theme('links__system_main_menu', array('links' => $main_menu, 'attributes' => array('id' => 'main-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Main menu'))); ?>
drupalshrek’s picture

I don't think you should include the prefix of your theme, i.e. you should call theme('links__system_main_menu' ...) and not theme('Vida_links__system_main_menu'...). When you are using the theme() function, you are proposing to Drupal a particular type of function, and asking Drupal to look through the possible functions of that name; this means that someone else can overrride even your function if they want to get ahead of you in the theme function chain. So, theme() looks for functions in an order like:

  1. YOURTHEME_links__system_main_menu
  2. phptemplate_links__system_main_menu
  3. theme_links__system_main_menu

When it doesn't find one, it goes on and looks for the next in the list until it finds one which matches. Hence, you should not include your template prefix.

If you include your template prefix, then you should just call your function directly, e.g. print Vida_links__system_main_menu(...). This though is considered bad theming since you should never call your function directly, but always use the theme function to allow Drupal to go through the list of possible theme implementations in order.

I definitely recommend using the Devel Themer module, which always shows you the full list of possible called functions and called templates, together with which function/template is actually being used.

So I think your call should look like as follows:

print theme('links__system_main_menu', array('links' => $main_menu, 'attributes' => array('id' => 'main-menu', 'class' => array('links', 'inline', 'clearfix')), 'heading' => t('Main menu'))); 

drupalshrek

luisnicg’s picture

I've read all the comments. And after that, I have succeeded.

template.php

function yourtheme_preprocess_page(&$variables){
	// Primary nav.
	$variables['primary_nav'] = FALSE;
	if ($variables['main_menu']) {
		// Build links.
		$variables['primary_nav'] = theme('links__system_main_menu', array('links' => $variables['main_menu']));
	}
}

continue in the same file

function yourtheme_links__system_main_menu(&$variables) {
  $links = '<ul>';
  foreach ($variables['links'] as $link) {
    $links .= "<li>".l($link['title'], $link['href'], $link)."</li><li class='sep'></li>";
  }
 $links .= '</ul>';
 return $links;
}

page.tpl.php or any order

...
<?php print render($primary_nav); ?>
...
jacofda’s picture

thanks for sharing

<?php
function yourtheme_preprocess_page(&$variables){
    // Primary nav.
    $variables['primary_nav'] = FALSE;
    if ($variables['main_menu']) {
        // Build links.
        $variables['primary_nav'] = theme('links__system_main_menu', array('links' => $variables['main_menu']));
    }
}
function yourtheme_links__system_main_menu(&$variables) {
  $links = '<ul>';
  foreach ($variables['links'] as $link) {
    $links .= "<li>".l($link['title'], $link['href'], $link)."</li><li class='sep'></li>";
  }
 $links .= '</ul>';
 return $links;
}
?>
jeromewiley’s picture

This works for me to the extent that the functions are being called and execute (verified using dpm(), then reloading page), but the array containing the main menu is then apparently re-worked further down the road and appears as before (does not contain the custom stuff I added.) In the meantime, I found a different way of adding a NAV element:

function MYTHEME_menu_tree(&$variables) {
  return '<nav><ul class="menu">' . $variables['tree'] . '</ul></nav>';
}

I found this at: Joshua Powell GitHub account