WP plugins and how to manage them

Sharing what I’ve learnt so far:

About composer

Composer is a package manager for PHP (similar to NPM) and there are also a couple of packages that allow us to manage monorepos with composer: composer-monorepo-plugin and monorepo-builder.

But I’m not sure if we have a use for it, as what we want to have is many WP plugins inside one repo, but these plugins don’t need to be composer packages to be used by our general plugin.


Possible solutions

1. One plugin to contain them all

In this solution, proposed by Luis, the main plugin is in the root of the repo and the other plugins will be inside that plugin, in a plugins folder, and will be directly imported by the main plugin.


  • We still can publish the minor plugins on its own just keeping the WP install/activate logic out of the main class, so the class can be directly imported by the main plugin.
  • The way the main plugin uses the minor ones is very simple, just require if not yet required.


  • If a blog already has a minor plugin installed, the code of that plugin would be duplicated.
  • We would need to use symlinks in development in order to work with the minor plugins as installed independently
  • We might need to handle some conflicts that can appear between minor plugins if they are installed independently and the main plugin is also installed.

2. One plugin to rule them all

All the plugins live inside the packages folder of the repo (including the main plugin), and the main plugin will have the minor plugins as dependencies, so in order to use the main plugin in production all the minor plugins should be installed. The main plugin will act only as a manager and it might install any minor plugin required.


  • There shouldn’t be conflicts between the main plugin and the minor plugins when installed.
  • No code is duplicated in production.


  • All minor plugins must be installed in order for the main one to work. To ask the user to install them is highly inconvenient. If we install them with the main plugin it might be a bit shady.
  • We would need to use symlinks in development in order to work with all the plugins

Things to consider

Minor plugins might need to save settings/transients

We should be careful about removing the settings/transients when uninstalling/deactivating a minor plugin if the main one is still installed or viceversa.

Minor plugins might need an UI in order to be used

Maybe here we should declare a general admin page in the menu called Frontity, no matter if we are dealing with the main plugin or with minor plugins, and for each of the minor plugins declare a subpage. So the UI for the main plugin would be a list of subpages created by the minor plugins.

We could also prevent the minor plugins from creating their UI in case the main plugin is installed, and with the main plugin render all the UIs needed in one page, if this is more suitable for our needs.

1 Like

I created a github repo for these plugins, also using Lerna like in our main repository. It’s just to have something to start with and it’s not ready to start developing any plugin yet.

I was trying to automate version updates in the .php files (using some of the npm scripts) and here is my conclusion:

  • postversion
    This is how I said to solve it before, but using this script Lerna has already created a “publish” commit and tags that point to that commit so it’s not a good moment to update any file.

  • version
    When running this script, package.json files have been updated but not committed. At that time you can update the version in the .php file by copying the version that is in package.json, and then stage the changes to the git repository. These changes will be committed in the “publish” commit that Lerna creates.

I added a version script in the root package to show how it could be implemented.

1 Like

Good points.

In general, I think we should aim for this:

final-user-experience > developer-experience > core-developer-experience

(">" meaning “more important than”)

With that in mind, I think the first solution has a better final-user-experience than the second one, although it has a worse core-developer-experience. The developer-experience is not affected.

The second solution has a worse final-user-experience because it has to install many different plugins. In my opinion, we should avoid that.

I agree with you.

We are back here! After discussing it we decided to proceed with the following implementation:

  • To use lerna to handle the packages version management of the different plugins.
  • To write a small script (width symlink-dir) that generates a symlink between your local WP wp-content/plugins and the repo containing the Frontity plugins, just passing the path to your local WP installation.
  • There is going to be a main plugin, that contains all the Frontity plugins, and then each Frontity plugin might be independent.
  • We are going to build a script that will sort out the directories to a new folder ready to be deployed with svn.
  • We will handle the differences between the requires of development and production creating two different files: require-dev.php and require-prod.php, so what we change with the script in our plugin.php file is just the required file path.
  • All the requires and imports script registered will be done in a different file than the one containing the main class of the plugin.

I might be missing some details, but I’ll start working with this.

1 Like

Maybe we don’t need a script, just instructions on how to use npx symlink-dir.

I just wanted to make it even simpler reducing the number of parameters needed. It’s already written though.

1 Like

Ok, so I’ve been thinking that we should add the “enabled” checkbox to the smaller plugins as well.

Why? Because features can also be enabled using query params. Something like this:

  • If query param is present, follow query param.
  • If query param is not present, follow “enabled” status.

Some examples:

HTML purifier not enabled in WP-Admin:

  • :x: /wp-json/wp/v2/posts <- html purifier not working
  • :white_check_mark: /wp-json/wp/v2/posts?htmlpurifier=true <- html purifier working
  • :x: /wp-json/wp/v2/posts?htmlpurifier=false <- html purifier not working

HTML purifier enabled in WP-Admin:

  • :white_check_mark: /wp-json/wp/v2/posts <- html purifier working
  • :white_check_mark: /wp-json/wp/v2/posts?htmlpurifier=true <- html purifier working
  • :x: /wp-json/wp/v2/posts?htmlpurifier=false <- html purifier not working

So you may want to install a small plugin, don’t enable it and use it only with queries.

Makes sense?

1 Like

I think it’s okay to give that possibility to users, right?

I cannot think of a case right now, but someone may want to have a feature disabled by default and only enable it using the query.

1 Like