Jump to content

Pagination for thumbnails from three different albums


creativejay
 Share

Recommended Posts

Full disclosure: I'm starting in ProcessWire after having used MODX almost exclusively for the last four or five years. I still tend to think in terms of the parameters that I can set in a function call and, frankly, my knowledge of php has degenerated thanks to every need pretty much being covered by the snippet library there.

I am trying to familiarize myself with ProcessWire by coding a simple gallery site (to work my way up to more complex sites as I get more comfortable). I've been able to look up everything I need between the cheat sheet, wiki and the existing forum topics until today. I have finally stumbled into something I can't quite work out (and can't figure out keywords with which to search).

Staging site, the gallery in question: http://www.creativejay.com/xine/portfolio/
(I haven't finished setting up fancybox, that's fiddly stuff for later)

In the portfolio I have three albums currently. Since these galleries will only grow, I want to add pagination now. I understand how to paginate with MarkupPagerNav and find(), which is how I retrieve the albums themselves, but the individual images in the album are retrieved with a double scoop of foreach. Here's the entire code of my function at the moment:

<?php
function galleryMain(){
    $albums = wire("pages")->find("has_parent=/albums/");
    echo "<div class='albumgrid'>";
    $out ="";

    foreach($albums as $album) {
        $albumimages = $album->gallery;
        $thumbsize = 140;
        foreach ($albumimages as $albumimage) {   
            $out .= "<a href='{$albumimage->url}' title='{$albumimage->description}' class='fancybox-button' rel='fancybox-button'>";
            $out .= "<img src='{$albumimage->size($thumbsize, $thumbsize)->url}' style='margin-right: 15px; margin-bottom:25px; border: solid 1px #000000;' height='{$thumbsize}' width='{$thumbsize}'>";
            $out .= "</a>";
            }

        echo $out;

    }

    echo "</div>";

}
?>

So what's happening above (as I understand it) is that it's fetching the children of /albums/ which results in three albums. It runs through each one "as $album" and within that it runs through all the items in the album's $gallery field, then loops back and repeats for each album.

If I add my pagination limit in the initial find() call, it's actually just limiting the number of albums display. Since my desired thumbnail limit is 30 per page and there are three albums this is moot (aside from not being what I want).

If I were to limit within the "as $album" call, or deeper, would it not limit the items displayed from each album, but not necessarily result in pagination in the resulting web page that would lead me to additional pages of thumbnails?

So my question is: 

What syntax (and where) do I use to paginate the code above to display a maximum of 30 gallery thumbnail images, total, from three albums per page?

Ideally I'd also like to order them so that the newest images appear first, exclusive of what album they are from.

I should note I'm following the gallery tutorial from the wiki and I am more than happy to use different code in my function entirely if it achieves the goal more directly.

Thanks a bunch in advance!

Link to comment
Share on other sites

Thanks for that link, Wanze! I think it's close to what I'm looking for, though it does seem to rely on getting to the images without the two additional levels I'm implementing in my function right now.

It seems like this is the function I need to focus on (thanks to Ryan):

<?php

// get the images you are going to display
$items_per_page = 4;
$start = ($input->pageNum - 1) * $items_per_page;
$total = count($page->images);
$images = $page->images->slice($start, $items_per_page);

// make this to give MarkupPagerNav what it needs
$a = new PageArray();

// add in some generic placeholder pages
foreach($images as $unused) $a->add(new Page());

// tell the PageArray some details it needs for pagination
// (something that PW usually does internally, for pages it loads)
$a->setTotal($total);
$a->setLimit($items_per_page);
$a->setStart($start);

// output your images
foreach($images as $p) {
   $img = $p->img;
   echo "<img src='{$img->url}' alt='{$img->description}' />";
}

// output the pagination navigation
echo $a->renderPager();

...but I'm still unclear on how to build an array from the combined gallery fields of multiple albums. I'm going to play around with it a bit and report back.

Link to comment
Share on other sites

creativejay,

Welcome to PW! Just to make sure we understand what you are after...Is the following your situation?

Example Tree

gallery (parent page)

Album A (child with 100 images)

Album B (50 images)

Album C (75 images)

 

You want to grab a total of 30 images from Albums A - C and display them on the page gallery?  Do you want to grab random images? I know you want to sort them by the latest (i.e. sort=-date). Do you want to grab the same number of images from each album? i.e. 10 each?

I'm just trying to wrap my head round what you want to accomplish. Ryan's code above was for a situation where all the images were on one page (i.e. no child pages).

Link to comment
Share on other sites

Thanks kongondo!

This follows the gallery tutorial in the wiki, so the structure is actually:

Example Tree

portfolio (solo page no children)

albums (parent page - hidden)

bridal (child with 50 images in field "gallery")

theatrical (child with 4 images in field "gallery")

runway (child with 10 images in field "gallery")

 

What I want to do is, from the page "portfolio," create an array with the total number of images in all the $gallery fields in the child pages of "albums" (so in this example, 64 images), then sort and paginate the newly created array to display 30 per page, with page 1 holding the newest images and the last page holding the oldest images.

At the top of the "portfolio" page, once I conquered this, my plan was to include links to the individual pages, with their own internal pagination. It would feel, to the visitor, as though you were filtering the entire portfolio by category and a "clear filter" type button would actually be a link back to "portfolio."

Please feel free not to just suggest code for the way I have it structured in the example site tree I give above, but any other structure that might make more sense! I just followed the wiki when I originally set this up.

Link to comment
Share on other sites

Your special need is that you want to sort the images of all the galleries by date.

This should be possible with the newest version 2.3.0 of Pw

Files and images are now date/time stamped for both creation and modification time. You can query these from selectors by the file's "created" and "modified" properties.

So Something like this should work, allthought I've not tested anything:

// Load all the images of all galleries, sorted by create date
$allImages = new PageArray();
foreach ($pages->find('parent=/albumbs/') as $gal) {
  $allImages->import($gal->gallery);
}
// Sort the images by created DESC
$allImages->sort('-created');

// get the images you are going to display
$items_per_page = 4;
$start = ($input->pageNum - 1) * $items_per_page;
$total = count($allImages);
$images = $allImages->slice($start, $items_per_page);

// ... same as in ryans example from here on

Does it work?

Edit: Don't forget to enable page numbers in the template settings of the template where you are running the code :)

Link to comment
Share on other sites

Thanks for that start, Wanze!

So here's where my code is currently:

function galleryMain() {
	// Load all the images of all galleries, sorted by create date
	echo "<div class='albumgrid'>";
	$allImages = new PageArray();
	foreach(wire("pages")->find('has_parent=/albums/') as $gal) {
		$allImages->import($gal->gallery);
		echo "Created an array from a page<br />";
	}
	
	// Sort the images by created DESC
	$allImages->sort('-created');
	echo "Sorted images <br />";
	  
	// get the images you are going to display
	$items_per_page = 4;
	$start = ($input->pageNum - 1) * $items_per_page;
	$total = count($allImages);
	echo $total . ' images counted<br />';
	$images = $allImages->slice($start, $items_per_page);
	echo "Defined pagination math <br />";

	// make this to give MarkupPagerNav what it needs
	$a = new PageArray();
	echo "Created a new page array to hold everything <br />";
	
	// add in some generic placeholder pages
	foreach($images as $unused) $a->add(new Page());
	echo "Created a new page in the array for each slice of total image count<br />";
		
	// tell the PageArray some details it needs for pagination
	// (something that PW usually does internally, for pages it loads)
	$a->setTotal($total);
	$a->setLimit($items_per_page);
	$a->setStart($start);
	echo "Delivered PageArray details for Pagination <br />";
	$thumbsize = 140;
	echo "Set thumbsize value <br />";
	
	// output your images
	foreach($images as $p) {
		echo "Beginning Image Output <br />";
		$img = $p->img;
		echo "<a href='{$img->url}' title='{$img->description}' class='fancybox-button' rel='fancybox-button'><img src='{$img->size($thumbsize, $thumbsize)->url}' style='margin-right: 15px; margin-bottom:25px; border: solid 1px #000000;' height='{$thumbsize}' width='{$thumbsize}'></a>";
	}

	// output the pagination navigation
	echo $a->renderPager();

	echo "Rendered Pagination <br />";
	echo "</div>";
}

Using my echoes I can see that there are no images in the allImages array, so I think this section needs some tweaking:

foreach(wire("pages")->find('has_parent=/albums/') as $gal) {
		$allImages->import($gal->gallery);
		echo "Created an array from a page<br />";
	}

(I tried it with parent and has_parent and neither worked but I believe has_parent is correct)

I'll look at it again after lunch but if someone else has keener eyes than I do, that's where it stands at the moment.

Thanks everyone!

Link to comment
Share on other sites

You could use my ImagesManager module which is made for use cases like a photo portfolio. Every image is created as a page and each gallery would be a category.

It would be a childs play to setup pagination and searching. Plus you can have as much meta data added as you like and all is searchable same as with using pages.

  • Like 1
Link to comment
Share on other sites

Using my echoes I can see that there are no images in the allImages array, so I think this section needs some tweaking:

Aren't you going throgh the loop? Or is it just the array that is empty?

Another possible way to get your galleries:

foreach ($pages->get('/albums/')->children() as $gal) {
  //..
}
Link to comment
Share on other sites

It could work but Pageimages requires a page context.

Also with this technic you load all images on every request just to display a couple which doesnt scale so nice. Using ImagesManager would solve those issues and give more flexibility. /advertising :-)

