Get pages in all languages

Hi, I have a multi-language website set up with 3 languages (en, de, ar).

For a very specific use-case, I am trying to get the children of a specific page in all 3 languages to show in a single foreach construct. I am adding the very basic structure of my code, because nothing I’ve tried so far worked… Would really appreciate any ideas or direction where I should look further! Thanks :pray:

        $items = $site->find('flyers')->children()->listed();
        foreach ($items as $item):

The children are always the same. But when looping through the children, you can get the content in each language, so you would loop through all languages ($kirby->languages()) inside your foreach loop, then get $item->content($languageCode)->whateverFieldHere().

Thanks for the answer @texine! I must say I didnt know how to loop through all the languages in the foreach using the ($kirby->languages()). But after fiddling around I managed to solve it using an array of my languages. So for good documentation I’m sharing it here :

$items = $site->find('flyers')->children()->listed();
foreach ($items as $item):

$langDe = $item->content('de');
$langAr = $item->content('ar');
$langEn = $item->content('en');
$langs = [$langDe, $langAr, $langEn];
foreach($langs as $lang):

And then get $lang->anyField() inside the loop. Anyways, it worked for me! but if this is redundant I’d love to learn :slight_smile:

If you don’t care about the order of the languages, I think you could write this as:

$items = $site->find('flyers')->children()->listed();
foreach ($items as $item):
  foreach(kirby()->languages()->codes() as $code):
    $lang = $item->content($code);
    echo $lang->anyField();
    // ... don't forget to close the loops

If you care about the order, you could also write the same like this:

$items = $site->find('flyers')->children()->listed();
foreach ($items as $item):
  foreach(['de', 'ar', 'en'] as $code):
    $lang = $item->content($code);
    echo $lang->anyField();
    // ... don't forget to close the loops

Tnx @rasteiner! That does look a bit neater :wink:

Hi, this topic is already closed, but I have a follow-up question that I hope this would be the right place to put it…

Following this thread I am now able to fetch all the children in all languages into a single loop. But my problem now is how could I filter them to only get the items that are actually translated? I’ve tried this method, but no matter what, it get an “item” for each child in all languages even if the content doesn’t exist (it replaces the default language content). I would really appreciate the help :pray: :blush:

// fetch flyers
$items = page('flyers')->children()->listed();
foreach ($items as $item):

// fetch all flyers in all languages
foreach(['de', 'ar', 'en'] as $code):
  $translatedItem = $item->content($code);

// filter flyers only if translation exists...?

?>

The question is when you regard a page as translated, and the way to go about this depends on it.

Does the page always have content in the default language?

Kirby always creates a content file in the default language. The content file for the non-default languages is created when the translation is saved (which may or may not actually contain a real translation).

The best way to go about this is usually to add a toggle field that explicitly marks a page as translated, then filter by that value.

Hey, thanks for the reply @texnixe.

The ‘flyer’ always has content in the default language, but is not always translated to the other two languages. The bool method is good. However, in this case the translation of some of the pages doesn’t even exist at all (there’s no txt file in the content folder), and still I am getting a $translatedItem for each item even if the content($code) doesn’t exist.

I guess it’s because of the way my code is written… So I wonder if there is a way to filter it somewhere? something like:

foreach(['de', 'ar', 'en'] as $code):
  $translatedItem = $item->content($code);

but then filter: only if page’s content actually exists… ?
:pray:

You need to check if the translation file exists, not based on content, something like

$item->translation($code))->exists()

Thanks as always @texnixe! :blush: had to play with it quite a bit, but the solution was to filter the items inside the loop. For good documentation, this works:

<?php
// fetch flyers
$items = page('flyers')->children()->listed();
foreach ($items as $item):

// fetch all flyers in all languages
foreach(['de', 'ar', 'en'] as $code):
  $translatedItem = $item->content($code);

  // filter items only if translation exists 
  if($item->translation($code)->exists()):
?>

// the loop...