Building a robust website with Craft CMS often involves integrating third-party plugins to extend functionality. However, a common challenge arises when your templates or custom modules rely on these plugins: what happens if the plugin is disabled or uninstalled? Without proper checks, your site might throw errors or show broken layouts.

In this guide, you will learn how to programmatically check if a plugin is installed and enabled within Craft CMS. We will cover both Twig templating methods and PHP approaches for module and plugin development, ensuring your code remains resilient regardless of the environment's configuration.

Why Check for Plugin Status?

Before diving into the code, it is important to understand the use cases for plugin detection. You might want to check a plugin's status to:

  1. Prevent Template Errors: If you call a variable provided by a plugin (like craft.freeform) and the plugin is missing, Twig will throw a runtime error.
  2. Conditional Feature Loading: You may want to load specific CSS or JavaScript only if a certain plugin (like SEOmatic) is active.
  3. Cross-Plugin Integration: When developing your own plugin, you might want to provide extra features only if another specific plugin is installed on the user's system.

Checking Plugin Status in Twig Templates

There are two primary ways to check if a plugin is active within your Twig templates. The best method depends on whether you need a quick "is it working?" check or a more granular "is it installed but disabled?" check.

Method 1: The Quick "Is Defined" Check

The simplest way to check if a plugin is both installed and enabled is to use Twig’s is defined test. Most plugins register a global variable under their handle. If the plugin is disabled, that variable will not be registered.

{% if craft.freeform is defined %}
  {# The Freeform plugin is installed and enabled #}
  {{ craft.freeform.form("contact").render() }}
{% else %}
  <p>Contact form is currently unavailable.</p>
{% endif %}

This method is clean and efficient for front-end logic where you only care if the plugin's functionality is currently available to the template.

Method 2: Using the Plugins Service for Granular Control

If you need to distinguish between a plugin being present in the filesystem versus it being enabled in the Control Panel, you should use the craft.app.plugins service. This is particularly useful for administrative dashboards or complex conditional logic.

{# The second argument 'false' tells Craft to return the plugin even if it is disabled #}
{% set plugin = craft.app.plugins.getPlugin('plugin-handle', false) %}

{% if plugin is not null %}
    {% if plugin.isInstalled %}
        <p>The plugin is installed.</p>
    {% endif %}

    {% if plugin.isEnabled %}
        <p>The plugin is enabled.</p>
    {% endif %}
{% else %}
    <p>The plugin is not found in the project.</p>
{% endif %}

In this example, calling getPlugin('handle', false) ensures that the plugin object is returned as long as the files exist and it is recognized by the system. If you omit the second argument or set it to true, the method will return null if the plugin is disabled.

Detecting Plugins in PHP (Modules and Plugins)

When writing a custom module or developing a plugin, you often need to check for the existence of other plugins within your PHP logic. This is handled through the main Craft application component.

To check for a plugin from within a PHP class:

use Craft;

// Get the plugin instance. 
// The second argument determines if you want to include disabled plugins.
$plugin = Craft::$app->getPlugins()->getPlugin('plugin-handle', false);

if ($plugin !== null) {
    if ($plugin->isInstalled) {
        // Logic for installed plugins
    }

    if ($plugin->isEnabled) {
        // Logic for enabled plugins
    }
}

If you are targeting older versions of the platform (like Craft 2), the syntax differs slightly as it utilizes the craft() helper:

// Legacy Craft 2 approach
$plugin = craft()->plugins->getPlugin('pluginHandle', false);

if ($plugin) {
    $isInstalled = $plugin->isInstalled;
    $isEnabled = $plugin->isEnabled;
}

How to Find a Plugin's Handle

All the methods above require the "plugin handle." This is not always the same as the folder name in your vendor directory. To find the exact handle required for these checks, you have two reliable options:

  1. Check the composer.json: Navigate to the plugin's source folder. Inside the composer.json file, look for the extra section. The handle is defined under handle within the craft-plugin-info object.
  2. Check Project Config: If you have access to your project files, look in config/project/project.yaml. Search for the plugin name, and you will see the handle used by Craft to track its status.
  3. Control Panel: While the CP shows the "Name," the handle is often a camelCase or kebab-case version of that name.

Understanding the Plugin Lifecycle

It is vital to understand the difference between the three states a plugin can inhabit in Craft CMS:

  • Not Found: The files do not exist in the vendor directory. getPlugin() will return null.
  • Installed but Disabled: The plugin files exist, and the plugin has been "installed" into the database, but an admin has toggled it off. You can still access the plugin object if you pass false to the getPlugin method.
  • Installed and Enabled: The plugin is fully operational. This is the state required for is defined checks in Twig to return true.

Frequently Asked Questions

How do I check if a plugin is installed but specifically disabled?

Using the craft.app.plugins.getPlugin('handle', false) method in Twig or PHP allows you to retrieve the plugin object regardless of its enabled state. Once you have the object, you can explicitly check if (plugin.isInstalled and not plugin.isEnabled).

Why does craft.pluginHandle is defined return false even though the plugin is in my vendor folder?

A plugin must be "installed" via the Craft Control Panel or the CLI (php craft install/plugin handle) before Craft recognizes it. Merely having the files in the vendor folder via Composer is not enough for the variable to be defined in Twig.

Does checking for a plugin affect performance?

Minimal. Using getPlugin() is a very lightweight operation as Craft already keeps a map of loaded plugins in memory. However, for template performance, the is defined check is the fastest way to perform a simple conditional.

Key Takeaways

  • Use {% if craft.pluginHandle is defined %} for quick, simple checks in Twig when you only need to know if the plugin is ready to use.
  • Use craft.app.plugins.getPlugin('handle', false) when you need to differentiate between installed and enabled states.
  • In PHP, access the plugin service via Craft::$app->getPlugins().
  • Always verify the plugin handle in the plugin's composer.json to ensure your code targets the correct ID.
  • Adding these checks makes your Craft CMS site more resilient, preventing "Internal Server Error" screens when plugins are toggled or updated.