3

I've been given a site and asked to prevent visitors from seeing the news archive beyond page 6.

The navigation has already been done, but if the user manually enters example.com/news/p7 they'll see it.

Here’s my template code:

{% set entries = craft.entries.section('news').limit(3) %}
{% paginate entries as entries %}
    {% for entry in entries %}
        {% include '_elements/_news-entry' %}
    {% endfor %}
    {% include '_elements/_pagination' %}
{% endpaginate %}

The _elements/_pagination include:

<nav class="pagination">
{% for page, url in paginate.getPrevUrls(5) %}
    <a href="{{ url  }}" class="button">{{ page }}</a>
{% endfor %}

<strong>{{ paginate.currentPage }}</strong>

{% for page, url in paginate.getNextUrls(5) %}
    <a href="{{ url  }}" class="button">{{ page }}</a>
{% endfor %}
</nav>

I tried adding the following to /craft/config/routes.php, but it doesn't appear to have any effect.

'news/p[^1-6]' => '404',
3

First, I don’t think your pagination navigation is limiting to just 6 pages like you think it is. The number you pass into paginate.getPrevUrls() and paginate.getNextUrls() will determine how many URLs the functions should return. So if you’re on the 3rd page, calling paginate.getNextUrls(5) will give you the URLs for pages 4-8.

Navigation-wise, what you’re probably better off using is paginate.getRangeUrls(), which accepts explicit first/last page numbers:

{% for page, url in paginate.getRangeUrls(1, 6) %}
    {% if page == paginate.currentPage %}
        <strong>{{ page }}</strong>
    {% else %}
        <a href="{{ url }}" class="button">{{ page }}</a>
    {% endif %}
{% endfor %}

(You can get a full breakdown of the properties/functions within that paginate variable here: http://buildwithcraft.com/docs/templating/paginate#the-paginate-variable)

Even with that change, you’re not actually enforcing that only 6 pages are available; there’s still nothing stopping a user from manually going to http://example.com/news/p7. The would still get the 7th page of news entries, with an awkward pagination navigation, because it would just show links to pages 1-6 with no indication that you’re on the 7th page.

So back to your original question: how do we enforce a 6-page maximum?

Your idea of setting a route in craft/config/routes.php was a good one, but unfortunately Craft actually removes the “page” part of the URL from its internal path before it starts checking the path for matching routes.

Because of that, your best option here is to enforce it from the actual News template.

You can access the current page using craft.request.getPageNum(), so let’s just check for that at the very top of your template, and if it’s greater than 6, return a 404 using the {% exit %} tag:

{% if craft.request.getPageNum() > 6 %}
    {% exit 404 %}
{% endif %}

To clean things up a bit, you might want to store that maximum number of News entries as a variable within your template, or maybe even as a 'maxNewsPages' custom config variable in craft/config/general.php.

{# Pull the custom 'maxNewsPages' config setting from craft/config/general.php #}
{% set maxPages = craft.config.maxNewsPages %}

{# Enforce it #}
{% if craft.request.getPageNum() > maxPages %}
    {% exit 404 %}
{% endif %}

...

{% for page, url in paginate.getRangeUrls(1, maxPages) %}
    {% if page == paginate.currentPage %}
        <strong>{{ page }}</strong>
    {% else %}
        <a href="{{ url }}" class="button">{{ page }}</a>
    {% endif %}
{% endfor %}
  • Wow, a perfect answer - thank you hugely Brandon! – jezmck Oct 23 '14 at 10:03
  • For the record, none of the existing code was mine in the first place, it's just been given to me. – jezmck Oct 23 '14 at 10:04
  • @jezmck Glad that helps! The old code probably worked fine for the previous requirements :) – Brandon Kelly Oct 23 '14 at 10:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.