In trying to figure out what to talk about at WordCamp Atlanta, I remembered a question put to me in WordCamp Birmingham. The question was how can a theme developer easily make a plugin-dependency in their theme?

I wrote some code to do this sort of thing, just as an example/test/demonstration, but then after looking over the schedule, I found that Thomas Griffin had beat me to it. After looking over his slides and having him walk me through his code, I realized that his solution was much more fully featured than mine, so I’m glad I didn’t present anything on this topic. (I ended up just doing an answer session where I tried to answer any question put to me, and frankly that was much more fun than having slides, so I’m probably just going to do that from now on.)

You can find his cool library here, BTW: http://tgmpluginactivation.com/

However, his solution is highly complex. The class he came up with is well done and fully-featured. He has capabilities for making notifications in the header space on the admin section, lightbox popups, bulk installs, forced activation, custom skinning, etc. It’s a big thing. While that’s great for a lot of people in terms of having code you can just drop-in and use, I thought that it doesn’t do much to teach how one can DIY it.

See, the code I wrote was tiny. It basically just provides some minor functionality to show a theme author how to detect installed plugins, how to detect when they’re active, how to build install and activate links, etc. It doesn’t do any pretty stuff. No custom skinning. No lightbox popups. All these things are possible, but if somebody hands you a hunk of library code to do them, then you know how to use that library, not how it works. I dislike using libraries for this reason.

So here’s the small class I wrote to do the same sort of thing, but in a very bare-bones style.

/* 

Simple class to let themes add dependencies on plugins in ways they might find useful

Example usage:

	$test = new Theme_Plugin_Dependency( 'simple-facebook-connect', 'http://ottopress.com/wordpress-plugins/simple-facebook-connect/' );
	if ( $test->check_active() ) 
		echo 'SFC is installed and activated!';
	else if ( $test->check() ) 
		echo 'SFC is installed, but not activated. <a href="'.$test->activate_link().'">Click here to activate the plugin.</a>';
	else if ( $install_link = $test->install_link() )
		echo 'SFC is not installed. <a href="'.$install_link.'">Click here to install the plugin.</a>';
	else 
		echo 'SFC is not installed and could not be found in the Plugin Directory. Please install this plugin manually.';

*/
if (!class_exists('Theme_Plugin_Dependency')) {
	class Theme_Plugin_Dependency {
		// input information from the theme
		var $slug;
		var $uri;

		// installed plugins and uris of them
		private $plugins; // holds the list of plugins and their info
		private $uris; // holds just the URIs for quick and easy searching

		// both slug and PluginURI are required for checking things
		function __construct( $slug, $uri ) {
			$this->slug = $slug;
			$this->uri = $uri;
			if ( empty( $this->plugins ) ) 
				$this->plugins = get_plugins();
			if ( empty( $this->uris ) ) 
				$this->uris = wp_list_pluck($this->plugins, 'PluginURI');
		}

		// return true if installed, false if not
		function check() {
			return in_array($this->uri, $this->uris);
		}

		// return true if installed and activated, false if not
		function check_active() {
			$plugin_file = $this->get_plugin_file();
			if ($plugin_file) return is_plugin_active($plugin_file);
			return false;
		}

		// gives a link to activate the plugin
		function activate_link() {
			$plugin_file = $this->get_plugin_file();
			if ($plugin_file) return wp_nonce_url(self_admin_url('plugins.php?action=activate&plugin='.$plugin_file), 'activate-plugin_'.$plugin_file);
			return false;
		}

		// return a nonced installation link for the plugin. checks wordpress.org to make sure it's there first.
		function install_link() {
			include_once ABSPATH . 'wp-admin/includes/plugin-install.php';

			$info = plugins_api('plugin_information', array('slug' => $this->slug ));

			if ( is_wp_error( $info ) ) 
				return false; // plugin not available from wordpress.org

			return wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $this->slug), 'install-plugin_' . $this->slug);
		}

		// return array key of plugin if installed, false if not, private because this isn't needed for themes, generally
		private function get_plugin_file() {
			return array_search($this->uri, $this->uris);
		}
	}
}

