Template TypesArchive & Search Templates

Archive & Search Templates

How to build custom archive layouts and a custom search results page using the Protuno Theme Builder and the get_posts loop.

Archive templates control the layout of category archives, tag archives, author archives, date archives, and custom taxonomy archives. A Search Results template controls what visitors see after they submit a search query. Both use Protuno's loop system to render lists of matching posts.

The Theme Builder is a Protuno Pro feature.

Create An Archive Template

  1. Go to Protuno → Theme Builder
  2. Click + Add New → Archive (or Search Results for search)
  3. Drag the Proton widget onto the canvas
  4. Build your archive layout
  5. Click Update to save
  6. Set display conditions

The term Provider In Archive Templates

On taxonomy archive pages (category, tag, custom taxonomy), the term Twig provider resolves to the current archive term:

<header class="archive-header pr-boxed">
  <span class="text-label">Category</span>
  <h1 class="text-heading-h1">{{ term.name }}</h1>
  {% if term.description %}
    <p class="archive-description">{{ term.description }}</p>
  {% endif %}
  <p class="text-body-sm">{{ term.count }} articles</p>
</header>

On author archive pages, use the user provider:

<h1>Posts by {{ user.name }}</h1>
<img src="{{ user.avatar('80') }}" alt="{{ user.name }}">

The Post Loop

Use get_posts with paged: current_page() to render the archive's posts:

<section class="archive-grid pr-boxed">
  <div class="pr-grid-3">
    {% for post in get_posts({
      post_type: 'post',
      posts_per_page: 9,
      paged: current_page()
    }) %}
      <article class="pr-blog-card">
        <a href="{{ post.link }}">
          <img 
            src="{{ post.thumbnail.src('medium') }}" 
            alt="{{ post.thumbnail.alt }}"
          >
        </a>
        <div class="card-body">
          <span class="text-label">{{ post.categories.name }}</span>
          <h2 class="text-heading-h4">{{ post.title }}</h2>
          <p>{{ post.excerpt|truncate(100) }}</p>
          <a href="{{ post.link }}" class="text-label">Read More →</a>
        </div>
      </article>
    {% endfor %}
  </div>

  {{ loop_pagination()|raw }}
</section>

current_page() reads the current page number from the URL (?loop_page=N). loop_pagination() renders numbered page navigation links.


Display Conditions For Archives

ConditionWhat it covers
Post Category (any category)All category archive pages
Post Category → specific termOne specific category's archive
Post Tag (any tag)All tag archive pages
Author ArchiveAll author archive pages
Date ArchiveDate-based archive pages

To apply one archive template to all categories and another to a specific category, use two templates:

  • Template A: Include → Post Category (any), broad
  • Template B: Include → Post Category → "News", specific (wins for the News category)

Search Results Template

The search results template uses request.get('s') to access the search query, and get_posts with the s parameter to fetch matching results:

<section class="search-results pr-boxed">
  <header class="search-header">
    <h1 class="text-heading-h2">
      {% if request.get('s') %}
        Results for "{{ request.get('s') }}"
      {% else %}
        Search
      {% endif %}
    </h1>
  </header>

  {% set results = get_posts({
    post_type: 'any',
    posts_per_page: 10,
    s: request.get('s'),
    paged: current_page()
  }) %}

  {% if results %}
    <div class="results-list">
      {% for post in results %}
        <article class="result-item">
          <h2 class="text-heading-h4">
            <a href="{{ post.link }}">{{ post.title }}</a>
          </h2>
          <p>{{ post.excerpt|truncate(150) }}</p>
          <span class="text-label">{{ post.date|date('F j, Y') }}</span>
        </article>
      {% endfor %}
    </div>
    {{ loop_pagination()|raw }}
  {% else %}
    <p class="no-results">No results found for "{{ request.get('s') }}".</p>
    <p>Try different keywords, or browse by <a href="/categories">category</a>.</p>
  {% endif %}
</section>

Display condition for search: Include → Search Results.


Tips

Filtering by the current term in loop: On a category archive, pass the current term to get_posts using tax_query. Get the current term slug from term.slug:

{% for post in get_posts({
  post_type: 'post',
  posts_per_page: 9,
  paged: current_page(),
  tax_query: [{
    taxonomy: 'category',
    field: 'slug',
    terms: [term.slug]
  }]
}) %}

Empty archive state: Add {% if %}...{% else %}...{% endif %} around your loop to show a "no posts" message when the archive is empty.