I’m having trouble setting up an additional category listing page from the one I have set with the Category URI Format and Template settings in my Category Site Settings. Specifically, I’m having trouble getting it to work on my site which has two locales.

I have one category group called “practices” and one structure section-type called “people.” I’m trying to create two different pages that each loops through all the entries for a particular category.

In other words, domain.com/people/practices/categoryA and domain.com/people/foo/practices/categoryA would both display all the “people” entries that belong to categoryA.

For my “practices” category group, I have the Category URIs to be people/practices/{slug} and the template to be people/_practices. Everything on this category listing page at domain.com/people/practices/categoryA works as intended.

I can also get the category listing page at domain.com/people/foo/practices/categoryA to work by using the last segment (which would be the category slug) and setting the category object by passing in the category slug like this:

{% set categorySlug = craft.app.request.segments|last %}
{% set category = craft.categories.slug(categorySlug).one() %}

However, this category listing page is throwing an error when I’m using it with my language switcher code, which uses:

{% if category is defined %}
    {% set entry = category %}
{% endif %}

{% set supportedSites = entry.getSupportedSites %}

<ul>
{% for siteForEntry in supportedSites %}
  {% if siteForEntry | length == 1 %}

    {# if category #}
    {% set site = craft.app.getSites.getSiteById(siteForEntry) %}
    {% set entryForOtherSite = craft.categories.id(entry.id).site(site).one() %}

  {% elseif siteForEntry | length == 2 %}
    {# if standard entry #}
    {% set site = craft.app.getSites.getSiteById(siteForEntry.siteId) %}
    {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}
  {% endif %}

  {% if site.id == entry.siteId %}
      {# This is the current language, mark it as active and don't retrieve its url #}
      <li class="current {{ site.language }}">{{site.name}}</li>
  {% else %}
      {# if it's not the current site, get the entry for this site #}
      <li class="{{ site.language }}"><a href="{{ entryForOtherSite.getUrl() }}">{{site.name}}</a</li>
  {% endif %}

{% endfor %}
</ul>

Specifically, I get the “Variable ‘entry’ does not exist” error. I’m not sure why I’m getting this error because I’m setting the “entry” variable with the “category” variable. This works with domain.com/people/practices/categoryA, but it’s not working for the other category listing page.

        {% if category is defined %}
            {% set entry = category %}
        {{ entry.id }}
        {% endif %}

Not sure what to do. I also set a route so that domain.com/people/foo/practices/{slug} loads the people/_practices template, but it still doesn’t work.

The reason it's not working is that domain.com/people/foo/practices/categoryA is not a match for the Category group's URI settings. Only urls that match people/practices/{slug} are going to have that category variable defined.

And this code:

{% if category is defined %}
    {% set entry = category %}
{% endif %}

... won't define an entry if there's no category defined.

If your People structure is a flat list (no nested children), you could create a URL rules like this:

'people/<person:{slug}>/practices/<category:{slug}>' => [
    'template' => 'test/4'
],

That would take a URI like domain.com/people/foo/practices/categoryA and use the people/_practices template and populate variables for person and category.

{{ person }}    {# foo #}
{{ category }}  {# categoryA #}

Then you could make an category query like this:

{% set cat = craft.categories().group('practices').slug(category).one() %}

{{ cat.title }}

But personally, I've found it easier to use query strings to filter a list instead of URL segments. You could possibly use a URL like this:

domain.com/people/foo?practice=categroyA

or...

domain.com/people/foo/practice?cat=categroyA

or even...

domain.com/people/practice?person=foo&cat=categroyA

Whichever works the most logically for your use case. Then use craft.app.request to pull the "categoryA" string from the URL:

{% set categorySlug = craft.app.request.getQueryParam('cat') ?? null %}

{% if categorySlug %}
  {{ categorySlug }}   {# "categoryA" #}
{% endif %}

Then use the categorySlug string in an entry or category query:

{% set cat = craft.categories().group('practices').slug(category).one() %}

Update

It's important to note, if you want a variable you set to be available in a layout template ({% extend %} tag), you need to define it outside of a {% block %} tag.

{% extends "_layouts/index" %}

{% set categorySlug = craft.app.request.getQueryParam('cat') ?? null %}

{% block content %}
  Content...
{% endblock %}

The categorySlug variable should now be available in the _layouts/index template context as well.

<body>
  <div class="language-switcher">
    {% if categorySlug is defined %}
      Yes it is!
    {% endif %}        
  </div>

  {% block content %}
  {% endblock %}
</body>
  • Thanks much, Alex! I used query strings as you recommended and it worked great. I realized that part of the problem I encountered was that I was setting my category and categorySlug within my {% block content %}. I needed to set these outside my {% block content %} in order for it to have worked with my language switcher, which was in my _layout.html. – user3092 Sep 20 at 19:48
  • Oh, good catch. I'll add a note in about that. – Alex Roper Sep 22 at 4:23

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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