32

Tip: To keep it short and reusable I would recommend that you wrap your preferred "check-method" in a Twig macro, I like Anna's version the most: _macros.html: {% macro is_active(segment) %}{% if craft.request.firstSegment == segment %}active{% endif %}{% endmacro %} layout.html: {% import "_macros.html" as macros %} <a href="{{ url('news') }}" class=...


30

Assuming you use a structure called pages to create your navigation and the entry variable represents the currently viewed entry, you can output your navigation and active state as follows: <ul> {% nav page in craft.entries.section('pages') %} <li class="{{ page.id == entry.id ? 'active' }}"> {{ page.link }} {% ifchildren %} ...


17

There's a couple of special variables available while for looping through an array. In your case I'd make use of loop.last. {{ tag }}{{ not loop.last ? ', ' }} This is the expression using the ternary operator to keep the syntax short.


17

Twig != is a comparison operator. The following comparison operators are supported in any expression: ==, !=, <, >, >=, and <= You can use != to compare any two things that php lets you compare, and what you get back is a boolean. Twig not is a logic operator. (so are and and or) not: Negates a statement.


15

You could first set a variable to test against and then change it the first time the block type appears. {% set firstTime = true %} {% for block in entry.matrixField %} {% if block.type == "text" and firstTime == true %} ...Do something once... {% set firstTime = false %} {% endif %} {% endfor %}


14

