Different amount of posts on first category page

Hi there!

I am new to kirby and new to the forum and I hope someone can help me.

Is it possible to display a different amount of posts (one less to be specific) on the first page of a category?

This is my Code so far and ChatGPT had different ideas for solving this. But none of them worked.

<?php
  $categoryFilters = get('category');
  $tagFilters = get('tag');
  $unfiltered = $page->children()->listed();
  $postsPerPage = 2;
  $posts = $unfiltered
    ->when($categoryFilters, function($categoryFilters) {
      return $this->filterBy('category', $categoryFilters);
    })
    ->when($tagFilters, function($tagFilters) {
      return $this->filterBy('tag', $tagFilters);
    })
    ->paginate($postsPerPage);
  $pagination = $posts->pagination(); // $pagination neu zuweisen
  $categories = $unfiltered->pluck('category', ',', true);
  $tags = $unfiltered->pluck('tag', ',', true);
?>

Thanks in advance.

The easiest way to achieve this would probably be with a little hack:

Prepend a virtual page

$posts = $unfiltered
    ->when($categoryFilters, function($categoryFilters) {
      return $this->filterBy('category', $categoryFilters);
    })
    ->when($tagFilters, function($tagFilters) {
      return $this->filterBy('tag', $tagFilters);
    });
$posts = $posts->prepend(Page::Factory(['slug' => 'trash', 'template' => 'trash']);
$posts = $posts->paginate(postsPerPage);

When you loop through the posts, skip the one with the wrong template.

foreach ($posts as $post) {
  if ($post->intendedTemplate()->name() === 'trash') continue;
  // do stuff with the rest
}

Thanks for the quick reply. This helped kinda. But I figured out another solution to this and it works nicely.

<?php
  $categoryFilters = get('category');
  $tagFilters = get('tag');
  $unfiltered = $page->children()->listed();
  $postsPerPage = 2;
  $posts = $unfiltered
    ->when($categoryFilters, function($categoryFilters) {
      return $this->filterBy('category', $categoryFilters);
    })
    ->when($tagFilters, function($tagFilters) {
      return $this->filterBy('tag', $tagFilters);
    });
  $posts = $posts->paginate($postsPerPage);
  $pagination = $posts->pagination();
  $categories = $unfiltered->pluck('category', ',', true);
  $tags = $unfiltered->pluck('tag', ',', true);
  // Auf der ersten Seite einer Kategorie ein Beitrag weniger
  if ($categoryFilters && $pagination->page() === 1) {
      $posts = $posts->paginate(1);
  }
  // Auf der ersten Seite eines Schlagworts ein Beitrag weniger
  if ($tagFilters && $pagination->page() === 1) {
      $posts = $posts->paginate(1);
  }
?>

I doubt that the pagination links will still work

Yeah, well, it still kinda works. But it brought a new problem. It no longer shows the second post in the list. There is post no.1 on page 1 and if I click to the second page, it starts with post no.3.

Maybe I find a different solution.

A non-hacky way would be to group your posts, then paginate the groups, similar to what I suggested here, with the only difference that you need to find a grouping scheme that returns the first page in one group, and the following pages in chunks of two, for example based on index number

https://forum.getkirby.com/t/paginate-by-months/13886/8

For your example you could create a method like this in a model:

	public function groupIndex($collection) {
		
		//return $this->indexOf($collection);
		return $this->indexOf($collection) === 0 ? 'group0' :
			($this->indexOf($collection) % 2 !== 0 ? 'group' . ($this->indexOf($collection)) : 'group' . ($this->prev($collection)?->indexOf($collection)));
		
	}

Controller:

	$posts = $page->children()->listed()->group(fn($item) => $item->groupIndex($page->children()->listed()));
	$pagination = Pagination::For($posts, ['limit' => 1]);
	$posts = $posts->slice($pagination->offset(), $pagination->limit());

Then continue like in the example I linked to.