2

I can't stand this and have to ask for help again.. Still working on my buddy's website.

I want to increase a entry's counter (using Entry Count plugin) So for my _entry.html I added an if statement to see if the request is for Ajax or not. If not, show the entire page. If it is only run the counter twig line.

_entry.html

{% if not craft.request.isAjax and not craft.request.isLivePreview %}
    {% extends "_layout" %}
    {% set title = entry.title|t %}

{% block content %}
 {# CONTENT GOES HERE #}
{% endblock %}

{% else %}
    {# ONLY INCREASE THE VIEWS/COUNT #}
    {% do craft.entryCount.increment(entry.id) %}
{% endif %}

Javascript on main page

$.get($(this).attr('data-url-item'), function(data) {
console.log(data);
});

Now I don't need to actually pickup any data or show it, so I'm using $.get() currently have the console.log() there so I can see which version of the page I'm getting.

Any help is appreciated.

  • Also, how this currently works is that the direct url works fine. the $.get() gets the same page (entire HTML/resources) instead of the nothing it should get back (but do activate that twig upon load.) – Kitsune Jul 10 '16 at 19:12
2

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.

| improve this answer | |
  • First off, thank you for your suggested solution, I'll dig my face into it in a sec. I figured it would just be more efficient if it did not load any unnecessary data just to register a view (to explain why. I open a modal with the item's info, instead of loading a new page. But also leave the possibility to share and therefor end up on a single page view of the item.) And currently the opening animation lags as the page is loaded through the $.get() I'm pretty sure it wont do this if it does not get an entire page as a respons. – Kitsune Jul 11 '16 at 20:32
  • Whatever happens serverside shouldn't affect the performance of your front end code and as long as you don't add any callbacks (i.e. success, error, complete etc), the $.ajax call won't hog any client side resources at all – in other words, yes, if you only call the do statement you will use (marginally) less resources serverside, but it won't have any impact on your animation performance whatsoever. – Mats Mikkel Rummelhoff Jul 11 '16 at 20:39
  • Come to think of it, I'm not sure if $.get allows not having a success callback, but $.ajax definitely does. – Mats Mikkel Rummelhoff Jul 11 '16 at 20:41
  • I'm not expert on that. But if I console.log(data); i see the entire raw HTML. doesn't that load a lot slower than just a little message (from the increase count bit)? I tried with $.ajax too (first attempt.) What I can say is that it does take a moment to load, I'd rather it would just increase the count through a request alone. Using the $.get() right? – Kitsune Jul 11 '16 at 20:42
  • Right, but that console.log could very well be the reason for the lag by itself :) Just remove the callback entirely. You're not going to use the returned data either way, so you don't need a callback. – Mats Mikkel Rummelhoff Jul 11 '16 at 20:44

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.