Jump to content

Order posts by children count


encho
 Share

Recommended Posts

I am really puzzled how to do this:

I have posts template with custom field called 'author', which is basically 'page field' referring to other page in the site where I keep list of the text authors.

In a nutshel I want to display list of 5 authors with most texts associated with them. If authors had subpages containing the text of the said author, this would not be an issue, but pages are actually elsewhere (primary sorting is by other criteria, categories).

So first part of the problem is how to get pages, which should be like this:

$authors = $pages->find("template=author, sort=count, limit=5");

So obvious problem is this 'count' part where it should calculate posts that have field 'author' used the most.

Second problem is how to display the number of posts every author has. I will need to rethink the whole scenario if this would not be possible (but considering it is ProcessWire we are talkin about, it shouldn't be an issue :) ). Thanks.

Link to comment
Share on other sites

Tricky one... let me think...

second problem is easy:

foreach($pages->find("template=author") as $a){
echo count($pages->find("template=post, author=$a));
}

and the first problem... hm, how about this?

$authors = $pages->find("template = author");

$authorsPosts = array();

foreach($authors as $a){
$authorsPosts[] = array("count" => count($pages->find("template=post, author=$a")), "author" => $a);
}
sort($authorsPosts);
$authorsPosts = array_slice($authorsPosts, 0, 5); //added this line to limit to 5

foreach($authorsPosts as $p){
echo $p["author"]->title . " wrote " . $p["count"] . " posts<br>";
}

edit: i forgot about the limit of 5... already edited the code:

  • Like 1
Link to comment
Share on other sites

Thanks for your try, first part of code does not produce valid results because field 'author' is page reference, so it actually produces an ID.

Second code is giving me 'Parse Error syntax error, unexpected T_DOUBLE_ARROW' and there is a bracket ')' missing.

But you're right this seems complicated, although you seem to be on a right track.

Link to comment
Share on other sites


// output the 5 authors with the most posts sorted by post count
$authors = $pages->find("template=author,posts.count>0")->sort("-posts.count")->find("limit=5");
foreach($authors as $a){
   echo "<p>$a->url $a->title ({$a->selec_page_image->count()})</p>";
}

This seems to work, but only if you make the sort and limit after the find. I'm not sure what exactly happens, but if you put sort inside first find it will throw error, now it works if added afterwards. The last find is to limit it to 5. Note limiting has to be after the sort, otherwise you get a mixed result obviously.

  • Like 7
Link to comment
Share on other sites

soma's answer is obviously better than mine. still:

on the first part ") was missing after $pages->find("template=author

i will edit it.

on the second I think you must have tried my code before I corrected it. It's working with me as it is.

Link to comment
Share on other sites

Not my day I guess.

@diogo your second code is still reporting unexpected T_DOUBLE_ARROW

edit: first code works perfectly fine, I can display all the authors with number of posts, thanks. Now just to sort them by post number.

@soma what is this posts.count part? It is reporting "Field does not exist: posts.count", should there be field name or?

Link to comment
Share on other sites

Sorry my fault. I haven't read careful and assumed from your selector that you have authors with a page field "posts" to reference all posts.

It's the other way round then. But having it the way I assumed would result in having a simpler code :D

Don't worry, you could either change it if you like it or use this with current (like nico but little improved I think)

$authors = $pages->find("template=authors");
// create empty page array
$res = new PageArray();
foreach($authors as $a) {
   // temporarely add postscount property to author
   $a->postcount = $pages->count("template=posts, author=$a");
   $res->add($a);
}

foreach($res->filter("sort=-postcount, limit=5") as $a){
   echo "<p>$a->title ($a->postcount)</p>";
}

Let me know if it works for you.

  • Like 4
Link to comment
Share on other sites

@diogo your second code is still reporting unexpected T_DOUBLE_ARROW

You're right again, another bracket was missing here after author=$a"). Already corrected it.

(like nico but little improved I think)

Yep, much more elegant than nico's ;)

Link to comment
Share on other sites

Sorry my fault. I haven't read careful and assumed from your selector that you have authors with a page field "posts" to reference all posts.

It's the other way round then. But having it the way I assumed would result in having a simpler code :D

Don't worry, you could either change it if you like it or use this with current (like nico but little improved I think)

$authors = $pages->find("template=authors");
// create empty page array
$res = new PageArray();
foreach($authors as $a) {
// temporarely add postscount property to author
$a->postcount = $pages->count("template=posts, author=$a");
$res->add($a);
}

foreach($res->filter("sort=-postcount, limit=5") as $a){
echo "<p>$a->title ($a->postcount)</p>";
}

Let me know if it works for you.

Amazing, that does it, with minor adjustment (template=post). Many, many thanks. Now sky is the limit ^-^

Link to comment
Share on other sites

  • 2 years later...

I have tried to use this setup on my movie blog, but replaced author with director. The thing is, I have 2300+ movie posts, and 1400+ director pages.

Is there a way to use count instead of find to ease the performance (first line?)? I have used the following code for testing purposes, but even locally (MAMP) without diagnostic I noticed the page load is a bit too much.

$directors = $pages->find("template=director");
$res = new PageArray();

foreach($directors as $a)
{
$a->postcount = $pages->count("template=post, director=$a");
$res->add($a);
}

foreach($res->filter("sort=-postcount, limit=10") as $a)
{
echo "<li><a href='$a->url'>$a->title ($a->postcount)</a></li>";
}
Link to comment
Share on other sites

You can hardly use this method, without caching the number of movies by director somewhere in the database. There's no internal counter for pagefield usage, so the only option besides runtime calculation is using a field, that'll hold the number of posts and updates on changes. You should probably use an hook on Pages::saveReady, which does update a "number_of_posts" field in the directors template when you save any post or when you save any director. For initial population of those fields you would need to heavily use uncache to prevent memory overflow, but, together with a not to short execution time, you can once loop over all directors to get initial counts set.

Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

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