It's hook_link_alter over jQuery or CSS alone

05 Jan in development, drupal, module, php

Last year I would have tried to approach this problem with some kind of image/text replacement... This year it's a whole new ballgame. The Drupal theming layer is like an onion and I continue to pull back the outer pieces and get to better and better stuff. Maybe it is more like a Parfait (thanks Donkey from Shrek) ;)

So here's what I wanted to do. Drupal gives us a teaser output with comment links.

3 comments | 2 new comments

Great, awesome, cool... great to have, now I want more... I want an image to replace the word "comments". I'm not going to rely on css alone... I'm not going to rely on some jQuery (which I love)... I'm going to use hook_link_alter and get it done in the code.

I had a starting point that looks like this...

before.png

I am completely familiar with hook_form_alter and have used and abused it to the fullest. This time I know that hook was not going to work, I needed something else. I started looking at the comment module and found the comment_link function. To my surprise it looked a little similar to when I have worked with form_alter. The 'array' looked like something I could work with...

        $all = comment_num_all($node->nid);

        if ($all) {
          $links['comment_comments'] = array(
            'title' => format_plural($all, '1 comment', '@count comments'),
            'href' => "node/$node->nid",
            'attributes' => array('title' => t('Jump to the first comment of this posting.')),
            'fragment' => 'comments'
          );

          $new = comment_num_new($node->nid);

          if ($new) {
            $links['comment_new_comments'] = array(
              'title' => format_plural($new, '1 new comment', '@count new comments'),
              'href' => "node/$node->nid",
              'query' => comment_new_page_count($all, $new, $node),
              'attributes' => array('title' => t('Jump to the first new comment of this posting.')),
              'fragment' => 'new'
            );
          }
        }
        else {
          if ($node->comment == COMMENT_NODE_READ_WRITE) {
            if (user_access('post comments')) {
              $links['comment_add'] = array(
                'title' => t('Add new comment'),
                'href' => "comment/reply/$node->nid",
                'attributes' => array('title' => t('Add a new comment to this page.')),
                'fragment' => 'comment-form'
              );
            }
            else {
              $links['comment_forbidden']['title'] = theme('comment_post_forbidden', $node);

and because it was part of the link function I decided to use hook_link_alter and see what happened.

At Do It With Drupal, over lunch I was talking with two programmers. Very cool guys who remarked about the ability to pass with reference. When I looked closely at the hook_link_alter

function hook_link_alter(&$links, $node) {
  foreach ($links as $module => $link) {
    if (strstr($module, 'taxonomy_term')) {
      // Link back to the forum and not the taxonomy term page
      $links[$module]['href'] = str_replace('taxonomy/term', 'forum', $link['href']);
    }
  }
}

I noticed that the links were being passed with the '&', which I know understood to mean that I didn't have to end the function with any type of 'return' statement. That all of the logic and goodness I needed form the links would stay in tack, I should be able to find the parts I needed, in the array, that would create the output I wanted.

So what do I want.
bubbles.png

I need to:
A -> find the comments 'word' in the array and change it with an image.
B -> include in the array that HTML is allowed (so I can use an image).
C -> retain the number in front of the bubble (was the word comment).

o.k., if you are a programmer, you are a Drupal guru, all of this seems pretty basic, but for me, using the Devel module, and inside of the hook_link_later using dsm($links) to find/access my array was totally awesome. I was able to find the arrays I needed (similar to when I do it with forms) and make my changes. So, if you are a guru don't laugh, if you aren't hopefully this is not only right, but it helps you down the road. Here's my code...

function NAMEOFMYTHEME_link_alter(&$links, $node) {
$pathhere = drupal_get_path('module','wsotheme');
$cool = '<img src="'.$pathhere.'/comment2.png" height="16" width="17"/>';
        //drupal_set_message('' . print_r($links, TRUE) . '');
        //dsm($links);

        $all = comment_num_all($node->nid);
$new = comment_num_new($node->nid);

if ($links['comment_comments']['title']) {
$com_comts = $all . ' ' . $cool;
$links['comment_comments']['html'] = TRUE;
$links['comment_comments']['title'] = $com_comts;
}
if ($links['comment_new_comments']['title']) {
$comts_new = $new .' new '. $cool;
$links['comment_new_comments']['html'] = TRUE;
$links['comment_new_comments']['title'] = $comts_new;
}
}

A -> I grabbed the array where "comments" was included from comment_link, then created a variable with my image.
B -> I added the 'html' = TRUE to the array to allow the tag to be included in the link output.
C -> I copyed/reused the $all and $new variables (placed them here to use) to make sure I was getting a count.

After some adjustments and some time to debug I ended up with the code above.
Some of the links that provided me some insight and direction, might also help someone else out there include...

http://www.kinetasystems.com/blog/theming-the-links-variable-in-drupal-n...
http://agaric.com/note/remove-add-comment-links-from-teasers
http://drupal.org/node/551180#comment-1933852

I am happy with the results, and looking forward to using more hook_link_alters when ever I can :); however my discovery is not without some questions. After I got it working... I started thinking...

1. What is...

foreach ($links as $module => $link)

do I need it?

2. Do I really need to re-declare $new and $all?

3. Did I miss anything important?

Feel free to clue me in if you have any thoughts.

Comments

Does this go in template,php

I've been trying to sort this out for ages but I haven't got your example working yet. Does the hook_link_alter() go in template.php of your theme? I've read elsewhere that you have to write a custom module to implement hook_form_alter, or use function _phptemplate_variables($hook, $vars = array()) in the theme's template.php and catch the form_alter hook in there. Or was there something else I missed?

I have stuck to the pattern

I have stuck to the pattern that "hook_" require a module, and "theme_" can live in template.php. There are some cases, where the site has some pre-processing or other theme overrides, that need to stay with the site... i.e. if I change themes, the node title for the content type story, always get's preprocessed and is appended with a date... in this case, I still like to use a module, so it's "independent" of the theme. As usual, there are dozens of ways to do the same thing, that's just how I have been doing it :)

vibram five fingers five finger shoes

vibram five fingers are comfortable and fashionable five finger shoes.There are broad range of colors and styles vibram five fingers sale for you.

This is interesting

This is interesting indeed!! http://www.tottini.com

Post new comment