CraftCMS 3 — Modules and Plugins

CraftCMS 3 brought many new features, performance improvements, and architectural changes. Arguably the largest architectural change is the upgrade of Yii to version 2.
This brought with it a switch to full composer-based package management, and alignment with the Yii structure of having a centralized “App,” in this case that App being CraftCMS.

In additional to the core source code and dependencies of Craft now being part of the composer ecosystem, Craft’s plugins are actually now Yii Modules with some additional features. Craft now additionally supports native Yii Modules.

Modules and plugins are very similar, but they serve slightly different purposes.
What are the Differences?

Modules

Modules are native Yii modules that have access to CraftCMS services. They normally live inside the modules folder in your project root, although that can be customized. This means that if your Craft project is tracked by a version control system (which I highly recommend), then the module files should be part of that codebase (or exist as a sub-module, but that's not within the scope of this article). Modules need to be manually included by composer, and bootstrapped with CraftCMS's application config.

In this code example, you can see that Modules extend the Yii base Module:

This code example is extremely simplified, and is just meant to illustrate that craft is included with a use statement, but not extended.

Plugins

Plugins are extensions on modules. They include all the functionality of modules. Additionally, there is no need to manually include them in composer.json or bootstrap them in the application configuration. Craft handles that. They include the following functionality on top of modules:

Settings: Plugins have a simple settings architecture that allows developers to store settings in the database, and have users access them in the Admin Control Panel, without the developer needing to manually create those views and records.

Installation tracking: Plugins exist as composer packages, but additionally can exist within the CraftCMS plugin store. A plugin can be:

Disabled (exists in the composer dependencies, but is not bootstrapped by Craft)

Installed (exists on the composer dependencies, and is bootstrapped by Craft)

Uninstalled (Craft disables the plugin, removes it from the composer.json, and then rebuilds the Autoload.php file)

Licensing: The plugin store includes the ability for developers to license their plugins. Plugins have access to those services to check on licensing and modify functionality based on licensing.

Migrations: Craft plugins can have migrations that occur on the database. These can occur on plugin installation, uninstallation, upgrades, and downgrades.

As opposed to the above code snippet, you can see that Plugins extend the built in CraftCMS Plugin Class:

Important to note that here we are using a fully qualified namespace to prevent conflicts with other plugins.

So, What Should I Use?

There are three questions that will influence whether or not you should build a plugin or a module:

Can your code be used on other projects? If so, build a plugin.
If the answer to this is yes, you should probably build a plugin. Creating a plugin means you can release it in the plugin store and benefit the community at large, or make money from it. Even if you only use the plugin for yourself or your organization, it’s still valuable having portable functionality that can be used in multiple places.

Do you need “quick and dirty” functionality? If that’s the case, a module is your best bet.
As much as we developers would love for everything to be properly planned and scoped, that often isn’t the case, and sometimes you just need to add functionality to a site. If this is the case, it’s probably best if you build a module. If you want the code to be portable later, you can always find time to turn it into a plugin 😂. Even though you need to add a bit of code to bootstrap the module, you don’t need to create a separate repo, worry about installation across databases, etc.

Is the code integral and highly specific to your website/project? Probably best to build a module, then.
Many times we need to build code that communicates with custom APIs, works with unique business logic, or is just individually branded for a specific purpose. In this case, a module is your best bet. It will always be installed, and lives as part of your site’s existing functionality and codebase, ensure they are tracked as a single project.

How Do I Get Started?

To get started, I recommend using the excellent https://pluginfactory.io/, created by nystudio107. It will bootstrap either a plugin or module for you, including all the controllers, services, variables, etc you might need.

If it’s a plugin you created, you can test it by either specifying a local folder in composer.json, or pushing it up to a VCS repo, and then including it from there. And then once it’s finished, publish it to the Craft Plugin Store and

If you are making a module, make sure to follow the instructions in the README.md file on how to bootstrap the plugin and get composer to autoload it.

Not a developer, but need CraftCMS help? Reach out to us @digitalsurgeons and we’ll see how we can help.