1

I would like to show new content to users since their last visit, and a bit confused about the best approach. I'm thinking I should use the Cookies plugin and something like this:

{% if not getSecureCookie('now') %}
  {% do setSecureCookie('now', 'now', now|date) %}
{% endif %}

~~

{% if entry.postDate > now %}
 New Content
{% endif %}

I understand this is wrong, but just looking for some guidance. How do I set a cookie for now and then check it on the next visit, and only show the new content? Any help much appreciated!

3

First, you want to always set the cookie to update it to the current date. Otherwise, the user will see content marked as new repeatedly. Also, setting 'now' as a string won't work – how will you know when 'now' is later on? Finally, make sure to use proper names to make your code easier to parse.

{# Add other parameters to the query here. #}
{% set entriesQuery = craft.entries() %}

{# Only show entries since the last visit if the user has visited before. #}
{% set last_visit = getCookie('last_visit') %}
{% if last_visit %}
    {% set last_visit_date = last_visit|date('Y-m-d') %}
    {% do entriesQuery.postDate("> #{last_visit_date}") %}
{% endif %}
{% set newEntries = entriesQuery.all() %}

This will find all available content if the user hasn't visited before, and only entries added after the last visit (according to the timestamp) if the user has visited before.

Finally, always update the last_visit cookie to store the current time, regardless of whether the user has visited the site before:

{% do setCookie('last_visit', now | atom, now | date_modify('+1 year') %}

Note the difference between 'now' and now. The latter is a global variable containing a DateTime object with the current time. The atom filter converts that to ISO-8601 for storage (you could also just store the timestamp or Y-m-d, not sure how picky the postDate parameter is). Finally, the third parameter makes sure the cookie will be stored for one year (you can increase that limit, obviously).

Add more parameters (path, domain) as needed. You may want to use secure=true and sameSite=none to allow this cookie to be sent on cross-origin requests as it's not security-related. See SameSite cookies explained.

Without a plugin

You can also accomplish this without a plugin, though it does get a bit more verbose:

{# Set a cookie using the Response object #}
{% set lastVisitCookie = create({
    class: 'yii\\web\\cookie',
    name: 'last_visit',
    value: now | atom,
}) %}
{% do craft.app.response.cookies.add(lastVisitCookie) %}

{# Read the existing cookie, if any #}
{% set last_visit_cookie = craft.app.request.cookies.get('last_visit') %}
{% set last_visit = last_visit_cookie ? last_visit_cookie.value : null %}

Sidenote: Logged-in users

If your users are logged in, you can also use the lastLoginDate property of their user account to display new content. A bit more reliable than cookies since it's stored in the database and won't disappear when the visitor clears their cache.

1
  • 1
    Thanks for the extremely thorough reply!! Super helpful. Your sidenote is actually the solution I've gone for -- not sure how I didn't think to do something like that. But I will use the cookie part on another project too. Thanks!
    – brynli64
    Aug 21 at 1:46

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.