Module plugin error invalid argument

Hi,
first of all I like so much the module and the pattern plugin. It’s such a good thing to work with!

With the module plugin I get an error:

Warning: Invalid argument supplied for foreach() in …

my code seems easy:

if($page->hasModules()) {
	foreach($page->modules() as $module) {
		echo $module;
	}
}

Am I blind, It must be something stupid I can’t see?!

The module is displayed as expected.

But the module appears too in the menu?

$page->modules() collects all modules and returns their HTML, so the foreach loop is unnecessary/results in an error, see the readme.

Yes you are right!

But how to prevent the modules from displaying in the menu?

Easiest way is to make the module pages invisible and only pull visible pages in your menu. But it all depends on your menu code.

I did, but then the module also disapeared.

my code is just this

if($page->hasModules()) {
 echo $page->modules();
}

I’am not asking for the visible ones in the code

Ok, the module code filters by visible modules, so they should be visible. Then you need to change your menu code, you can use the not() method with a collection of pages to exclude from the menu.

Ahh, I was understanding the idea of modules more as parts of a page and why should they then be visible in the menu?!

Is there no way to see if a item is a module?

No, to Kirby, modules are subpages just like any other subpage.

You can filter by template (all module templates start with module.).

But even easier: You can use the second, recommended approach and create a subpage called modules for each page where you need modules. This modules page can be invisible. Only the individual modules inside that directory need to be visible, but because of the hidden parent they won’t appear in menus.

BTW: Thanks for the feedback regarding “easily detecting if a page is a module”, I have noted the idea for the next version.

Ohh yes that would be great!

I have it like this now:
in module -> text.yml

parts:
    label: Module
    type: select
    text: module
    default: module
    options:
      module: Modul
      subpage: Unterseite

and in the menu:

if($child->parts() != 'module' ):

I wouldn’t recommend this, manual options are always a bit error-prone. Consider using something like this instead:

if(!str::startsWith($child->template(), 'module.'):

Even better would be to filter the collection before the foreach loop, but the simple if is easier for you to drop in.

1 Like

Thank you, that works pretty!

Hi @lukasbestle,
did you mean something like this:

// get all children for the current menu item accept modules
$children = $item->children()->visible()->filter(function($child) {
  if(!str::startsWith($child->template(), 'module.')) {
  return $child;
  }
});

Yeah, but even simpler:

// get all children for the current menu item except modules
$children = $item->children()->visible()->filter(function($child) {
  return !str::startsWith($child->template(), 'module.');
});

The filter function only needs to return true or false, so there is no need for the if.

1 Like

thank you, that’s even better!

Hi @lukasbestle,
if I want to put my modules inside patterns, where do I have to change the root path?

kirby()->roots()->site() . DS . 'patterns' . DS . 'modules'

Ahh, I got it. Everything is okay and again GREAT WORK!

For reference in case someone else has the same issue: There’s a modules.directory option.

just to end this post. In the end I used the second, recommende aproach and put all modules inside a invisible subpage named modules. This is the clean and easy way.

Thanks for great support and this great plugin :grinning: