Drupal: remove "reply" link from comments

Drupal

In admin/content/types you can configure the behavior of the comments per content type. One of the options under the comment settings is the visibility of the comment form: either hide it or display it under the comments.

Display mode

If you select display on separate page then the form is not displayed. Visitors have to click on the add new comment or reply link, so a new page loads with the comment form.

Or you can select display below post or comments so that the form is displayed at the bottom of the page, under the post or the last comment.

In the same admin page you can select whether you wish threaded comments or flat comments. If you prefer threaded comments, then displaying the comment form under the last comment may be confusing. Most visitors will likely just enter their reply there, saving themselves a click and a new page load. But there is the option to click reply for an individual comment as well.

Display mode

If you wish to display the comment form, you may as well switch to the flat comment model. In that case, the reply links for individual comments are sort of redundant. Wouldn't it be nice if we can hide those reply links.

The easy way out: hide the link

You can simply use display: none in CSS but this is certainly not the most elegant solution. It hides the last class, for example. Take a look at the default code for the comment links (I need the PHP tags for the syntax highlighting):

<?php
<div class="links">
  <
ul class="links">
    <
li class="comment_delete first"><a href="/test-site/comment/delete/3668">delete</a></li>
    <
li class="comment_edit"><a href="/test-site/comment/edit/3668">edit</a></li>
    <
li class="comment_reply last"><a href="/test-site/comment/reply/1853/3668">reply</a></li>
  </
ul>
</
div>
?>

This is an example with delete and edit links that you hopefully don't have enabled for your visitors.

Simply adding something like this to CSS:

.links ul li.comment_reply {
  display: none;
}

will indeed hide the reply link, but it also hides the last class and that can sometimes wreak havoc with the styles.

It would be better to completely remove the reply link, so we'll do that next.

Slightly better, simply removing the reply link

The easiest way to remove the reply link is by creating the function phptemplate_links to template.php or to add the code to it if it already exists.

<?php
function phptemplate_links($links, $attributes = array('class' => 'links')) {

  if (isset(
$links['comment_reply'])) {
    unset(
$links['comment_reply']);
  }

  return
theme_links($links, $attributes);
}
?>

But this will always remove the reply link. If you prefer to have different configurations of the comments for the various content types, then simply always removing the reply link can also cause issues: for example, if the comment form is not visible (display on separate page in the admin pages) there is no visible clue for visitors what to do.

So we need to improve our code: remove the link, but only if the comment form is displayed on the same page.

Better yet, conditionally remove the reply link

Check the variables comment_form_location_... where ... is the content type, e.g. blog, forum, page, etc. If the comment form is displayed on a separate page its value will be 0. If the comment form is displayed on the same page its value will be 1.

So we will extract the content type from the reply link, retrieve the configuration of the comment form, and then determine whether to remove the reply link or not. Again, create this function in template.php or add the code to the function if it already exists.

<?php
function phptemplate_links($links, $attributes = array('class' => 'links')) {

 
// -- Remove the link "reply" --
 
if ( isset($links['comment_reply']) ) {
   
// Dissect link urls
   
$parts = explode('/', $links['comment_reply']['href']);
   
// Execute rest if we have a numeric node ID
   
if ( ctype_digit($parts[2]) ) {
     
// Load the node
     
$node = node_load($parts[2]);
     
// Variable to check
     
$variable = 'comment_form_location_' . $node->type;
     
// Indicate whether we display the comment form below the post/comments
     
$form_below = variable_get($variable, COMMENT_FORM_BELOW) == COMMENT_FORM_BELOW;
     
// If displayed on same page then remove 'reply' link
     
if ( $node && $form_below ) {
        unset(
$links['comment_reply']);
      }
    }
  }

  return
theme_links($links, $attributes);
}
?>

The $parts array contains the exploded substrings. Since the reply link is made up as comment/reply/nnn where nnn is the node ID, we can extract that and use it to load the node so we can extract the type ('blog' or 'forum', etc).

$node contains the complete node.

$variable contains the name of the variable we will be looking up. E.g. comment_form_location_blog or comment_form_location_forum.

variable_get() will retrieve the value for the variable and the comparison be true or false. The constant COMMENT_FORM_BELOW is from the comment module and equals 1 (see Drupal API).

So once we have the node type we can extract the comment form setting to determine whether to show or hide the reply link. The reply link will be hidden if we have a node ID in the URL and the comment form is configured to be displayed below the post or the comments.

Credit

The idea for this code was taken from an old 2007 post at Drupal. There, however, the reply link is simply removed per content type (e.g. for blog posts or forum posts). I added some additional code to check the configuration of the content type.

Edit: added the class to the function's attributes.

Drupal 7

In D7 you can use this solution as part of comment preprocess function (this was also offered by cameronbprince in the comments):

<?php
function MYTHEME_preprocess_comment(&$vars) {
  unset(
$vars['content']['links']['comment']['#links']['comment-reply']);
}
?>

This will indeed remove the link.

But I just realized that the removal of the link does not alter the functionality. When looking with the developer module ("render" tab) it still shows the links, even though they aren't displayed:

And if you paste the URL in the browser address bar it will indeed execute and add a new comment as a child to node x, comment y. If you are using flat comments then it may seem like the comment belongs to the node x, while it belongs to the parent comment y. When deleting comment y its children, our new comment, will also get deleted.

