In my page.tpl.php I have my primary links being put into an unorded list. What I would like to do is add a SPAN tag inside the A tag around the text for each link; this way I have another place to hook in CSS styles.

I believe that this could be done by hacking a function in the PHPTemplate engine, but I am not sure what function or how to write the PHP code to make it work properly.

If there is another way to do this without hacking or changing the code of the PHPTemplate engine that would be an even better solution for me.

This is what my current page.tpl.php consists of for generating the primary links unordered list:

<!-- START Main Navigation -->
    <?php if(is_array($primary_links)): ?>
        <ul class="noPrint" id="mainNavigation">
            <?php foreach ($primary_links as $link): ?>
                <li><span><?php print $link ?></span></li>
            <?php endforeach; ?>
        </ul>
    <?php endif; ?>
<!-- END Main Navigation -->

Currently I have the A tag contained in the SPAN tag, I would like to switch this around so the XHTML output would be like this:

<ul class="noPrint" id="mainNavigation">
    <li><a href=""><span>Home</span></a></li>
    <li><a href="/services" class="active"><span>Services</span></a></li>
</ul>

I am using background images to create a tab-style primary links navigation and I would like the color of the tab to be different if th user is on that page; for example in the above code the main color for tabs is blue, so 'home' would have a blue colored tab. Since the user is on the services page (the A tag for Services has the active class) the 'services' tab would be say purple. I need two places to hook CSS styles for my top rounded corner images, the A tag would be one, and I need another, thats why I wanted to add-in a SPAN tag within the A tag.

Comments

factoryjoe’s picture

There's always more than one way to skin a cat, as they say, and the same is true with your needs.

I don't know off-hand how to change the content of the $link function, though I'm sure it can be done.

What I've done is somewhat different. I've created classes that apply to the body tag of every page and then make my page and section styles happen from there on down... for example body.about or body.admin.

You can grab the code for this in the CivicSpace theme. Let me know if you have any questions.

eferraiuolo’s picture

I see what your getting at and your idea behind the site sections, I looked at the CVS module sections, but I am after something a little different.

I simply need a way to add a nested XHTML element within the A element, like a span, to give me one more level of hooking for the style sheet. I am looking for a way, hopfully contained in the theme itself (no core hacking) using override functions to get the output I disire. Any suggestion on how to override the output of PHPTemplates Primary_Links would be what I am after.

Thanks for the follow-up,
Eric

factoryjoe’s picture

Status: Active » Postponed

So the short answer is that it's not readily possible to do what you want. This is the conversation I had with Steven:

factoryjoe: do you guys know how to pass HTML to the l() function?
for example if i want to output title?
how do i get the span in there?

killes
http://drupaldocs.org/api/head/function/l
l($text, $path, $attributes = array(), $query = NULL, $fragment = NULL, $absolute = FALSE, $html = FALSE)

factoryjoe:
can it be done @ the theme level?

UnConeD
factoryjoe: you need to pass $html as TRUE

factoryjoe:
then where does the HTML get put?
this is what i'm trying to answer: http://drupal.org/node/26846

UnConeD
in $text
the $html parameter decides whether what you pass is text or html
the reason it is like this is because it catches a lot of possible XSS issues
if you, then you're responsible for calling check_plain() on user-submitted data
*if you do

factoryjoe:
i c
so what's the answer to that person's question?

UnConeD
everything above is
pass $html = false to l(), wrap user-defined data in check_plain() in the $text parameter as this is no longer done for you, and add all the HTML you want

factoryjoe:
but how do you override <li><span><?php print $link ?></span></li>?

UnConeD
by overriding the themable function which generates $link

factoryjoe:
hmm
now i have to find that
isn't that a phptemplate function?

UnConeD
you want to add spans to primary links?

factoryjoe: apparently
didn't you read that guy's post?

UnConeD
no i'm sort of busy
this is what I use

