Jump to content

Recommended Posts

Posted

Howdy all,

Is there a means to return pages sorted by star ratings? I apologize if I have missed a topic, but I haven't found anything related with my searches.

Thanks for your help!

Posted (edited)

@dragan, I'm using the core comments with star rating field type.

Yes, the test code doesn't return any errors...

// Tracy console
$p = wire('pages')->get('template=my_template,include=all');
if($p->hasChildren) {
	$pc = $p->children('sort=stars, limit=12'); // One of many combinations I've tried
	d($pc);
}

But the results (12) are not sorted by stars, rather the results are returned in the order the pages were created (Id)...

total => 34
start => 0
limit => 12
pager => "1 to 12 of 34" (13)
items => array (12)
	Page:0 => array (5)
	...
	Page:11 => array (5)
selectors => "parent_id=1026, sort=stars, limit=12, status<1024" (49)

[edit]

Also, each template has the comments (fieldtypecomment) and stars are enabled.

Edited by rick
Additional info
Posted

Yes Sir, I've tried  a few combinations with the same results.  I haven't seen anything in the source regarding an average other than the public function stars itself.

Posted

For other's and my reference:

Sorting pages by stars requires the comment field name prefix, eg:
 

// From previous post...
$pc = $p->children('sort=-comments.stars, limit=12');
// Returns pages with 5 stars, then 4.5 stars, etc.

I must have mistyped the comment field name before. My apologies.

Thanks for your help @dragan.

  • Like 2
Posted

I really hate dealing with comments - due to GDPR and such - but maybe I should give it a try.

(Kind of) Glad you pushed me into this direction with your question.

  • Like 1
Posted

Well, sorting by stars seems to not work. When I expand the test data the sort fails. Here is the tracy test code...

$p = wire('pages')->findMany('template=my_template,sort=-comments.stars,include=all,limit=12');//34 total pages
foreach( $p as $m ) {
    $stars = $m->comments->renderStars(true, array('schema'=>'microdata','partials'=>true));
    echo $m->id.': '.$stars.'<br />';
}

which gives the following results...

1027: ★★★★★4/5 (7 ratings)
1068: ★★★★★★4.3/5 (6 ratings)
1148: ★★★★★★3.8/5 (17 ratings)
1086: ★★★★★★4.3/5 (10 ratings)
1056: ★★★★★★4.5/5 (2 ratings)
1114: ★★★★★4/5 (9 ratings)
1057: ★★★★★4/5 (7 ratings)
1120: ★★★★★★4.8/5 (8 ratings)
1121: ★★★★★5/5 (3 ratings)
1063: ★★★★★★3.8/5 (12 ratings)
1064: ★★★★★5/5 (1 rating)
1065: ★★★★★★4.4/5 (14 ratings)

Also notice that some ratings display 6 stars. The default config is set to 5.

I am not concerned with sorting by the number of ratings, only the average ratings.

Anyone have an idea what I am doing wrong?

Posted

Okay, here is a workaround. I call it a workaround, because one, it works for what I need, and two, this will present problems when I have to process all 5K+ pages for each of the three parent pages in this current project.

Here is the tracy code:

$p = $pages->findMany("template=my_template"); // 34 total
$s = array();
foreach( $p AS $m ) {
    $s[$m->id] = $m->comments->stars(true);
}
arsort($s);
$s = array_slice($s,0,12,true);
d($s);

Produces this result:

array (12)

1064 => 5.0
1121 => 5.0
1120 => 4.75
1056 => 4.5
1065 => 4.43
1054 => 4.41
1068 => 4.33
1086 => 4.3
1122 => 4.29
1062 => 4.25
1127 => 4.25
1058 => 4.22

 

  • Like 1
Posted
14 hours ago, rick said:

this will present problems when I have to process all 5K+ pages for each of the three parent pages in this current project

Using the brand new "multiple methods" hook feature in PW 3.0.137 you could save the average stars value to a decimal (or float) field every time a comment is approved/disapproved/updated/deleted. Then you can find or sort pages by the field more efficiently.

The hook below assumes a comments field named "comments" and a decimal field named "decimal":

$wire->addHookAfter('FieldtypeComments::commentApproved, FieldtypeComments::commentUnapproved, FieldtypeComments::commentDeleted, FieldtypeComments::updateComment', function(HookEvent $event) {
	/* @var Page $page */
	$page = $event->arguments(0);
	/* @var Field $field */
	$field = $event->arguments(1);
	if($field->name !== 'comments') return;
	if($page->template->hasField('decimal')) {
		// Save the average star rating for comments with approved or featured status
		$page->setAndSave('decimal', $page->comments->find("status=1|2")->stars(true));
	}
});

P.S. You'd do a one-off API operation to save the average stars value for all your existing comments to get things set up initially.

  • Like 3

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...