Themes enabling plugins: this (PHP) class is one you might actually enjoy

50 Comments

Thomas Griffin and Gary Jones have been at work creating a class that will, they say, “revolutionize how plugins can be handled in WordPress themes.” Their class, TGM Plugin Activation, allows theme authors to include plugins with their theme or have them automatically downloaded from the WordPress Plugin Directory and prompt the users to install and activate them when they activate the theme.

It leverages code found within WordPress to handle the installation and activation of the plugins the authors use in the creation of the theme. For instance, it uses the WP_Filesystem Abstraction class to find the best way to install the plugins based on the user’s server setup.

The latest version offers up an API for developers to make using the class in their theme easier.  More information about features and future additions is available in their readme file on GitHub.

What do you think of this as a method for more simply including plugins with WordPress themes? Do you think you’ll be including this in your themes? Give your opinion in the comments.

50 thoughts on “Themes enabling plugins: this (PHP) class is one you might actually enjoy

  1. Sounds like a great idea! Just had this discussion today about how many of the more “substantial” themes (both free & premium) are offering a lot of functionality that really should be isolated in plugins. This sounds like a good way to at least try to get all the resources in to the right place.

    Thanks for sharing Justin!

    • Exactly – too many themes trying to do too much. Hopefully this will allow theme devs to include the absolute necessary elements and push the users to install the other “suggested” items.

    • Agreed Dave. It’s worth pointing out that the extra required / recommended plugins can be packaged with the theme, pulled from the .org repo, or given a URL to another zip file held elsewhere, so even a premium theme wanted to extract part of it to a plugin, they don’t *have* to put it on the .org repo to make use of this class functionality.

  2. Interesting idea, but I’d rather see it extrapolated a little differently. Drupal has custom packages, which are full installations with plugins and themes included. I’d like to see something like that?

    • Since themes and plugins are stored in different areas and are installed differently, currently there isn’t a feasible way to do just that. Hopefully this class will begin to bridge the gap though and make it easier for theme developers to recommend or require plugins and users to act upon those suggestions.

    • Problems are seem to get solutions, and this was one of the solutions I came up with. I think it at least gets the ball rolling on solving the problem of theme developers requiring or recommending plugins and making it easy for users to act upon those recommendations.

      And I take it by the smiley that this is a good start. :) I’m indebted to your tutorial on WP_Filesystem – it opened my eyes to see how to do this the WordPress way.

      • Yeah, I think it’s a good idea. I haven’t looked at the actually implementation yet, but it sounds good.

        This has always seemed to me as a rather obvious next step, as opposed to integrating plugins into the theme’s code itself. But I don’t make themes, so I’ve never had a need to actually do it. Installing a plugin isn’t hard from a code perspective (just a couple of function calls, I think), and the WP_Filesystem trickery to get the username and password (if needed) just once for any number of plugin installs is an easy trick to figure out if you really want to.

        The only issue off the top of my head is the timeout factor, where you could have the script timeout if you’re trying to install too many plugins or the HTTP is being slow. This one is edge-caseish, but something you might have to deal with in the future. I can think of a couple possible workarounds. My favorite would be to have some buttons on the theme screen, one for each plugin, that will do a one-click install of the plugin in question (maybe even make the interface all AJAXy), allowing the user to install the bits they want. There’s several different approaches to solve that problem.

        • We currently have the one-button per plugin system, and it’s the bulk install of checkboxed plugins that we’ll be working on as one of the next steps.
          How does WP deal with potential timeouts when bulk updating plugins?

    • Same here.

      I’d contemplated working on something like this myself, but have been sitting here someone would do it before I absolutely HAD to do it myself. It seems my laziness paid off for me :)

        • We’ve tried our best. There’s still a few issues we want to improve for the UX (for instance, if you register 5 plugins, you’ll get 5 admin notices, which is too many), but the underlying registration and installation is working well on everything we’ve tested so far, and by it using the WP_Filesystem API, we’re hopeful that it should cover most back-end setups.

    • Thanks for picking up on this Justin. All feedback from the community is greatly received :-)

      PS. Can I please get the link to my Twitter page corrected? (GaryJ, not GaryJones) Thanks.

  3. Big thumbs up :)

    I wrote a theme for one of the commercial theme companies a while ago which bundled a whole stack of plugins into it. It downloaded them fresh from the repository, installed and activated them automagically, but it didn’t make use of the WP_Filesystem class (I didn’t realise how important that was at the time) so it’s great to see there’s a convenient way to do this in future without having to dick around writing it all yourself.

    • And that’s the whole idea.

      Thomas had come up with a basic implementation (non WP_Filesystem) himself for a theme, and after my suggestions, revised it so it did make use of the WP_Filesystem API. Between us, we then worked on the API, to make it so that the file could be dropped anywhere within a theme (no dependencies), and that registering the plugins and overriding the default configuration settings was as easy as possible for the developer. The next tasks will look at improving the implementation from the user’s point of view.

  4. Including pre-determined plugins to be installed with a theme seems logical.
    However, a few issues need to be addressed.

    For example, what if a required plugin is already installed with a few configuration already set by the webmaster. In that case, what would be the solution to that conflict? Will that plugin be skipped even in an older version is installed?

    I’m sure the developers will consider that kinda situations, if they haven’t already.

    Thanks alot for the idea though :)

    • Currently, if the plugin is installed, but not activated, we’ll still show a message saying this theme recommends / requires that it be activated.

      We use the plugin slug (typically the plugin folder name) to determine if two plugins (one already installed, one registered) are actually the same plugin.

      We’ve got no checks on whether a minimum version of a plugin is required, but that is an excellent idea and I’ll open a ticket for it right away!

    • Just to further address this, this issue is addressed in the next stable version release, 2.2.0. You can set a parameter ‘version’ for each plugin, and if the currently installed and activated plugin does not meet that minimum version, a notice will appear encouraging users to update the plugin to the latest version.

  5. Is it possible to deactivate the plugins when switching theme?
    For Example: You are using a Genesis child theme and making use of all the Genesis associated plugins and then decide you would like to try a non Genesis theme.

    • I don’t think we’d go that route. Consider if one of the required plugins added a CPT (lets say Listing, from the AgentPress child theme, seeing as you mentioned Genesis) – if we were to deactivate the Listings plugin upon you changing to a different theme (perhaps another real estate child theme that makes use of the same CPT), then all your content would be temporarily lost, until you manually reactivated the Listings plugin yourself. That’s going to cause confusion. Plugins, by their nature can be used across many themes, so I think it should be left to the the user, not the developer who registers the plugins in the original theme, to decide if a plugin’s functionality is no longer needed.

    • This issue is addressed in the next stable version release, 2.2.0. You can set a ‘force_deactivation’ parameter for each plugin (and conversely a ‘force_activation’ parameter as well) which will automatically deactivate the plugin upon theme switch.

  6. While it seems this has a primary focus on themes, could this also be used to create different distributions of WordPress? There has been pent up demand for different WordPress distributions that cater to specific needs and or functionality and I wonder if this could help keep the distro maintained without having to actually bundle the plugins along with the distro since bundled plugins going out of date is a big problem.

    • If you’re distributing WP with a different default theme, then yes, you could include this class file in that theme, and so the Install Plugins menu item would be available immediately. The user could then download the latest versions of the required / recommended plugins.

    • This sort of thing is possible by creating an ‘install.php’ file within the wp-content directory. In the wp-admin/includes/upgrade.php code, there are several functions that one can override to set the defaults for the initial install, and it should be possible to pre-install and pre-activate themes and plugins.

      • Are there any decent tutorials you’d recommend which cover the creation and population of this install.php file Dougal?

  7. I can think of one particular example for something like this (similar to @Charlie’s comment above), and I’m not sure it’s supported. If someone can enlighten me, I’d appreciate it…

    Let’s say that we’d like to make RocketTheme WordPress themes available on a multisite installation designed for novice users (with the appropriate license allowing unlimited entitlements, of course).

    The RocketTheme WP themes won’t work unless the Gantry Theme Framework plugin is active. (I wish they’d do it differently.) But novice users aren’t likely to activate and deactivate this plugin every time they activate an RT theme.

    Will your PHP class enable a plugin to automatically be activated and deactivated when a theme is activated?

    I understand @GaryJ’s point that this kind of functionality is not always ideal (as it could cause settings to be lost). But I’m still wondering if it’s possible.

    Thanks!

    • Will your PHP class enable a plugin to automatically be activated and deactivated when a theme is activated?

      Currently we don’t install a plugin, without the user’s say-so, and I don’t think I’d be happy for that to happen, without user interaction.

      However, what might be worth considering is if the plugin is already installed (the network admin would need to ensure Gantry Theme Framework is installed, say), and just needs activating – then I guess when registering, a plugin could specify a force_activation boolean parameter for one of the plugins, to work like you suggest.

      I’ve opened a ticket at https://github.com/thomasgriffin/TGM-Plugin-Activation/issues/39

    • Gary opened a ticket for this here: https://github.com/thomasgriffin/TGM-Plugin-Activation/issues/39

      Basically we both agree that automatically installing and activating plugins without the user knowing is not ideal. In your specific case, the odds are that since they are a novice they would never notice anyway, but I don’t believe that type of precedent should be set regardless. What Gary did mention though is that if that plugin is already installed, we can add a boolean argument that will activate the plugin upon theme activation. Otherwise, the normal process will continue (alerting the user that the plugin needs to be installed and activated). You could always code the theme to do a check to see if the plugin is activated or not and lock down the theme until that particular plugin is active, which would further motivate the user to get the plugin up and running.

      So yes, it is possible, but in the manner that you described I don’t think it would be the best plan of action.

      • Exactly, we’d have the plugin installed already. I agree that, in general, it’s best to avoid doing things without the users’ knowledge. But in this case we are trying to automatically handle anything needed by the user…as a benefit to them. So we would install the plugin, and we’d only need to activate it and deactivate it with particular themes.

        • Mark,

          This issue has been addressed in the next stable version release, 2.2.0, which is due out soon. You can set both ‘force_activation’ and ‘force_deactivation’ parameters for each plugin.

          ‘force_activation’ will force an installed plugin to be active at all times while the current theme is active. Once the theme is switched, then the plugin can be deactivated.

          ‘force_deactivation’ automatically deactivates the plugin upon theme switch.

  8. Really interesting idea, although I don’t include plugins with any of my themes this class might make me think twice about including them in the future. Definitely alleviates the issue of either building the plugin into the theme (not a great option as it makes plugin updates cumbersome) or instructing the buyer on where and how to download/install (ends up in more support requests).

    Will definitely be giving this a test run.

    • That was one of the issues I was running into constantly with themes being shipped out. Some parts would need updating, so they would have been better served as a plugin, but then it would’ve been a hassle with all the support requests of getting it setup had I gone the other route. This at least starts to bridge that gap.

    • Well, it is automatic in the sense that the users do not have to go searching for the plugins and install them themselves. Automatically installing and activating plugins without a user’s consent is not something either Gary or myself are particular keen on because that subverts the user’s control over his site. Rather, this class allows the users to decide if he/she wants to install the plugin (which in most cases will be yes) and gives an easy-to-use UI to do so.

  9. I just started using this properly this morning. It is an awesome little class. It’s not perfect, but it’s better than anything I’ve implemented myself so far.

    Something which wasn’t entirely obvious to me initially, is that you can use it to install non WordPress.org hosted plugins too without having to bundle the zip file into the theme.

    • Ryan, I thought our readme mentions this ability to install from other, non-repo, URLs but I could be wrong. If there’s other things not perfect about it, please add suggestions via the GitHub Issues for the project, thanks!

    • You can include plugins from any ‘repo’ as long as the download link is valid. Just set the ‘source’ argument to point to the plugin download and the class can determine whether or not the plugin is pre-packaged or from a private repo.

  10. I have yet to play with it, but it sounds great to a theme/plugin developer.
    I have a question though.

    Let’s say I sell plugins and themes of my own, would it allow me to include plugins I sell separately as “already authorized” (without admin prompts), and so allow me to sell a special version of a theme-only, as a products combo with a price cut?
    Would I be able to deploy some open source plug-ins from the .org. without a prompt ?

    Could the process be completely smooth ?

Leave a Reply

Please note that WPCandy is a moderated community.

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>