Allow multiple plugins to register the same component

If 3 plugins all register set the css component I guess the first or the last plugin will use the css component.

Is it possible to use a component more than once? With more and more plugin I guess it can be a future problem to solve?

Code examples for possible solutions would be nice! :slight_smile:

What exactly do you mean with “use more than once”?

Like the plugin below. It uses the respone component. What if another plugin extends the response class as well. Can 2 plugins extend the response class?

If not would it be possible to solve it somehow?

For example a html minifier + cache plugin, both extending the response class.

https://github.com/jenstornell/kirby-html-minifier/blob/master/html-minifier.php

Do you know what I mean? One hook can be used by multiple plugins. What about a component?

No, that’s not possible. The last registered one always wins.

Hooks are independent from each other, which is why there can be multiple ones per hook. Components on the other hand return very specific information that is used by Kirby. We can’t just pipe the output of one component into the next because it will expect a different input.

If you want to support other plugins with your plugin, you need to do so manually by detecting if the plugin is installed and communicating with that plugin.

1 Like

Would pipes like that be a nice future feature then?

The only problem I see with it is the order of things.

My predictions were true. Today I got my first issue related to this:

@jevets

https://github.com/jenstornell/kirby-init-controller/issues/2

If I’ve registered my own template component, there are conflicts.

Either this plugin is called and my custom template component is never run, or my template component runs and the init-controller is never run.

But, one could build-in the same principal as this into his own custom component.

In my previous comment I suggested some kind of pipes feature, but then how can the plugins know in what order to run the registration of the components, when all plugins want to run first or last.

Another CMS solves it by adding a number and if I want to run it last I may put like 1000 in the function. But then another plugin is created that also want to run last and it adds the number 10000 and it’s like a battle of the highest number. It’s probably not the best solution.

Another thing that comes to mind is a setup of a config array of the component order, but that might be hard for new users to understand. The admin needs to understand what compenents there are and in what order to run them.

Yes, that’s exactly what I was referring to above. Even with a config array this is not going to work as components suddenly get input they don’t expect if it has been modified by the previous component.
The only way is to manually check if a specific plugin is loaded and then cooperate with it somehow if it’s in your whitelist of supported plugins.

The only way is to manually check if a specific plugin is loaded and then cooperate with it somehow if it’s in your whitelist of supported plugins.

Yes, I guess so. :slight_smile: If it’s possible already in a nice way it would be great to have an example, a proof of concept that me and other plugin developers can use as a starting point in cases like this.

If there is not a good way, maybe add an issue to the Kirby repo and then you can think about what approach to take?

I haven’t tested it, but an approach like this should work (all of that happens in the constructor of your component class):

  • Try to load the other plugin by name with kirby()->plugin('theotherplugin')
  • If that returns anything else than false, it means that the plugin exists and has been loaded (the component has been registered as well)
    • Grab the component from the other plugin with kirby()->component('css') and store it in a property of your component
    • You can use any method of that component in your newly registered component
  • If it returned false, behave as normal (the plugin is not there)

Please note that it will only work in the constructor, in every other method you won’t have access to the other component as yours has already overwritten the other by then.