Obviously, for theme authors wanting to do something, they’re going to want to make much prettier means of displaying things and installing things. Thus, this code is meant as an example, to show the basics of how to detect such things.

So, use it directly if you like (it works), but more importantly, if you want to put plugin dependancies in your theme, then I suggest reading it and figuring out how it works instead. Then you can see how plugins can be detected and how to build simple install and activation links.

(BTW, note that I used the slug and the PluginURI for a reason. Plugins should be using a unique URL for the plugin in their code, and that URL is very likely to be the most unique thing about the plugin, and therefore the best way to check for a plugin already being there or not. Slugs can be duplicated by accident or design, but URLs are generally going to be unique and specific to a particular plugin.)

Shortlink:

31 Comments

  1. Really interesting,
    This is a problem encountered in most of projects.
    Scribu have made a plugin like this, not a class but can help in the process of installing plugins :
    http://wordpress.org/extend/plugins/plugin-dependencies/

  2. Needs to be in core.

    But then you knew I’d say that.

    • If you examine the code above, it pretty much already is in core. Most of these are just wrapper functions around a couple of simple checks for things like the results of get_plugins and similar. They could be probably written as one liners if you cared to do so.

      I just think that adding wrappers solely for the sake of more descriptive naming is silly. The only reason I wrote these was to show people how. If you were actually implementing it, the class is pretty much unnecessary, and it could be done faster and better with a custom set of code for the use case.

      • That’s kinda like “almost pregnant”; it either is in core or it isn’t.

        The benefit of being is core is that it becomes a standard best practice among all WP developers and themers. It being almost in core means it’s something that only the “in crowd” who read Otto’s blog know about, and not even they can depend on it being available.

        Standards. Not just for post formats anymore. :-)

        • get_plugins() is in core. is_plugin_active() is in core. The above shows how to put them together, but anybody should be able to figure that out.

          Theme developers are going to eventually have to learn to program some code too. It can’t all be design and graphics and layout. Advanced functionality is still functionality, and IMO, people need to learn to program real code.

          That’s partially why I write this blog. I provide examples. I present tutorials. I often try to walk people through things. Because I really do believe that anybody can be a programmer, and can do it well. Heck, it’s not that hard.

          Pre-made solutions only solve pre-made problems. Eventually, everybody has to learn to solve problems they haven’t seen before.

          • Pre-made solutions only solve pre-made problems.

            LOL! What does that even mean? Sounds like a bumper sticker slogan for a political candidate to rally the partisans. :-)

            Eventually, everybody has to learn to solve problems they haven’t seen before.

            Without standardized APIs, nobody solves any problems. This is an example of the type of functionality that should be exposed as an API by core.

            Just sayin…

  3. Great read, and I got interrested in reading Thomas Griffin’s version…. and found it here: http://tgmpluginactivation.com/

    On automating stuff, It would be lovely to auto activate/assign menu’s when activating themes.

    • Hope you can make use of the class. :-)

      What do you mean by auto activating/assigning menus? If your theme has options or you have specified a menu via one of the add_*_page functions, it will automatically be added when you active your theme (assuming that file has successfully been included).

  4. All these things are possible, but if somebody hands you a hunk of library code to do them, then you know how to use that library, not how it works.

    That statement is right on the money, however unfortunate it may be. You’ve done an excellent job explaining how to do this stuff. :-)

    • Well, yeah. Of course, sometimes it’s speed of development you’re looking for, especially when making something for a client. In which case using a well-made library can save a whole lot of time and brain power.

      So there’s arguments for and against, I guess. :)

  5. All these things are possible, but if somebody hands you a hunk of library code to do them, then you know how to use that library, not how it works. I dislike using libraries for this reason.

    Thanks for the class example.

    While I understand the need to know how to do it, I don’t get the dislike part, I use WordPress, a library by the way, because it doesn’t make sense to do it for myself, classes offer a more efficient to reuse code without having to rewrite it. We all know how much rewritten code sits in the WP plugin directory…

    • Meh. Just my personal opinion. I find most libraries too cumbersome half the time. Difficult to read, hard to use, etc. This varies though. For example, using a library like SimplePie to parse feeds, for example… that’s fine. Using a PHP library to talk to Facebook’s API is kind of overkill. People tend to write libraries for what sometimes seem to me to be the simplest of tasks. If I can write the code I need to do the job in like 10-20 lines, then using a library to do it strikes me as overkill.

      This tends to be specific to PHP though, it’s not quite the same on other systems. You can’t live without having truckloads of libraries in Java, for example.

      • I agree with you, there are libraries that are poorly written and bloated, on the other hand if you open the WordPress twenty eleven theme functions file you will see the same register_widget function copy and pasted five times, this for me is way more efficient.

        
        cwp::register_sidebar('Top Sidebar', 'top-sidebar', 'Top sidebar widget');
        cwp::register_sidebar('info 1', 'info-1', 'Display widgets in the first footer box');
        cwp::register_sidebar('info 2', 'info-2', 'Display widgets in the second footer box');
        cwp::register_sidebar('info 3', 'info-3', 'Display widgets in the third footer box');
        cwp::register_sidebar('info 4', 'info-4', 'Display widgets in the fourth footer box');
        
        

        Libraries are simply collections of variables and functions written more efficiently. I want to see more libraries like like TGM’s saves me from having to do it for myself in addition the code is well documented and looks pretty easy to extend…

        • See, no, that right there is horrible. It’s unreadable, and you have no idea what it’s doing. Inefficient and sloppy code, that is.

          Code should be self-documenting to a greater extent. Named variables in the call is much better than unnamed anonymous variables like you’re using above.

          • I’m a bit surprised at your response and I really don’t get your point! You do realize that this is a static function? You have not yet seen the code behind the function so it’s a bit offish to say it is sloppy!

            Now let me explain, the code replaces this (code below) in your functions file and is simply the same code placed in a static PHP function, so if you are familiar to writing the arrays in the register_sidebar you are now doing the same thing without the copy – paste, copy – paste, copy – paste ,copy – paste… repetition you find in a lot in WordPress. The code behind the function is exactly the same as the one below just placed in a class function / object to reduce the unnecessary bloat that happens code!!!!

            That is the importance of using classes!

            register_sidebar( array(
            		'name' => __( 'Main Sidebar', 'twentyeleven' ),
            		'id' => 'sidebar-1',
            		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
            		'after_widget' => "</aside>",
            		'before_title' => '<h3 class="widget-title">',
            		'after_title' => '</h3>',
            	) );
            
            	register_sidebar( array(
            		'name' => __( 'Showcase Sidebar', 'twentyeleven' ),
            		'id' => 'sidebar-2',
            		'description' => __( 'The sidebar for the optional Showcase Template', 'twentyeleven' ),
            		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
            		'after_widget' => "</aside>",
            		'before_title' => '<h3 class="widget-title">',
            		'after_title' => '</h3>',
            	) );
            
            	register_sidebar( array(
            		'name' => __( 'Footer Area One', 'twentyeleven' ),
            		'id' => 'sidebar-3',
            		'description' => __( 'An optional widget area for your site footer', 'twentyeleven' ),
            		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
            		'after_widget' => "</aside>",
            		'before_title' => '<h3 class="widget-title">',
            		'after_title' => '</h3>',
            	) );
            
            	register_sidebar( array(
            		'name' => __( 'Footer Area Two', 'twentyeleven' ),
            		'id' => 'sidebar-4',
            		'description' => __( 'An optional widget area for your site footer', 'twentyeleven' ),
            		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
            		'after_widget' => "</aside>",
            		'before_title' => '<h3 class="widget-title">',
            		'after_title' => '</h3>',
            	) );
            
            	register_sidebar( array(
            		'name' => __( 'Footer Area Three', 'twentyeleven' ),
            		'id' => 'sidebar-5',
            		'description' => __( 'An optional widget area for your site footer', 'twentyeleven' ),
            		'before_widget' => '<aside id="%1$s" class="widget %2$s">',
            		'after_widget' => "</aside>",
            		'before_title' => '<h3 class="widget-title">',
            		'after_title' => '</h3>',
            	) );
            
            • Yes, I know exactly what you’re talking about, and the lines you pasted above are more readable and more descriptive and more verbose than the lines you posted before.

              I’m speaking entirely about readability here. Those “copy-pasted” lines you dislike are better than your other option. IMO, of course.

              Basically, I do not agree with the practice of adding wrappers solely to make one-line bits of code. The register_sidebar calls you have above have named variables. Even not knowing how the function works, one can pretty much deduce what it’s supposed to do just from looking at the call being made. Can’t do that with your class’s static function calls above.

              Those 48 lines are better than your 5 lines because the 48 lines make immediate sense even if you don’t know how register_sidebar works.

              • It is also very inefficient, repetitive and a very poor coding standard, some people would even call it sloppy and bloated, as for documentation PHP doc is now the standard way to document your code…

                • Code, of any type, should be mostly self-documenting. Having to wrap layers upon layers of comments and documentation is annoying, makes things more difficult, and is generally bad practice.

                  You don’t need crazy amounts of docblocks and comments when the code is clear and capable of being read easily. Comments in code should be reserved for special cases that need further clarification beyond the code, and docblocks should be constrained to high level explanations and descriptions of possible parameters and return values.

                  You’re welcome to your opinion. But I still think that you’re wrong. :)

                • Here is the register sidebar function from the WordPress code

                  /**
                   * Builds the definition for a single sidebar and returns the ID.
                   *
                   * The $args parameter takes either a string or an array with 'name' and 'id'
                   * contained in either usage. It will be noted that the values will be applied
                   * to all sidebars, so if creating more than one, it will be advised to allow
                   * for WordPress to create the defaults for you.
                   *
                   * Example for string would be <code>'name=whatever;id=whatever1'</code> and for
                   * the array it would be <code>array(
                   *    'name' => 'whatever',
                   *    'id' => 'whatever1')</code>.
                   *
                   * name - The name of the sidebar, which presumably the title which will be
                   *     displayed.
                   * id - The unique identifier by which the sidebar will be called by.
                   * before_widget - The content that will prepended to the widgets when they are
                   *     displayed.
                   * after_widget - The content that will be appended to the widgets when they are
                   *     displayed.
                   * before_title - The content that will be prepended to the title when displayed.
                   * after_title - the content that will be appended to the title when displayed.
                   *
                   * <em>Content</em> is assumed to be HTML and should be formatted as such, but
                   * doesn't have to be.
                   *
                   * @since 2.2.0
                   * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
                   *
                   * @param string|array $args Builds Sidebar based off of 'name' and 'id' values
                   * @return string The sidebar id that was added.
                   */
                  function register_sidebar($args = array()) {
                  	global $wp_registered_sidebars;
                  
                  	$i = count($wp_registered_sidebars) + 1;
                  
                  	$defaults = array(
                  		'name' => sprintf(__('Sidebar %d'), $i ),
                  		'id' => "sidebar-$i",
                  		'description' => '',
                  		'class' => '',
                  		'before_widget' => '<li id="%1$s" class="widget %2$s">',
                  		'after_widget' => "</li>\n",
                  		'before_title' => '<h2 class="widgettitle">',
                  		'after_title' => "</h2>\n",
                  	);
                  
                  	$sidebar = wp_parse_args( $args, $defaults );
                  
                  	$wp_registered_sidebars[$sidebar['id']] = $sidebar;
                  
                  	add_theme_support('widgets');
                  
                  	do_action( 'register_sidebar', $sidebar );
                  
                  	return $sidebar['id'];
                  }
                  

                  Show me the named variables in the function seems like a lot of php doc to explain how the function works to me.

                  Now here is my function

                  /**
                       * 
                       * @param type $name
                       * @param type $widget_id
                       * @param type $description
                       * @param type $id
                       * @param type $div
                       * @param type $title
                      *
                      * <code>
                      * //example
                      * cwp::add_widget('Top Sidebar', 'top-sidebar', 'Top sidebar widget');
                      * </code>
                       */
                      public static function register_sidebar($name, $widget_id, $description="", $id='widgets', $div="aside", $title='h3') {
                          //$widget_id = preg_replace(" ", "-", $name);
                          register_sidebar(array(
                              'name' => __(ucfirst($name), $id),
                              'id' => $name,
                              'description' => __($description),
                              'before_widget' => '<' . $div . ' id="%1$s" class="widget %2$s">',
                              'after_widget' => "</{$div}>",
                              'before_title' => '<' . $title . ' class="widget-title">',
                              'after_title' => '</' . $title . '>',
                          ));
                      }
                  

                  Now tell me which is self documenting???

                • Anyways sorry to hijack the post, I do agree with mot of what you say though

                • I’m not talking about the function… I’m talking about the function *call*.

                  This:

                  register_sidebar( array(
                         'name' => __( 'Main Sidebar', 'twentyeleven' ),
                         'id' => 'sidebar-1',
                         'before_widget' => '<aside id="%1$s" class="widget %2$s">',
                         'after_widget' => "</aside>",
                         'before_title' => '<h3 class="widget-title">',
                         'after_title' => '</h3>',
                  ) );
                  

                  is clearer and easier to understand than this equivalent:

                  cwp::register_sidebar('Main Sidebar', 'sidebar-1');
                  

                  If I have to go look at the function to see what the parameters correspond to, then it’s already not self-documenting.

                  Furthermore, your code for the class-based static register_sidebar function has an error in it. I18N based translation will not work with that function because the string won’t get marked for translation in the PO/POT files, and variable based text-domains are incorrect. So the strings you used in your theme are now untranslatable. See Mark’s post on the topic for more info on text-domains.

                • Yes there is an error thanks for pointing that out, Translation is something i hate but I recognize it’s importance so I will pay more attention to how it works… Good thing I did not have that piece of code duplicated 5+ times would have been hell to fix :) :)

  6. Thanks for this explanation, Otto. I’ve been checking for defined plugin functions in my themes, since I didn’t know how to do this before.

  7. im getting Call to undefined function get_plugins() when trying this code, not sure why

    • Ditto. But…

      It works fine from an admin hook but I also get the ‘Call to undefined function get_plugins()’ when attaching it to a frontend hook (wp_head, after_theme_setup, etc.).

      • Most of the admin stuff isn’t loaded on front-end hooks, and really, you shouldn’t need this sort of dependency checking on the front-end anyway. Use function_exists and similar to check to see if the plugin you need to call is there or not.

        • Funny you should say that ;)

          I just got done adding an “include plugin.php” to the constructor so it would work on the frontend and realized that the links would do a non-admin absolutely no good. Thanks for the speedy reply.

  8. […] Update: As brought up in the comment, it would be much better if theme authors simply use Theme/Plugin dependencies. Here is a great article by Otto talking about Theme/Plugin Dependencies. […]

  9. […] deactivate the child and so on and so forth. I’m not going to write it all for you (though Otto wrote a lot about it for themes)Now going back in your parent plugin, you can run the same check: if […]

  10. […] Wood has written a post on how to achieve dependency in plugins, and Thomas Griffin has a very full featured class to do so. But these tools are still […]

  11. I’m looking to add a version check to this class, but am not sure what the best way to go about doing it would be. If I do something like this:

    $data = get_plugin_data( 'expected_plugin_folder_name');
    $version = $data['version'];

    I would only get the right response if the end-user didn’t change the name of the folder the plugin is in, which I can’t be sure of.

    Anyone have a solution for this?

Leave a Reply

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>

Need to post PHP code? Wrap it in [php] and [/php] tags.