Of course, it will require the node ID and the comment ID but the node ID can be read from the comment form action, and the comment ID is available via the permalinks.

I haven't found a native Drupal solution for that yet; something to keep in mind. You could use Flatcomments mentioned elsewhere in the comments) for this. It will move comments to the node, regardless of what reply link is used.

If you decide to install that module, it also offers a content type option to remove the "reply" link for comments:

Comments

Hi there, thanks for this code - it did the job for me, but unfortunately it broke the styling for the buttons on my blog comments as well! It looks like the basic HTML is there (a div with class="links" containing an unordered list), but the list doesnt have any CSS classes assigned to it any more, so none of the styling gets applied!

Any thoughts would be really appreciated,
Cheers,
Jack

I would have to run it on a fresh installation with Garland to confirm but this is what I see on my comments:

<?php
<div class="links">
  <
ul>
    <
li class="comment_delete first"><a href="/comment/delete/1">delete</a></li>
    <
li class="comment_edit last"><a href="/comment/edit/1">edit</a></li>
  </
ul>
</
div>
?>

As you can see, the only difference is that the "reply" list element has been removed. The remaining elements of the list have not changed. The DIV, the UL and any other LI elements should remain unaffected (including the class names for any remaining LI elements). Could it be that you have other modules or other code interacting with the $links array? The example was for Drupal 6, by the way.

(I'll post another comment when I have ran a test later tonight. Frankly, I don't see why an unset statement would affect anything else but the LI element.)

I just created a brand new test site with Drupal 6. Using my example in the phptemplate.php it only removed the existing "reply" link, nothing else.

I am not sure I understand what buttons you are referring to. These must either be CSS based or you are using additional code or modules since this doesn't sound like a standard Drupal feature.

Hi stplanken, thank you so much for your time. After looking over the code, I see that I do get the same HTML as you, but this is different to what I get if I don't include your function. The only difference being that originally, the UL element had a class of "links".

This means that lots of my theme's styling rules are no longer applied. This is clearly a theme related issue, but I'm not sure how to correct it. How do I find out where/how my theme is adding it's own css classes to the HTML elements? And will it be possible to incorporate that into your function?

I'm using the Acquia Marina theme.
Thanks a lot,
Jack

Hmmm... haven't seen that one... Don't have time right now, but how about adding a class name in your comment template? Something like this:

<?php
<div class="links some-unique-class">
  <
ul>
    <
li class="comment_delete first"><a href="/comment/delete/1">delete</a></li>
    <
li class="comment_edit last"><a href="/comment/edit/1">edit</a></li>
  </
ul>
</
div>
?>

And then using

.links.some-unique-class ul {
  styles here
}
.links.some-unique-class ul li.comment_delete {
  styles here
}
...etc

I am using Acquia Marina at work for our local intranet, and I have used the same code snippet there as well to hide the reply link for forum comments. I will run a test today and post the results here later this morning.

I checked, I am unable to duplicate your issue. But you haven't explained what buttons are being affected. The links in the nodes and comments are not affected. I checked the default A.M. theme version 2 and the only location where links are manipulated is template.php in acquia_marina_preprocess_node at line 283. I haven't checked version 3 of the theme.

Hey I'm using AM v2. I'm referring to when I view a blog post that has comments. Each comment has the links: delete, edit, reply etc. I want to remove the reply link.

Note: originally, the HTML was the same as in your comment #2, except the UL had class="links". Now if I add the following code to my theme's template.php, that UL loses that class, and none of the theme's styling gets applied:

<?php
function phptemplate_links($links, $attributes = array()) {
    unset(
$links['comment_reply']);
    return
theme_links($links, $attributes);
}
?>

Thanks for your workaround of adding another unique class to the container div, but it is unnecessary: I can already access the elements in a unique way. The problem is that this is not an elegant solution: obviously this code is not calling the same theme-related functions, and so the resulting HTML is missing a class.

This is not a major issue, but I would be interested in understanding why it is happening.

Cheers,
Jack

Aha, I see... Just add the array('class' => 'links') to the function's attributes, instead of leaving it empty.

<?php
function phptemplate_links($links, $attributes = array('class' => 'links')) {
  ...
}
?>

This adds the class="links" to the output.

Amazing - so simple when you know how!

Many thanks.

Isn't that always the case. :-)

I think somewhere in here is a way to add styling to the links, instead of removing them. I wish I understood more. Thx!

Just use your style sheets:


.links ul li.comment_reply {
...styles here...
}

Can this function be used in a module instead of a theme (e.g. put the code in MYMODULE.module instead of template.php)? I tried it, but it doesn't seem to work.

It really is easiest to implement it in phptemplate but you might want to take a look at the flatcomments module over at : http://drupal.org/project/flatcomments which has this as an option (although it's main purpose is to move comments to a comment to its parent node).

i need this comment reply module...
help me out...

Follow the instructions, please.

You can do this within template.php as follows:

function theme_preprocess_comment(&$variables) {
  unset($variables['content']['links']['comment']['#links']['comment-reply']);
}

Using hook_preprocess_comment allows you to remove the reply links conditionally as you have access to the entire array of comment variables unlike the links hook.

Thanks!

Thanks. @17 worked instantly for me on drupal 7.

I just realized that the solution offered by cameronbprince has the same drawback: it indeed removes the link from the comment, but it will still allow the URL to be executed. I added it to the original post. Unless you use Flatcomments.