You're bumping into a Twig gotcha: you can't conditionally extend a template. Either a template extends another template (i.e. it has an {% extends %}
tag in it) or it doesn't. It doesn't matter if the {% extends %}
statement is inside an {% if %}
statement.
The solution is to create an additional layout template – e.g. _ajax.html
– and use a ternary operator to have your entry template extend one or the other, before putting the conditional that loads either the content or the call to entryCount.increment
inside the {% block content %}
. Note that for your purposes, the _ajax.html
template can be completely blank, except of course for the {% block content %}{% endblock %}
). Also note that since we now need to test if the request is an Ajax request twice, it makes sense to cache the test to a variable isAjax
:
{% set isAjax = craft.request.isAjax and not craft.request.isLivePreview %}
{% extends not isAjax ? '_layout' : '_ajax' %}
{% block content %}
{% if not isAjax %}
{# CONTENT GOES HERE #}
{% else %}
{% do craft.entryCount.increment(entry.id) %}
{% endif %}
{% endblock %}
Not very elegant, is it? A better option might be to create a different endpoint for incrementing the counter entirely, negating the need to create an additional layout template and to wrap most of your content in a conditional. To create a dedicated endpoint for incrementing the counter, you can create a dynamic route. Make sure the route contains a <number>
token, which will hold your entry ID (the route could just be count/<number>
, for instance). Have the route point to a new template called _count.html
or the like, and put the following in that template:
{% do craft.entryCount.increment(number) %}
You'll have to expose the current entry's ID to your JavaScript somehow, but that's easily done by setting a data attribute somewhere in your markup – e.g.
<body data-entryid="{{ entry.id }}">
Then, you just need to use jQuery or the like to issue a request to http://yourwebsite.com/count:
$.ajax('/count/'+$('body').data('entryid'));
Closing thought: So long as you "don't need to actually pickup any data or show it", I'm curious why you couldn't just request the basic template as-is. As long as the template contains the call to entryCount.increment
somewhere inside the {% block content %}
block, does it really matter if it loads the full layout behind the scenes? Sure, there's a little overhead, but it's way less work and probably doesn't matter that much in the scheme of things.