function phptemplate_menu_item_link($item, $link_item) {
/* added magic spans for funky tabs */
return l('<span class="a"><span class="b">'. check_plain($item['title']) .'</span></span>', $link_item['path'], array_key_exists('description', $item) ? array('title' => $items['description']) : array(), NULL, NULL, FALSE, TRUE);
}

factoryjoe: ah ok

UnConeD
or maybe those are the regular tabs

factoryjoe:
yeah
those are your local tasks i think
not primary_links
i mean, the whole loop would need to be recreated, wouldn't it?
to break out the values contained in $link?

UnConeD
btw it seems those primary/secondary links are oddly enough generated in theme.inc's theme_get_settings
which would mean it's not themable
but i remember adrian saying he was rewriting some part of the links handling
in any case, this should really be a themable function, and the links should be passed as an array to the theme engine, not as prebaked links

eferraiuolo’s picture

Status: Postponed » Active

This is also another person trying to do exactly what I am attempting to do:
http://drupal.org/node/24827

Maybe if we can't get in and theme whats contained within the anchor tags in the primary links, we can assign the class="active" attribute to the LI tag contains the actual link which links to the same page the user is on (i.e. the page and link are "active"). The XHTML code presented in http://drupal.org/node/24827 would work perfect for what I am after. I was looking at this issue from two directions:

  1. Add an XHTML tag within the anchor element to allow from an additional level of CSS style hooking.
  2. Or tell the LI tag that contains the "active" anchor tag that it's also "active"

Either approach would work and make Sliding-Doors tabbing (http://www.alistapart.com/articles/slidingdoors2/) possible in the Primary Links. Say the user is on the Home page for the site, the Home "tab" in the primary links would contain the class="active" attribute on the LI and A elements allowing for that "tab" to have a different appearance than the other tabbed primary links.

Is this approach (adding the class="active" to the LI element that contains the "active" A element) possible with the current state of drupal and PHPTemplate?

micha_1977’s picture

yes its possible, and as said above one need to reproduce existing functions

i used another technique for my links, but needed the "active" info and special html layout too
see www.langmi.de (the tabbed primary links)

my code for this in the phptemplate (i deleted almost all nonrelevant functions)

function _phptemplate_variables($hook, $vars) {
/***********************************
 * HOOK PAGE
 * - frontpage
 *   - save 'which page' to the $vars 
 *   - override template file depending on page
 *   - add special stylesheets
 * - get the right is_front info, drupal core won't look at path aliases
 * - save some user rights info to the $vars
 *   - make customized primary links
 */
  if ($hook == 'page') {

    /**
      * FRONTPAGE
      */
    if ($vars['is_front']) {

      /**
        * save page info
        */
      $vars['my_page_type'] = 'front';
      
      // set frontpage layout 
      $theme = 'candy';
      $style = 'front';
      $page_type = 'frontpage';
      $vars = my_set_theme($theme, $page_type, $vars);
      $vars = my_add_style($theme, $style, $vars);

      /**
        * customized primary links
        * - see http://www.stunicholls.myby.co.uk/menus/snazzymenu2.html for more info on this link design
        */
      foreach (array('primary') as $type) {

        //Get the data to populate the textfields, if the variable is not an array .. try to parse the old-style link format.      
        $value = variable_get('phptemplate_' . $type . '_links', array());

        //Get the amount of links to show, possibly expanding if there are more links defined than the count specifies

        $count = variable_get('phptemplate_' . $type . '_link_count', 5);
        $count = ($count > sizeof($value['link'])) ? $count : sizeof($value['link']);

        if (theme_get_setting('toggle_' . $type . '_links')) {
          for ($i =0; $i < $count; $i++) {
            unset($attributes);
            if (!empty($value['text'][$i])) {
              if (!empty($value['description'][$i])) {
                $attributes['title'] = $value['description'][$i];
              }
              $text = $value['text'][$i];
              $link = $value['link'][$i];            
              // the original from phptemplate.engine changed to catch the produced links
              if (substr($link, 0, 4) == 'http') {
                $_templink = '<a href="'. $link .'"'. drupal_attributes($attributes) .'>'. $text .'</a>';
              }
              else {
              $_templink = l($text, $link, $attributes);
              }
              // reproduced "l" function from includes/common.inc to get the active link, only for "primary links"
              // classes are set acccording to my style.css, $classtext is needed for additional css logik
              if ($type == 'primary') {
                if (drupal_get_normal_path($link) == $_GET['q']) {
                  isset($attributes['class']) ? $attributes['class'] .= ' active' : $attributes['class'] = 'active';
                  $classtext = 'darkblue';
                }
                else {  
                  isset($attributes['class']) ? $attributes['class'] .= ' notactive' : $attributes['class'] = 'notactive';
                  $classtext = 'lightblue';
                }
                $_templink = '<a href="'. $link .'" class="menu"><b class="snazzy"><span class="boxcontent '. $attributes['class'] .'">'. $text .'</span><b class="b4 '.$classtext.'"></b><b class="b3 '.$classtext.'"></b><b class="b2 '.$classtext.'"></b><b class="b1"></b></b></a>';
              }
              $links[$type][] = $_templink;              
            }
          }
        }
        $vars['customized_type1_links']= $links['primary'];
      }
    }
  }

  /**
    * set front + site-mission according to path alias
    */
  if (drupal_get_path_alias($_GET['q']) == variable_get('site_frontpage', drupal_get_path_alias('node'))) {
    $vars['mission'] = theme_get_setting('mission');    
    $vars['is_front'] = true;
  }

  
  // calling function expects an array
  if (empty($vars)) { 
    $vars = array();
  }
  return $vars;
}
micha_1977’s picture

its not inside the phptemplate, but inside the template.php :-)

