I'd like to reverse order of comments with one special content type to DESC. Unfortunately this option is no more in Drupal 7 :(

I know you'll advise me very likely to use Views. But it's tooooo heavy weight weapon to solve just such simple task. I don't want to define everything newly about fields, layout and formatting. Current comments are great and the only thing I want is to have the newest ones on the top of the thread with one content type.

I found function comment_get_thread($node, $mode, $comments_per_page) in comment.module where it's hard coded in the core to ASC. Unfortunately I'm not such professional drupalist to know how to override that without changing the core. It's not hook or theme function.

Any advice, please? I'm quite desperate... just wanna do simple task in a simple way...

Comments

barrett’s picture

Well, I'm surprised, but it doesn't look like you can do that without hacking core. However, based on the comments in that function and some quick testing, loading comments in reverse order is surprisingly tricky when you're dealing with comments and replies to comments. Just switching ASC to DESC yields some pretty non-intuitive results.

abe.lincoln’s picture

Yep, I'm surprised as well. Nevertheless even it's tricky to sort descended threads with replies, every other content management system can do it.

I'm also surprised nobody else wanna solve that...

doronin’s picture

Thank you for pointing out the function. There is a comment that clarifies the sorting issue. And as much as I understand at this fairly late hour, DESC is where it gets somewhat tricky (Thread mode, of course. There's nothing special about Flat mode as it executes a simple 'SORT BY comment id' query).

My project runs comments as a guestbook on one page only. So the structure [ Comment - One Answer ] is all I need and here is what I've done to make this work for me:

  else {
    // See comment above. Analysis reveals that this doesn't cost too
    // much. It scales much much better than having the whole comment
    // structure.
    $query->orderBy('c.thread', 'DESC');
  }

However, when it comes to sorting multiple child comments this is not gonna work (again, the function comment for more info). One more thing: the submit function requires attention as it redirects to the last page.

I'm not a drupal expert either, but I don't feel bad to change the core module a little bit. The thing I was really surprised about is that nothing has changed in developer versions yet.

barrett’s picture

The thing to watch with core hacks, simplyrank1, is when you upgrade core your hack is going to be overwritten and you'll have to reapply it. There's also the risk that other modules which depend on the core functionality you've altered will not work as expected because of the alterations you've made.

It's your site. Do with it what you will. Just make sure you're prepared for the consequences.

doronin’s picture

I appreciate your competent advice.

maurizio.ganovelli’s picture

Since i still couldn't find any solution for that, i developed a little module to sort comments on nodes. If you want you can download & try it at http://ganovelli.it/project/sort_comments. Let me know if works for you.

nuez’s picture

you might manually reverse the array in the output in theme layer

the comment-wrapper.tpl.php outputs
print render $content['comments'];

you might do:

 $comments = array_reverse ($content['comments']);

 print render($comments); 

It is a bit tricky though when you have threaded commetns, i haven´t tried that yet.

Freelance Drupal Consultant

yngens’s picture

Interesting approach, but this didn't work for me. Using this instead http://drupal.org/project/comment_goodness

paulhudson’s picture

'Bit tricky' - yes quite. :-)

Here's my solution:


    $comments_sorted = array(); // Our sorted comment array ready to render
    $comments_thread = array(); // Temp store for threaded comments

    foreach($content['comments']['comments'] as $key => $comment) {

      if (is_object($comment['comment_body']['#object'])) { // Comment object?

        // Top level comment
        if ($comment['comment_body']['#object']->depth == 0) {

          // We have a previous thread to append before building the new thread
          if (!empty($comments_thread)) {

            array_unshift($comments_sorted, $comments_thread);

            $comments_thread = array(); // empty our temp store for the next thread
          }

          array_push($comments_thread, $comment);
        }

        // Comment is a threaded reply
        if ($comment['comment_body']['#object']->depth > 0) {

          array_push($comments_thread, $comment);

        }
      }
    }

    // We should be left with the final thread so we append it here
    array_unshift($comments_sorted, $comments_thread);

    print render($comments_sorted);

NOTE: I am using comment goodness module to order the newest comments first... however I wanted only say the 3 most recent comments and them listed old to new:

So if I have comments:

-1
--1a
--1b
-2
--2a
-3
-4
--4a

I use comment goodness to select the newest 3 comments:

-4
--4a
3

But I don't want them in that order... so with my snippet of code I can flip them about into a more logical order:

-3
-4
--4a

This allows me to use the standard comment settings to only load the number of comments out the DB as I actually intend to render and sort their order very quickly last minute... no core hacking, no *substantial* performance impact and it's fairly obvious to any future code maintainers.

Hope it's useful for someone... would be pleased to hear any possible improvements!

Paul

tassaf’s picture

That is not working

any other solution for that?

paulhudson’s picture

humm, stable and works fine for my use case with Comment Goodness. If you give me some details I might be able to help.

edsenior’s picture

I was hoping this would let me sort comments in forum topics so the latest comment shows first.
I installed the module but have given up trying to find where to configure it.
Can you explain?

edsenior’s picture

Right after I posted my last post I found it in the nodes module. Thanks It works perfect.

davidwbarratt’s picture

I submitted a Feature Request..
http://drupal.org/node/1193520

fax8’s picture

I'm using http://drupal.org/project/sort_comments and it's working good so far..

Anyway, that's really bad to remove a feature present in 6.x core...

greenwork’s picture

For other people like me

http://drupal.org/project/comment_goodness

I will try this one

====================================
Website:LEED Exam V4

jetwodru’s picture

Don't know why later versions of Drupal keep removing basic functionalities which were already in core in Drupal 6. It seems so silly to bring back this basic function with an add-on module.

d2ev’s picture

those who don't want to use module ...don't forget to clear cache.

* Implements hook_query_TAG_alter().
 *
 * Alter comments query to order by DESC as well as the default ASC.
 */
function modulename_query_comment_filter_alter(QueryAlterableInterface $query) {
  $orderby = &$query->getOrderBy();
  $expressions = &$query->getExpressions();
  // Sorting for threaded comments.
  if (isset($orderby['torder'])) {
    // Get rid of the expressions that prepare the threads for ASC ordering.
    unset($expressions['torder']);
    unset($orderby['torder']);
    // Simply order by the thread field.
    $orderby['c.thread'] = 'DESC';
  }
  // Sorting for flat comments.
  else {
    $direction = 'DESC';
    if (isset($orderby['c.cid'])) {
      unset($orderby['c.cid']);
    }
    $orderby['c.created'] = $direction;
    $orderby['c.cid'] = $direction;
  }
}
seant’s picture

Thank you :)

figtree_development’s picture

Im using the code above:

/* Implements hook_query_TAG_alter(). 
* * Alter comments query to order by DESC as well as the default ASC. */
function currents_query_comment_filter_alter(QueryAlterableInterface $query) {
    $orderby = &$query->getOrderBy();  
    $expressions = &$query->getExpressions();  
    // Sorting for threaded comments. 
    if (isset($orderby['torder'])) {   
       // Get rid of the expressions that prepare the threads for ASC ordering.
        // Simply order by the thread field.
            
            unset($expressions['torder']);
            unset($orderby['torder']);
           $orderby['c.thread'] = 'DESC';   
           
         
    }else{  // Sorting for flat comments.   
        $direction = 'DESC';
        if (isset($orderby['c.cid'])) {
            unset($orderby['c.cid']);    
        }
        $orderby['c.created'] = $direction;
        $orderby['c.cid'] = $direction; 
    }

}

which gives me the descending order. However is there a way to modify this so it only effect threads at the top level (i.e. XX/) while preserving the ascending order for replies to threads. (i.e. xx.xx/ or xx.xx.xx/, etc)?

martaci’s picture

Hello,

i was also looking for that and i used the following:


function comment_query_comment_filter_alter(QueryAlterableInterface $query){
	  if (($node = $query->getMetaData('node')) && (get_class($query) == 'PagerDefault')) {

		  $orderby = &$query->getOrderBy();
		  $expressions = &$query->getExpressions();
		  // Sorting for threaded comments.
		  if (isset($orderby['torder'])) {
			// Get rid of the expressions that prepare the threads for ASC ordering.
			unset($expressions['torder']);
			unset($orderby['torder']);			
			$query->orderBy("SUBSTRING_INDEX( REPLACE( c.thread,  '.',  '/' ) ,  '/', 1 ) ", "DESC")->orderBy('pid');
		  }
		  // Sorting for flat comments.
		  else {
			$direction = 'DESC';
			if (isset($orderby['c.cid'])) {
			  unset($orderby['c.cid']);
			}
			$orderby['c.created'] = $direction;
			$orderby['c.cid'] = $direction;
		  }

	  }
}

I exchanged

$orderby['c.thread'] = 'DESC'; 
 

for

$query->orderBy("SUBSTRING_INDEX( REPLACE( c.thread,  '.',  '/' ) ,  '/', 1 ) ", "DESC")->orderBy('pid');

Here is an example of the comments table:

cid | pid | thread
1 | 0 | 01/
2 | 0 | 02/
3 | 1 | 01.00/
....

