Featured Post on 1st page + pagination from Controller

Hi - over the years I’ve done this multiple ways, but I want to get a decent setup using controllers in sage 9. for some reason the solution eludes me!

I have an archive page displaying (eg) 12 posts. When the archive is on page one I want to pull out a featured post, but keep a grid of 12 below.

So if not paged = 13posts (12 + the one featured) if paged 12

in my archive controller:

public static function archiveItems()
    {
        global $posts;
        return array_map(function ($post) {
            return [
                'title' => get_the_title($post->ID),
            ];
            }, $posts);
    }

and in template (index or archive whatever):

@foreach(Archive::archiveItems() as $newsItem)
  @include('partials.content-news', ['data' => $newsItem])
@endforeach

I tried:

@foreach(Archive::archiveItems() as $i => $newsItem)
          @if ($i == 0)
            <li class="feature">
              @include('partials.content-news', ['data' => $newsItem])
            </li>
          @else
            <li class="not-feature">
                @include('partials.content-news', ['data' => $newsItem])
            </li>
          @endif
@endforeach

(+conditioals for is paged etc)
but that is obviously putting logic in the template when the (number of) posts has already been returned from the controller. So i’d probably want to look at pre_get_posts? - but not sure how to fit that in with the controller method?

Thanks!

Hi @chrisk2020 - with something like this you may be worrying too much about having a little logic there.

Two options that come to mind: use a method in your controller to get the class name, or keep the logic in your template but just clean it up a little.

For option #1, you’d just put the logic for determining the class to use (feature or not feature) in a method in your controller and then echo the output of that method in your class attribute.

For option #2, you’d just do something like this (not tested):

@foreach(Archive::archiveItems() as $i => $newsItem)
            <li class="{{ $i == 0 ? 'feature' : 'not-feature' }}">
              @include('partials.content-news', ['data' => $newsItem])
            </li>
@endforeach

Hi - Thanks - that wasn’t really the issue I was having. My question was more about how to return 13 posts on the first page of pagination and 12 on the next.

In the end I did it like this:
in archive.php controller

public static function archiveItems()
    {
        $paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : '1';
        $posts = get_posts([
            'posts_per_page' => $paged > 0 ? 13 : 12,
            'post_type' => 'post',
            'paged' => $paged,
        ]);

        return array_map(function ($post) {
            global $paged;
            return [
                'title' => get_the_title($post->ID),
                'permalink' => get_permalink($post->ID),
                'id' => $post->ID,
                'category' => get_the_category($post->ID),
                'is_firstpage' => $paged == 0,
            ];
            }, $posts);
    }

In the template:

@foreach(Archive::archiveItems() as $i => $item)

            @if ($item['is_firstpage'] && $i == 0)
              <li class="list__item--feature">
                @include('partials.content', ['data' => $item])
              </li>
            @else
              <li class="list__item">
                @include('partials.content', ['data' => $item])
              </li>
            @endif

@endforeach

could use a ternary in there - preference I guess :slight_smile:

1 Like