eferraiuolo’s picture

I am having trouble getting my template.php file to work. Through trial and error by editing the phptemplate.engine directly the Primary Links are being passed to the "l" function when executing this IF statement in the phptemplate.engine file:

if (theme_get_setting('toggle_' . $type . '_links')) {
      for ($i =0; $i < $count; $i++) {
        unset($attributes);
        if (!empty($value['text'][$i])) {
          if (!empty($value['description'][$i])) {
            $attributes['title'] = $value['description'][$i];
          }
          $text = $value['text'][$i];
          $link = $value['link'][$i];
          if (substr($link, 0, 4) == 'http') {
            $links[$type][] = '<a href="'. $link .'"'. drupal_attributes($attributes) .'>'. $text .'</a>';
	    }
          else {
            $links[$type][] = l($text, $link, $attributes);
          }
        }
      }
    }
  }

Like you did I will need to reporduce and change the "l" function. I know the exact part I need to modify, but I can't seem to get it working correctly in template.php. I am unsure how to override the functions correctly (even after reading the handbook entries and searching). I noticed that you extracted the functionality of the "l" function and included it in your template.php, I would also need to do this but eventually I need to end result to be this:

$links[$type][] =  '<a href="'. check_url(url($path, $query, $fragment, $absolute)) .'"'. drupal_attributes($attributes) .'><span>'. ($html ? $text : check_plain($text)) .'</span></a>';

I added a SPAN tag around the text part.

I tried using your code for my template.php but couldn't get it working right even after modifying it. So I need some help on how to implement theme function overrides.

Thanks for the help and showing my the path ;)
Eric

eferraiuolo’s picture

I have finally figured out the solution. I have posted two working solutions that use just a couple lines of PHP code in the page.tpl.php:
http://drupal.org/node/24827#comment-36781

I appricate the feedback I got from everyone, all the comments on both of these related issues have led me to a simple yet effective solution for creating tab-styled navigation with Primary Links.

morbus iff’s picture

Status: Active » Fixed

The original submitter asked for support, got it, and settled on a solution. Closing.

Anonymous’s picture

Status: Fixed » Closed (fixed)