120 | 0 | 111/
121 | 120 | 111.00/

In order to get the main thread i replace the "." --> "/" and take the substring until the character "/".

01/
01/00/
02/
....
111/
111/00/

Then you order them DESC by "thread" and ASC by "pid"

Hope it helps!

figtree_development’s picture

using that code, with the following comments:
cid | pid | thread
151 | 150 | 03.00/
155 | 150 | 03.01/
157 | 150 | 03.02/
156 | 155 | 03.01.00/
158 | 155 | 03.01.01/
159 | 155 | 03.01.02/

produces this:
03.00/
03.01/
03.02/
03.01.00/
03.01.01/
03.01.02/
......
what should be produced is this:
03.00/
03.01/
03.01.00/
03.01.01/
03.01.02/
03.02/
02.00/
02.01/
02.01.00/
01.00/

I guess im missing the DESC but not sure where it goes?

martaci’s picture

Yea i didnt take into account a reply from a reply.

You can order them by the different parts of the thread, but it does not look pretty! ;)

exchange:

$query->orderBy("SUBSTRING_INDEX( REPLACE( c.thread,  '.',  '/' ) ,  '/', 1 ) ", "DESC")->orderBy('pid');

with:

/*  For example in 00.01.02   */
$query->orderBy("SUBSTRING_INDEX( REPLACE( thread,  '.',  '/' ) ,  '/', 1 ) ", "DESC") /* --> 00 */
 ->orderBy("SUBSTRING_INDEX( SUBSTRING_INDEX( REPLACE( thread,  '.',  '/' ),  '/', 2 ) ,  '/', -1 ) ") /* --> 01 */			  
 ->orderBy("SUBSTRING_INDEX( SUBSTRING_INDEX( REPLACE( thread,  '.',  '/' ) ,  '/', 3 ) ,  '/', -1 ) ");/* --> 02 */			  

The actual query would be:

SELECT * 
SUBSTRING_INDEX( REPLACE( thread,  '.',  '/' ) ,  '/', 1 ) AS substr, 
SUBSTRING_INDEX( SUBSTRING_INDEX( REPLACE( thread,  '.',  '/' ),  '/', 2 ) ,  '/', -1 ) AS substr2, 
SUBSTRING_INDEX( SUBSTRING_INDEX( REPLACE( thread,  '.',  '/' ) ,  '/', 3 ) ,  '/', -1 ) AS substr3
FROM  `comment` 
ORDER BY substr DESC , substr2, substr3

Your comment would be sorted like this:

02/
02.00/
01/
01.00/
01.00.00/
01.00.01/
01.00.02/
01.01/

Hope it helps!

eliosh’s picture

... but we have a problem.
Sorting works like a charm for me, but i have a problem when trying to calculate page for the comment.
The problem is with the function comment_get_display_ordinal that calculates comment page based on original order.

I'm trying to override this function, but it doesn't seem very simple.

--
eLiosh

SilviuChingaru’s picture

I use the following code, that is working for unlimited nested replies:

/** Implements hook_query_TAG_alter().
 *
 * Alter comments query to order by DESC as well as the default ASC.
 */
function MYMODULENAME_query_comment_filter_alter(QueryAlterableInterface $query) {
  $orderby = &$query->getOrderBy();

  // Sorting for threaded comments.
  if (isset($orderby['torder'])) {
    // Sort by root parent first, then normal threaded.
    $query->addExpression("SUBSTRING_INDEX(c.thread, '.', 1)", 'rparent');
    $orderby = array('rparent' => 'DESC') + $orderby;
  }
  // Sorting for flat comments.
  else if (isset($orderby['c.cid'])) {
    $direction = 'DESC';

    $orderby['c.cid'] = $direction;
    $orderby = array('c.created' => $direction) + $orderby;
  }
}

--
Works at Magazinul Cu Scule .ro

delta’s picture

Thanks, it work for me too

narendrar’s picture

Thanks, this worked for me too.

Let's Drupal

iic220’s picture

I used the approach provided here to reverse comments order in Drupal 8.
but I receive the followig error when run the module:
Recoverable fatal error: Argument 1 passed to mymd_query_comment_filter_alter() must be an instance of QueryAlterableInterface, instance of Drupal\Core\Database\Query\PagerSelectExtender given, called in D:\wamp95\www\drupal83\core\lib\Drupal\Core\Extension\ModuleHandler.php on line 501 and defined in mymd_query_comment_filter_alter()
what is the problem and how should I solve it?

cohmstede’s picture

Thanks fiftyz

This worked for me.

lobodakyrylo’s picture

For Drupal 8 you can use the next module: Comments order.

It solves this problem.