Extending WordPress: Requiring Plugins with TGMPA

Dec 31 2015: added a source control repository containing the sample theme - https://bitbucket.org/grantpalin/wp-tgm-demo. TGMPA is in the libs folder, configuration is at inc/tgm.php, and the kickoff is at the bottom of functions.php. The theme is otherwise a basic one generated from http://underscores.me.

Introduction

PHP developers will be familiar with the main ways to require dependency code: a combination of Composer and include/require. This can of course be used when writing plugins or themes for WordPress, but WordPress doesn’t itself offer a way for allowing and fulfilling suggested or required dependency plugins. It’s not uncommon for themes to lean on plugins for providing functionality – as well they should – so there is a need for the means to require said plugins. Fortunately there is a way to do so thanks to TGM Plugin Activation.

What is TGMPA?

TGM Plugin Activation is a library (maintained on GitHub) that can be added to a WordPress theme or plugin – though a theme seems more likely. When said theme or plugin is active, the plugin – when configured, more on that later – will check for the presence and status of dependency plugins. If the plugins are not installed, TGMPA will prompt for installation; if plugins are installed but not active, TGMPA will prompt for activation. Further, it allows distinguishing between plugins that are recommended, perhaps for nice-to-have or redundant functionality, as well as required which MUST be installed for the host code to work correctly.

Besides the TGMPA library, the host code also requires some configuration to specify the dependencies. The library then uses this configuration to do its magic. This configuration is fortunately easy to do, TGMPA itself does all the hard work. The next section will look at how to implement TGMPA in a theme.

TGMPA notification

When a theme or plugin using TGMPA is active, AND there are unsatisfied dependencies, a notice is shown in the WordPress Dashboard.

Clicking on Begin installing plugins takes the user to a page generated by TGMPA, where necessary or optional plugins are listed; this includes plugins that are not installed, and ones that are installed but not activated. Clicking the Install link for a plugin initiates the process that WordPress users will be familiar with – TGMPA just uses functionality that is already there – and redirects back to the same page. The user must then click the Activate link, after which the relevant plugin will drop out of the listing. Other required or optional plugins can be brought in the same way.

Implementing TGM

There are two ways to add TGMPA to a project: the manual way of copy/paste files into a lib folder, or via Composer.

For this post I opted to use the manual way and not bring in yet another tool (Composer). However the Composer route can be simplified down to the following command:

composer require tgmpa/tgm-plugin-activation

The manual route is straightforward: download the zip file from the project website or the GitHub page (the latter may be more up to date) and extract into a directory local to the project, such as lib/tgm, as I have done.

TGMPA library location

As mentioned before, there is some minor configuration to be done before TGMPA does anything. The downloaded library includes an example.php file which contains a sample implementation of said configuration. Because this file is theme/plugin code rather than library code, I copy it into an inc directory parallel to lib, and rename the file tgm.php.

TGMPA config file location

Opening the file in a text editor presents a large configuration function, but it simplifies down to the following:

<?php
require_once dirname( __FILE__ ) . '/class-tgm-plugin-activation.php';

add_action( 'tgmpa_register', 'my_theme_register_required_plugins' );

function my_theme_register_required_plugins() {
    $plugins = array(
        array( ),
        array( ),
        // ...
    );

    $config = array(
        // ...
    );

    tgmpa( $plugins, $config );
}

The require_once brings in the core library file to do the dirty work. The add_action call instructs WordPress to run the given function. Lastly, the function contains the actual configuration and activates the library’s functionality.

The require will need to be amended if the configuration file has been moved away from the library. Due to my preferred directory structure, I updated the require to read:

require_once dirname( dirname( __FILE__ ) ) . '/lib/tgm/class-tgm-plugin-activation.php';

There are examples of multiple ways to require plugins, whether they be on the official repository, on GitHub, bundled with the theme, or just located elsewhere.

There are some bits that can to be edited to better integrate this functionality into the host project. There is an array of config values:

$config = array(
    'id'           => 'tgmpa',                 // Unique ID for hashing notices for multiple instances of TGMPA.
    'default_path' => '',                      // Default absolute path to bundled plugins.
    'menu'         => 'tgmpa-install-plugins', // Menu slug.
    'parent_slug'  => 'themes.php',            // Parent menu slug.
    'capability'   => 'edit_theme_options',    // Capability needed to view plugin install page, should be a capability associated with the parent menu used.
    'has_notices'  => true,                    // Show admin notices or not.
    'dismissable'  => true,                    // If false, a user cannot dismiss the nag message.
    'dismiss_msg'  => '',                      // If 'dismissable' is false, this message will be output at top of nag.
    'is_automatic' => false,                   // Automatically activate plugins after installation or not.
    'message'      => '',                      // Message to output right before the plugins table.
    // more settings
);

Because TGMPA is fairly widely used (and may be used by other plugins/themes running on the same site), it may be a good idea to change the id value to something unique to the host project. Beyond that, some of the later settings may be customized to control the experience that TGMPA provides. There is a large number of additional settings (not shown) to control the text of the notices that TGMPA shows; these have reasonable default values and only need be edited if something different is needed.

Now the interesting part: specifying the prerequisites. Look at the following code, which is located in the middle of the aforementioned configuration function.

// This is an example of how to include a plugin from the WordPress Plugin Repository.
array(
    'name'      => 'BuddyPress',
    'slug'      => 'buddypress',
    'required'  => false,
),

That’s pretty simple. Since BuddyPress is on the official plugin repository, just the name and slug will ensure it gets mentioned.

Lastly, the configuration file needs to be loaded by WordPress; if in a theme, it can be done via functions.php, while placing it in a plugin will depend on how the plugin is structured. The sample here is a theme, so the following line goes in functions.php:

require get_template_directory() . '/inc/tgm.php';

Conclusion

WordPress is sorely missing a native means of allowing themes to indicate their dependency on plugins, and to facilitate installing and activating said plugins. TGMPA provides a solution to fill this gap, and does so in a way that works with the core WordPress functionality and maintains a familiar experience for the users.

So many commercial themes have functionality built in that really should be coming from plugins. Judicious use of TGMPA can decouple themes from said plugins, though could only by relied upon if the theme handles missing plugins well. That said, I believe that theme authors should be leveraging TGMPA when they depend on plugin-level functionality.

The sample shown in this post was built around using TGMPA in a theme. It’s also possible to use TGMPA in a plugin, but the placement of code may differ based on how the plugin is structured.

Further Reading