All I want to do is alter properties of the links displayed in comments. This is very easy to accomplish if you want to alter a node's links, but there doesn't seem to be any equivalent for comments... no hook, nor preprocess function. The only way I can imagine doing it is doing some kind of string replacement trickery inside the comment's template preprocess function, because the links are passed to it as straight markup, rather than an array or something that can be easily modified.

Am I missing something here? Or is there really no way to alter a comment's links?

Comments

blueminds’s picture

Kind of late, but in case any body else would struggle with this issue...

There is no way how to alter comment links through hook, so you need to hack it in HOOK_preprocess_comment() as follows:


function yourmodule_preprocess_comment (&$variables) {
  $comment = $variables['comment'];

  //load links for current comment
  $links = comment_links($comment, FALSE);
  
  //code to alter the links array
  
  //reset the links HTML
  $variables['links'] = theme('links', $links);
}

phKU’s picture

"It's never too late to do well" (translated from a french proverb)

Thanks divamys for your good input. It saved me from patching the "comment.module" as a last resort. It's weird there's still no comment link_alter hook implemented despite the several requests in the forum.

I tried before with no luck to catch the theme_comment call but from there after altering the links, I couldn't redirect the call to the theme engine (D6 dont provide anymore the "_phptemplate_callback" function).

Is there really no other way but to have the comment links rendered twice?

phKU’s picture

Sorry, but at second thought, divamys solution is missing one essential point. The comment_links() function doesn't invoke hook_comment() thus any module action on comments is lost. Even so, it wouldn't be a good idea to pass through all modules comment hook twice.

Therefore, I propose another working option, ugly but simple and efficient in my case: with a couple of lines in template.php (4 in my case), de-render $variables['links'] back to the Drupal standard link array type. Then do any wanted link alteration and finally theme back the link array to $variables['links']. This solution is fast, without any system call but the theme_link function. It even allows to act as well on extra module links.

Hope that will help some :)

dazweeja’s picture

Although it's possible, I'm not sure how often not invoking hook_comment from comment_links would present an issue. Surely only in cases where other modules have added extra links to the links for the comment? For standard comment links, you're only going to override them anyway with whatever solution you come up with (that's the point of this issue, isn't it?). comment_links would seem to be a very inexpensive function - there's only one call to node_load and that's for a node that would already be cached anyway.

On the other hand, if I understand you correctly, you propose to run a function on all links that are themed? When you say "de-render $variables['links'] back to the Drupal standard link array type" what exactly do you mean? Maybe you could post the whole function that you altered here to demonstrate.

Ideally, it would be great to have a comment_link_alter in core wouldn't it ;)

phKU’s picture

In order to simulate a comment_alter hook, I added the following code in phptemplate_preprocess_comment hook:

preg_match_all('|<li class="(.+?)(?: first)?(?: last)?"><a +href="(?:/(\w\w))?/(.*?)(?:\?(.+?))?(?:#(.+?))?"' .
               '(?: +(\w+)="(.*?)")?(?: +(\w+)="(.*?)")?(?: +(\w+)="(.*?)")? *>(.*?)(?:<span class=".*?">.*?</span>)?</a></li>|s',
               $variables['links'], $lines, PREG_SET_ORDER);

$links = array();
$languages = language_list();

foreach($lines as $li) {
  $links[$li[1]] = Array('language' => $languages[$li[2]], 'href' => $li[3], 'query' => $li[4], 'fragment' => $li[5],
                         'attributes' => Array($li[6] => $li[7], $li[8] => $li[9], $li[10] => $li[11]),
                         'title' => $li[12]);

  unset($links[$li[1]]['attributes']['']);  // get ride of any nonexistent attribute
}

< call your comment_alter hook here >

$variables['links'] = preg_replace('|amp;|', '', theme('links', $links, array('class' => 'links inline')));

The last preg_replace '|amp|' is needed to correct any javascript attribute which are html encoded in the theme function (through the drupal_attributes() call).
The main regex may need somehow to be tuned to match some specifics configurations.

I use such comment link alteration for a website (french/german) where I've installed the excellent advanced forum to have the comment links being consistent with the node links.