craft.request is useful for setting an "active" class based on URL segments. If your URL was: domain.com/sale/products/shirts You could write conditionals like the following to target each segment: {% if craft.request.firstSegment == "sale" %}class="active"{% endif %} {% if craft.request.segment(2) == "products" %}class="active"{% endif %} {% if craft....


13

Instead of using the divisibleby-function you can use the batch-filter: {% for row in entriesInYear|batch(2) %} <div class="row"> {% for entry in row %} <div class="block_txt"></div> {% endfor %} </div> {% endfor %} If you have 3 entries in entriesInYear this code would output: <div class="row"> <div ...


13

You can set a cookie from your template, which assigns visitors to specific groups: Craft 2: (Use the LJ Cookies plugin) {% set testGroup = craft.lj_cookies.get('group') %} {% if not testGroup %} {# New user - assign them to a group at random #} {% set testGroup = random(['a', 'b']) %} {% set expires = now|date_modify('+30 days').timestamp %} ...


12

Barrel Strength also have a URL segment based plugin called Sprout Active, with docs/examples here.


12

I've had luck using "is defined" before using other logic operators. This should do it: {% if entry.title is defined and entry.title | length == 0 %} {% set entry = craft.entries.section('sectionname').slug(craft.request.segment(2)).first() %} {% endif %}


12

There are several ways you could attack this, but probably the easiest is directly from the SQL side with something like this using a SQL CASE statement: {% set entries = craft.entries.section('news').order('(CASE WHEN field_alphaTitle IS NULL OR field_alphaTitle = "" THEN title ELSE field_AlphaTitle END)').find() %} <ul> {% for entry in entries %...


11

The Containment Operator helps with this... It returns true if the left operand is contained in the right {% if craft.request.getSegment(2) in ['knowledge', 'search'] %} OR {% if craft.request.getSegment(2) not in ['', 'sale'] %}


11

You want: {% if craft.request.firstSegment == 'This' or craft.request.firstSegment == 'That' %} or this would work: {% if craft.request.firstSegment in ['This', 'That'] %}


11

First, you should create a dynamic route (something like "games/glossary/<slug>") and point it to a template. A dynamic route means you won't have to create a template for every letter. Note the use of the <slug> token, which – although not entirely semantic – should do nicely in this case. In your template, you'll need to pull the letter from ...


10

If you wish to use divisibleby to solve this problem, the key is in how you use the loop.index and loop.index0 variables. loop.index counts the iterations in your loop starting with the number 1 loop.index0 counts the iterations in your loop starting with the number 0 You can test this with an odd number of items using the range function: {# Loop 3 times ...


10

In your template you can set a var in twig: {% set active = 'blog' %} And then in your navigation you can run an if statement to see what the var is <nav> <a {% if active = 'homepage' %}class="active"{% endif %}> Home </a> <a {% if active = 'blog' %} class="active"{% endif %}> Blog </a> </nav>


10

You're close! SectionModel has 'name' and 'handle' attributes and one of those is probably what you're looking for. {% if entry.section.handle == 'lettings' %} {{ entry.rentFrequency.label }} {% endif %}


9

Here's yet another way you can do it (in some circumstances) and it's nice and DRY: Craft 2 {% if craft.request.getPath() == entry.uri %} Craft 3 {% if craft.app.request.pathInfo == entry.uri %}


9

An alternative, if you are getting the tags from the Tag Field type, is the Join filter: {% if post.tags | length %} Tags: {{ post.tags | join(', ') }} {% endif %}


9

From PHP: if (craft()->request->getIpAddress() == '255.255.255.255') { ... } Note from the docs that this is a "best guess" and can easily be spoofed, so you shouldn't use it to hide any sensitive information. We currently don't expose that method at the template level, but we probably should. I'll add that on the Craft 2.3 branch. If you want ...


9

According to the docs, the userModel.isInGroup() method takes a "user group model, its handle, or ID" – in other words, it can only test for membership in a single group, not several. What you want in this case is the or operator: {% if currentUser and (currentUser.isInGroup('userGroup1') or currentUser.isInGroup('userGroup2')) %} {# secret content #} {...


8

Fun question! :) You can use getNext() and getPrev() Methods on the MatrixBlockModel documentation page. {% for point in entry.keyPoints %} {# if this is the "typeToWrap" block type #} {% if point.type == 'typeToWrap' %} {# if there is a previous point to check #} {% if point.getPrev() %} {# if the previous point wasn'...


8

Alright, I was able to figure it out myself: channel{% if object.type == 'xyz' %}/{type}{% endif %}/{slug} produces the desired results. The section for Dynamic Entry Titles in the docs pointed me into the right direction.


8

This looks like a situation where you might get away with just using Twig's default filter: {{ entry.metaTitle|default(title|default(siteName)) }} It works even with undefined or empty strings, and methods that don't exist on objects that might not be defined themselves.


8

It depends. Technically to determine if a variable is not empty (keep in mind '0' or 'false' are not considered empty), you can use Twig's 'is not empty': {% if entry.myField is not empty %}...{% endif %} But in most situations where '0' and/or 'false' are not expected values, then anything that evaluates to '0', 'false' or 'null' will also work. So, {% ...


8

For your example, you should exclude the fictional towns in the initial query itself rather than filtering them out afterwards: {% set towns = craft.entries.section('towns').townFictional('not 1').relatedTo(counties) %} So that no towns with the Fictional Lightswitch on will be returned from the database at all. You would use the |without filter, if you ...


7

Another way to achieve this: {% for entry in entries %} {% set active = craft.request.path ~ '/' matches "|^#{entry.uri}/|" %} <a href="{{ entry.url }}" class="{{ active ? 'is-active' : '' }}">{{ entry.title }}</a> {% endfor %} This accounts for even when a navigation item might not be on the top level, but you want every ...


7

You can do that by using the next parameter... {% for block in entry.myMatrixField %} {% if block.next %} <p>Next block type is: {{ block.next.type }}</p> {% endif %} {% endfor %} It's important to check {% if block.next %}, because the last block won't have a "next". If you were to try to call block.next.type where there is no "...


7

To make use of your visitors IP address, use {{ craft.request.getIpAddress() }} in Craft 2.5. In Craft 3.x, there is {{ craft.app.request.userIP }}.


7

Thanks to Brad for the answer, and the solution was to use {% if entry.mainImage|length %} instead of {% if entry.mainImage %} for the conditional. So my working code looked like this: {% if entry.mainImage|length %} {% for asset in entry.mainImage %} <img src="{{ asset.url }}" alt="{{ asset.title }}" /> {% endfor %} {% else %} <img src="...


Only top voted, non community-wiki answers of a minimum length are eligible