Link to comment
Share on other sites

....Using ImagesManager would solve those issues and give more flexibility. /advertising :-)

"Shameless plug"!  :P

Wasn't the idea not to piggyback on MarkupPagerNav module, hence "enable" pagination?

So here's another option, which is to piggyback onto the MarkupPagerNav module, even though you aren't dealing with pages.

http://processwire.com/talk/topic/390-images-pagination/?p=2928

I'd still go for the ready-made IM solution though :)

Link to comment
Share on other sites

It could work but Pageimages requires a page context.

Why? Pageimages are a collection of Pageimage objects. And Pageimages extends Pagefiles extends WireArray, so the import() should work.

But I haven't tested anything to be honest :)

Edit. Pageimages also doesnt support pagination.. only pagearrays.

Yep. But if you look at ryans code, there's another Pagearray created for the Paging - not the array containing the images.

But of course: Using ImagesManager is better, and loading all images to display only 30 is not very efficient. Though there's no other solution IMO if they need to be sorted date-based from different pages :)

Link to comment
Share on other sites

Yes right, of course the Pageimages is a WireArray, and it looks like you can import Pageimage (but I'd rather say add()), and considering we're dealing with Pageimage here already taken from pages it would work as the page context is already present. But I still think you need also a page you associate the Pageimages() as with Pagefiles() requires a Page in the construct, so maybe adding a empty page would work on the fly. But yeah ImagesManager is better. ;)

Link to comment
Share on other sites

If you take it now. You'll get two stock free images and a T-Shirt for free! 

Ha ha, I'll just be happy if it's what I've been hoping for!

It was the Gallery module for MODX that drove me away (I am hosted on a shared server), since it was actively scanning the folders in my directory and displaying the images (and creating new thumbnails) each time. My host was very patient (though stern) but I ran out of time to work on the problem and kept finding forum posts about how it's insane to try and host Revo on a shared server, so I went looking for better solutions and wound up here! I like the flexibility and the promise that I'll be able to use my brain cells on php again. And just in time, I have a project that's probably 85% finished in MODX but I'm more than willing to start over in PW if it's going to be kinder to my server. ImagesManager looks like a big step in the right direction.

Link to comment
Share on other sites

  • 2 years later...

I went another way, don't know why but those others felt a little more hacky, maybe I still don't understand enough in this fields..
 
Maybe someone got improvements or is just interested in using another approach here it is:
 

$limit = 42;
$current_page = $input->pageNum ? : 1;
$start = ($current_page - 1) * $limit;

// I'm joining pages table because I needed only images from certain templates in this case tpl_id 44 & 52
// and I'm sorting by page published date
// if you don't need this context you could of course go without the join
$images = $database->prepare('SELECT i.pages_id, i.data, i.description, i.tags
FROM field_images AS i
LEFT JOIN pages AS p
ON p.id = i.pages_id
WHERE p.templates_id IN (44,52)
ORDER BY p.published DESC,
i.sort ASC
LIMIT :start, :limit
');
$images->bindValue(':start', (int)$start, PDO::PARAM_INT);
$images->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
// I tried to pass the params via the execute, but somehow I couldn't get it working, he wouldn't treat them as integer, even though some people are doing it..?!
$images->execute();

while ($rawImage = $images->fetch(PDO::FETCH_OBJ)) {
// for easier image handling I turn the raw data into an actual Pageimage
$p = $pages->get($rawImage->pages_id); $i = new Pageimage($p->images, $rawImage->data); // create whatever markup you prefer for your gallery } // Just read about "SQL_CALC_FOUND_ROWS" here http://stackoverflow.com/a/12887293/3484824 $totalImages = $database->query('SELECT count(*) FROM field_images AS i LEFT JOIN pages AS p ON p.id = i.pages_id WHERE p.templates_id IN (44,52)'); $totalImages = $totalImages->fetchColumn(); $totalPages = ceil($totalImages / $limit); // and the pager $content .= "<ul class='pagination'>"; if ($input->pageNum > 1) { $prevPage = $input->pageNum > 2 ? $page->url . 'page' . ($input->pageNum - 1) : $page->url; $content .= "<li class='pagination__item'><a href='$prevPage'>prev</a></li>"; } for ($i = 1; $i < $totalPages; $i++) { $pagerPage = $i === 1 ? '' : "page$i"; $current = $input->pageNum === $i ? ' pagination__item--current' : ''; $content .= "<li class='pagination__item{$current}'><a href='{$page->url}{$pagerPage}'>$i</a></li>"; } if ($input->pageNum < $totalPages) { $nextPage = $page->url . 'page' . ($input->pageNum + 1); $content .= "<li class='pagination__item'><a href='$nextPage'>next</a></li>"; } $content .= "</ul>";

So far so good, hope you enjoy this peace of code and improvements, tips and tricks are always welcome as I'm still learning

  • Like 1
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

×
×
  • Create New...