n.b idea of comment_link_alter hook is a long term ride ;)

v8powerage’s picture

I wanna add another button to links "quick edit" with class='popups', but I don't know how to achieve this

I've been trying change contactlink.module into my needs, but I'm getting error "call to undefined function comment_load" (upon replacing user_load with it):


/**
 * Implementation of hook_link().
 */
function quickedit_link($type, $object = 0, $main = 0) {
  global $user;
  $links = array();
  // Only show link to authenticated users, because user contact
  // is not available to anonymous users.
  if ($user->uid && in_array($type, array('comment')) && ($type != 'node' || variable_get('quickedit_'. $object->type, 1)) && $comment = comment_load(array('cid' => $comment->cid))) {
      $links['quickedit'] = array(
        'title' => t('Quickedit'),
        'href' => "comment/edit/$comment->cid",
        'attributes' => array('title' => t('Quickedit')),
      );
  }
  return $links;
}

/**
 * Implementation of hook_form_alter().
 */
function quickedit_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
    $form['workflow']['quickedit'] = array(
      '#type' => 'radios',
      '#title' => t('Show "Quickedit" link for this content type'),
      '#default_value' => variable_get('quickedit_'. $form['#node_type']->type, 1),
      '#options' => array(t('Disabled'), t('Enabled')),
    );
  }
}

dazweeja’s picture

There is no comment_load but if you have a look at the api entry for hook_link, you'll find the answer there:

http://api.drupal.org/api/function/hook_link/6

If $type is 'comment', the second parameter, $object, will be the comment itself so something like this should work (untested):

function quickedit_link($type, $object, $teaser = FALSE) {
  global $user;
  $links = array();
  // Only show link to authenticated users, because user contact
  // is not available to anonymous users.
  if ($user->uid && $type == 'comment' && variable_get('quickedit_'. $type, 1)) {
      $links['quickedit'] = array(
        'title' => t('Quickedit'),
        'href' => 'comment/edit/'.$comment->cid,
        'attributes' => array('title' => t('Quickedit')),
      );
  }
  return $links;
}

Also, it looks to me that the default value in your _form_alter function should be:

variable_get('quickedit_'. $form['#node']->type, 1);
v8powerage’s picture

It's working but instead /comment/edit/123 I'm getting incorrect address /comment/edit/

dazweeja’s picture

My bad, line should be:

'href' => 'comment/edit/'.$object->cid,
v8powerage’s picture

Thank You very much! ;-)

One more thing the Quickedit is now appearing for all comments, even if user didn't posted them, which is wrong :/

dazweeja’s picture

OK, this is the last time that I'll help and then you're on your own ;) My advice is to use api.drupal.org wherever possible, look in existing Drupal code (especially core) for solutions to similar problems, and maybe read the Pro Drupal Development book which is very good.

So to your problem. What you want to do is add another check to your 'if' statement to see whether the comment author is the same as the logged in author. You already have a reference to the logged in author, ie. the line 'global $user', so this is easy. Usually you'll also want to add the ability for someone with the correct permissions to make changes too, eg. a site admin, moderator, etc., so it's a good idea to look on the user permissions page (/admin/user/permissions) to see if there's an existing permission that's relevant. In this case, there's one called 'administer comments'. You can check if the logged in user has this permission to with the function 'user_access'. So try this:

if ($type == 'comment' && !empty($user->uid) && ($user->uid == $object->uid || user_access('administer comments')) && variable_get('quickedit_'. $type, 1)) {
v8powerage’s picture

Hi
I was fiddling around with user_access before, but couldn't make it right.

Thank You v. much again ;-)

chromix’s picture

In my module comments_og I do something like the following:

<?php
function MY_MODULE_link_alter(&$links, $node, $comment) {
  if ($comment) {
    $links['comment_edit'] = array(
      'title' => t('edit'),
      'href' => "MY_MODULE/edit/$comment->cid/$group->nid"
    ); 
  }
}

So there is a link alter for comments...!

dazweeja’s picture

Yes, hook_link_alter works now. I'm pretty sure it wasn't working for comments in threads though until this patch was committed.