Jump to content

List pages by year (similar to blog archive)


cb2004
 Share

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
Link to comment
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.

Link to comment
Share on other sites

  • 1 month later...
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
Link to comment
Share on other sites

  • 6 months later...

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?

Link to comment
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. 

Link to comment
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 2
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...