I have a custom Module and I would like to implement the craft\webhooks\filters\FilterInterface as seen on the doc.

I understand that the event Webhooks::EVENT_REGISTER_FILTER_TYPES should be added in the public function init() of my Module, but I don't know where to store the class ArticleFilter implements FilterInterface.

Is it under /controllers, /services, /models,... or something else? I don't understand the logic and where to store this filter.

1 Answer 1


It doesn't really matter as long as you make sure to type-hint correctly relative to the current namespace and/or use the fully qualified class name. However, it's best to follow the established conventions of the core or in this case, the plugin you're building on. The Webhooks plugin puts all the default filters in the directory src/filters/.

I like to put all modules under the \modules\ namespace, with sub-namespaces for each module. For example, for a module that extends the Webhooks plugin, I would use \modules\CustomWebhooks\ as a namespace. So this would result in the following directory structure:

├── CustomWebhooks
│   ├── CustomWebhooksModule.php
│   └── filters
│       └── ArticleFilter.php

And the following fully qualified class names:

  • CustomWebhooksModule.php -> \modules\CustomWebhooks\CustomWebhooksModule
  • ArticleFilter.php -> \modules\CustomWebhooks\filters\ArticleFilter

Optionally, you can also put the filters and every other subdirectory into a src directory inside modules/CustomWebhooks, this depends on your autoload setup. In this case, the fully qualified class names don't change, but the directory structure looks like this:

├── CustomWebhooks
│   ├── CustomWebhooksModule.php
│   └── src
│       └── filters
│           └── ArticleFilter.php
  • Thank you! I followed as straghit as possible your indications and I think that works. But just for a reason I still don't undertand, I had to add abstract before class ArticleFilter implements FilterInterface to make it works.
    – Romain P.
    Jan 17, 2022 at 10:25
  • @RomainPoirier That won't work – abstract classes can't be instantiated, they're meant as base classes for other classes to extend. If you were getting an error that was fixed by making the class abstract, your class is probably missing one of the methods required by the interface. Remove abstract from the class definition and check the error message to see what you're missing!
    – MoritzLost
    Jan 17, 2022 at 10:30
  • This is what I get if I remove abstract: Class modules\utilitiesmodule\filters\CompaniesFilter contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (craft\base\ComponentInterface::isSelectable). My code is almost a copy/paste of the example in the doc, I don't undestand what's missing.
    – Romain P.
    Jan 19, 2022 at 11:07
  • @RomainPoirier You're missing the isSelectable method of the ComponentInterface. The example code in the readme would result in this error as well – maybe post an issue about that on Github. The built-in filters all extend the BaseElementFilter class, you could do that as well. This one extends the Component base class which includes the missing method.
    – MoritzLost
    Jan 19, 2022 at 11:17
  • @RomainPoirier So your definition would look like this: class ArticleFilter extends BaseElementFilter implements FilterInterface. Make sure to add use statements at the top for the classes / interfaces you're using.
    – MoritzLost
    Jan 19, 2022 at 11:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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