Jump to content
cb2004

List pages by year (similar to blog archive)

Recommended Posts

We had to add this to our latest project and I am happy to share here. I couldn't find anything on the forums for this so apologies if it has been done before. But there are always different ways of doing things:

$firstEntry = $pages->find("parent_id=1037, sort=date_1, limit=1");
foreach (range(date("Y"), date("Y", $pages->get("$firstEntry")->date_1)) as $year) {
	$start = strtotime(date("$year-01-01"));
	$end = strtotime(date("$year-12-31"));
	$count = $pages->count("parent_id=1037, date_1>=$start, date_1<=$end");
	if ($count > 0)
		echo '<li><a href="' . $page->parent->url . $year . '/">' . $year . '(' . $count . ')</a></li>';
}

So what is going on:

  • first of all, our pages were children, so we set the parent_id, and our date field is called date_1
  • we need to get the year of the oldest entry, so that happens with $firstEntry and a simple find
  • next we create an array using a range of years, we start with the current year, then we get the year from our $firstEntry (note: if you have an output format for your date set in the field settings you will want to use $pages->get("$firstEntry")->getUnformatted("date_1") within the foreach)
  • next we create a start date and end date for the year
  • we count if there are any entries for that year
  • if there are display them in a list

Your next step would be to create the $input->urlSegment code to display your pages.

  • Like 9

Share this post


Link to post
Share on other sites

This is very similar to what I used when creating a sidebar archive recently:

sidebar-archive.gif

It's ajax-loaded (plain JavaScript), and results are cached.

Btw, watch out when using cache on a multilanguage site because if you don't name the cache key differently for each language you'll get incorrect results. I use the language name as suffix, eg. 'archives' . $user->language->name in this case.

Share this post


Link to post
Share on other sites
On 1.9.2016 at 0:29 PM, cb2004 said:

We had to add this to our latest project and I am happy to share here. I couldn't find anything on the forums for this so apologies if it has been done before. But there are always different ways of doing things:


$firstEntry = $pages->find("parent_id=1037, sort=date_1, limit=1");
foreach (range(date("Y"), date("Y", $pages->get("$firstEntry")->date_1)) as $year) {
	$start = strtotime(date("$year-01-01"));
	$end = strtotime(date("$year-12-31"));
	$count = $pages->count("parent_id=1037, date_1>=$start, date_1<=$end");
	if ($count > 0)
		echo '<li><a href="' . $page->parent->url . $year . '/">' . $year . '(' . $count . ')</a></li>';
}

 

 

Anybody feeling adventures could use my (still a bit experimental) DatetimeAdvanced field. With that, the code gets a little more concise. The retrieval of the oldest page can be optimized a little with the findOne method when using PW >= 3.0.0:

$firstEntry = $pages->findOne("parent_id=1037, sort=date_1");
foreach (range(date("Y"), date("Y", $firstEntry->date_1)) as $year) {
	$count = $pages->count("parent_id=1037, date_1.year=$year");
	if ($count > 0)
		echo '<li><a href="' . $page->parent->url . $year . '/">' . $year . '(' . $count . ')</a></li>';
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for your solution, I've used your code and learned a bit about urlSegments in the process.

One question though. In testing, I created an article and set my date field to 2018, but it does not generate a list item as it does for the current and previous years. 

Is there an obvious reason for this I'm not seeing?

Share this post


Link to post
Share on other sites
5 hours ago, DonPachi said:

Thanks for your solution, I've used your code and learned a bit about urlSegments in the process.

One question though. In testing, I created an article and set my date field to 2018, but it does not generate a list item as it does for the current and previous years. 

Is there an obvious reason for this I'm not seeing?

In the foreach it is limiting the year ranges to the current year, and the year from the  $firstEntry. You would need to create a $lastEntry and edit the foreach. Let me know if you need a hand as I am currently on mobile so can help when I am back on desktop. 

Share this post


Link to post
Share on other sites

This is what I use. It groups items into an array with years as keys, then you iterate over them and display your output.

<?php
$items = $pages->find('selector');
$grouped = array_reduce($items->getArray(), function (WireArray $carry, Page $item) {
    $year = date('Y', $item->published);

    if (!$carry->has($year)) {
        $carry->set($year, new WireArray());
    }
    $carry->get($year)->add($item);
    return $carry;
}, new WireArray());

?>
<?php foreach ($grouped as $year => $yearItems): ?>
    <h2>Year: <?= $year ?></h2>
    <?php foreach ($yearItems as $item): ?>
        <!-- render your items of certain year here -->
        <?= $item->title ?>
    <?php endforeach; ?>
<?php endforeach; ?>
  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...