Jump to content

Sorting by Related Page Count


Go to solution Solved by horst,

Recommended Posts

Hey folks, I'm attempting to order a list of subjects based on the number of pages (not child pages) that link to each subject. The end result will look like this:

portrait — 120 items

landscape — 78 items

trees — 42 items 

beards — 8 items

etc.

I've been digging through the archive here, but I can't seem to find a solution. The issue is that I'm using wire('page')->find to get the list of subjects, and then getting the number of linked items inside the foreach — here's my code:

$subjects = wire('page')->find("template=subject, sort=title");
foreach ($subjects as $subject) {
$artwork = rendersubjectArtworkList(findartworks("subjects=$subject, limit=1"));
$count = findartworks("subjects=$subject")->count;
}

I can't figure out how to either combine my queries or re-sort the list after the call. Any ideas? 

Thanks so much for any help!

Link to post
Share on other sites

How have you linked the pages to the subjects? WIth which field(s)? Do you use an InputfieldPage for that?

What does this function do: findartworks("subjects=$subject, limit=1") ?  You call it two times.

Link to post
Share on other sites

Assuming your artworks have a template named 'artworks' and a select/ multiselect field 'subjects' of type page, where you define the type (subject) you could do the following:

$subjects = $pages->find("template=subject, sort=title")->each('title'); // get the titles of subjects (pages)
foreach ($subjects as $subject)
$artworks = $pages->find("template=artworks, subjects=$subject");
 echo $subject.' — '.$artworks->count;
}
  • Like 4
Link to post
Share on other sites

Hi Horst! Excellent questions — 

I've got pages with two different templates: artworks, and subjects. On the artwork pages, I'm using a page field (set to allow multiple pages using AsmSelect) to link to 

subjects.

kixe — that does work, but the end result is still ordered by title, and I'm attempting to reorder the list by $artworks->count; from highest to lowest. 

I'll kick it around more today, thanks for your input!

Link to post
Share on other sites
  • Solution

I think this must work:

$pa = new PageArray();                                     // use a PageArray to collect all subject pages
foreach($pages->find("template=subject") as $subject) {    // iterate over all subject pages
    $subject->set('myCount', $pages->find("template=artworks, subjects=$subject")->count);   // add a temporary property to it that holds the total number of linked items
    $pa->add($subject);                                    // add it to the PageArray
}
foreach($pa->sort("-myCount") as $item) {                  // sort the PageArray descending by total number and echo the title and count
    echo "<li>{$item->title} ({$item->myCount})</li>";
}
  • Like 3
Link to post
Share on other sites

horst — many thanks!

This worked perfectly. It's a pretty hefty database call, so I've limited the number of subjects to 20 to keep the TTFB down. But it works! And @Macrura, thanks for your thoughts as well - I'll keep that solve in mind — 

Here's my final function:

function rendersubjectlistsort($pages) {
	$out .="<div class='listWrapper'><div class='imageList'>";

	$pa = new PageArray();
	foreach($pages->find("template=subject, limit=20") as $subject) {
	    $subject->set('myCount', findartworks("subjects=$subject")->count);   
	    $subject->set('myImg', rendersubjectArtworkList(findartworks("subjects=$subject, limit=1"))); 
	    $pa->add($subject); 
	}
	foreach($pa->sort("-myCount") as $item) {
		$out .= "<a class='listItem' href='{$item->url}'>" . 
					$item->myImg .
					"<div class='itemInfo'>" .
						"<h3>{$item->title}</h3>" . 
						"<span class='dates'>{$item->myCount} images</span>" .
						"<div style='clear:both;'></div>" .
					"</div>" .
				"</a>";

	}

	$out .="<div style='clear:both;'></div></div></div>";
	return $out; 

}

Thanks again!

  • Like 1
Link to post
Share on other sites

Only you have to keep in mind that it doesn't scale if you do this for more and more pages.

Also note that if only counting a $pages->count(selector) is more efficient. Instead of $pages->find()->count

What I do on a shop category tree, is calculate it every time a product is saved and write the count to a integer field on the category pages. So it's like cached.

You could also use markup cache to cache the output and only let rebuild it when a product is changed.

  • Like 1
Link to post
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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Robin S
      Displays image tags overlaid on the thumbnail using customisable colours. This makes it easier to see which images have which tags without needing to open the edit pane for individual images or changing to the list view.
      Screenshot

      Usage
      Enable tags for one or more image fields. Install the Image Thumbnail Tags module. Optionally configure colours for any of your tags.
       
      https://github.com/Toutouwai/ImageThumbnailTags
      https://modules.processwire.com/modules/image-thumbnail-tags/
    • By Andi
      Continuing my journey into PW hooks, I'm trying to find a way to retrieve all images from a page that explicitly *do not* have a certain tag (or tags) attached to them.
      Found this post from 2015
      But I'm wondering if there's a more elegant way to go about this.
      Let's say I have a multi-image field called "images_header" and instead of
      $page->images_header->findTag('mytag'); I would like to do this:
      $page->images_header->excludeTag('mytag'); So I'd be able to do
      // find images that don't have the tag "mytag" $images = $page->images_header->excludeTag('mytag'); // check if there's any images if (count($images)>0) { // do something.. } Would this be possible by hooking into Pagefiles somehow?
      There's this bit in /wire/core/Pagefiles.php Line 626 that I'd basically just need to reverse (or at least in my mind 😄 )
      public function findTag($tag) { $items = $this->makeNew(); foreach($this as $pagefile) { if($pagefile->hasTag($tag)) $items->add($pagefile); } return $items; } Any ideas on how this could be done in a graceful manner?
      Thanks in advance!
    • By opalepatrick
      Hi, trying to order pages by modified date, date. I can do 'sort=-date_modified, sort=-date' but that will always put the modified date first regardless of actual date order. I just want to coalesce the two fields and sort. Any ideas would be appreciated.
    • By louisstephens
      So I don't know how many have noticed yet, but Youtube has depreciated "rel=0" at the end of the embedded url in September 2018. For some reason, I just noticed today on a site I was working on. If you do not use the rel, you will get related videos across youtube, but if you use it, you will only get related videos from the same channel. Just wanted to share in case people did not know and they needed to make a change on whatever they were working on.
    • By louisstephens
      I have done a bit of searching, but I can not seem to find an actual answer. I have a list of services as child pages under "Services". I can output the services just fine, but I cant wrap my head around how to group them "alphabetically" like:
      Services A - Service "A" 1 - Service "A" 2 - Service "A" 3 B - Service "B" 1 - Service "B" 2 - Service "B" 3 C - Service "C" 1 - Service "C" 2 - Service "C" 3 Has anyone achieved this type of functionality before?
×
×
  • Create New...