I'm building a language switcher for a clients website. The website consists of multiple regions which can have multiple locales. As regions aren't supported yet in Craft 2, I've worked my way around that in a variety of ways.

For my products section, I have a category group of product categories. The top level of each tree within that group is the region a product belongs to. So you can have something like this:

  • US
    • Category US A
      • Category US A 1
  • Europe
    • Category Europe A
      • Category Europe A 1

So when selecting category 'US A 1' I know the region this product needs to be shown in is US and I have the correct category too.

Now when switching languages, I check if the region also changes. If so, I have the ID of the new region (which is the first level category of a tree within that group). So, I check if this entry exists related to that category ID. If so I need to find the exact same subcategory in the Europe tree as was selected in the US tree (so find 'Europe A 1') and check if the entry is also related to that category. If so, send the user to that URL. Problem is I don't know how to do that last step as all I'm getting is an array of categories without any hierachy.

Important: I need this in a plugin in PhP so no Twig.


The only link between for example: 'US A 1' and 'Europe A 1' will be the slug. I'll have to enforce the client to make sure similar categories share the same slug. (Thanks to carlcs to ask this important info I forgot to mention :)

  • What’s the link between “US A 1” and “Europe A 1”? Just a naming convention for the slugs?
    – carlcs
    May 29, 2017 at 11:37
  • Yes, that's the only link I can think of I can use. May 29, 2017 at 11:41

1 Answer 1


I would just split that category group, if possible, and offer one group for the region and one for the “A1” type of categories.

If this is out of question, you need to find a way to link your categories. Give them the same slug or use another field to make the connection (e.g. a Categories field) and use the corresponding criteria param to filter for the entry in the new locale.

$currentLocaleCategory = $entry->myCategoriesField->last();

if ($currentLocaleCategory) {
    $criteria = craft()->elements->getCriteria(ElementType::Category);
    $criteria->locale = $locale;
    $criteria->descendantOf = $descendantOfParam;
    $criteria->slug = $currentLocaleCategory->slug;

    $newLocaleCategory = $criteria->first();
  • I can't split them up. That decision was made at the beginning and I didn't want to do that, because than I needed to to write a custom plugin to check if a selected product category was linked to a selected region category and add custom warnings and validation when this was not the case. On hindsight, maybe that was the better option but we're to far in the project now to make that kind of big changes. May 29, 2017 at 12:09
  • I'm all for the same slug idea, that was what I was allready doing, but I have no clue how to proceed with that as explained in my post. How can I get the slug of a subcategory from an entry? All I get back is an array with all categories flat listed. May 29, 2017 at 12:11
  • @TomDeSmet updated the answer with some example code.
    – carlcs
    May 29, 2017 at 12:52
  • Thanks but ->last() doesn't give me the correct subcategory but the last item in the category array which is always the bottom category of the last tree in the category group. May 29, 2017 at 13:51
  • Do you select more than one category? Otherwise it should be the correct one, no?
    – carlcs
    May 29, 2017 at 14:20

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.