Skip to content

Instantly share code, notes, and snippets.

@squarestar
Last active April 20, 2024 08:02
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save squarestar/37fe1ff964adaddc0697dd03155cf0d0 to your computer and use it in GitHub Desktop.
Save squarestar/37fe1ff964adaddc0697dd03155cf0d0 to your computer and use it in GitHub Desktop.
Programmatically install and activate wordpress plugins
<?php
/**
* Programmatically install and activate wordpress plugins
*
* Usage:
* 1. Edit the $pluginSlugs array at the beginning of this file to include the slugs of all the
* plugins you want to install and activate
* 2. Upload this file to the wordpress root directory (the same directory that contains the
* 'wp-admin' directory).
* 3. Navigate to <your-domain-wordpress-root>/install-wp-plugins.php (If wordpress is installed
* in its own sub-directory, <your-domain-wordpress-root> is that sub-directory, not the root
* domain of the site, e.g., example.com/wordpress/install-wp-plugins.php)
*/
$pluginSlugs = array(
'contact-form-7',
'simple-cache',
'codepress-admin-columns',
);
require_once(dirname(__FILE__) . '/wp-load.php');
require_once(ABSPATH . 'wp-admin/includes/plugin-install.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/misc.php');
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
require_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
/*
* Hide the 'Activate Plugin' and other links when not using QuietSkin as these links will
* fail when not called from /wp-admin
*/
echo '<style>a {display: none;}</style>';
class QuietSkin extends \WP_Upgrader_Skin
{
public function feedback($string) { /* no output */ }
}
/**
* Download, install and activate a plugin
*
* If the plugin directory already exists, this will only try to activate the plugin
*
* @param string $slug The slug of the plugin (should be the same as the plugin's directory name
*/
function sswInstallActivatePlugin($slug)
{
$pluginDir = WP_PLUGIN_DIR . '/' . $slug;
/*
* Don't try installing plugins that already exist (wastes time downloading files that
* won't be used
*/
if (!is_dir($pluginDir)) {
$api = plugins_api(
'plugin_information',
array(
'slug' => $slug,
'fields' => array(
'short_description' => false,
'sections' => false,
'requires' => false,
'rating' => false,
'ratings' => false,
'downloaded' => false,
'last_updated' => false,
'added' => false,
'tags' => false,
'compatibility' => false,
'homepage' => false,
'donate_link' => false,
),
)
);
// Replace with new QuietSkin for no output
$skin = new Plugin_Installer_Skin(array('api' => $api));
$upgrader = new Plugin_Upgrader($skin);
$install = $upgrader->install($api->download_link);
if ($install !== true) {
echo 'Error: Install process failed (' . $slug . '). var_dump of result follows.<br>'
. "\n";
var_dump($install); // can be 'null' or WP_Error
}
}
/*
* The install results don't indicate what the main plugin file is, so we just try to
* activate based on the slug. It may fail, in which case the plugin will have to be activated
* manually from the admin screen.
*/
$pluginPath = $pluginDir . '/' . $slug . '.php';
if (file_exists($pluginPath)) {
activate_plugin($pluginPath);
} else {
echo 'Error: Plugin file not activated (' . $slug . '). This probably means the main '
. 'file\'s name does not match the slug. Check the plugins listing in wp-admin.<br>'
. "\n";
}
}
foreach ($pluginSlugs as $pluginSlug) {
sswInstallActivatePlugin($pluginSlug);
}
@simplenotezy
Copy link

Doesn't seem to work. Tried installing: wordpress-seo, and got this error:

image

@simplenotezy
Copy link

I had to include pluggable like so:

	require_once(ABSPATH . '/wp-load.php');
	require_once(ABSPATH . 'wp-includes/pluggable.php');
	require_once(ABSPATH . 'wp-admin/includes/plugin-install.php');
	require_once(ABSPATH . 'wp-admin/includes/file.php');
	require_once(ABSPATH . 'wp-admin/includes/misc.php');
	require_once(ABSPATH . 'wp-admin/includes/plugin.php');
	require_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');

@simplenotezy
Copy link

Also, instead of guessing the installation .php file, you may do like so:

    $pluginDir = WP_PLUGIN_DIR . '/' . $slug . '/';
    $activation_success = false;

    $files = scandir($pluginDir); 
	foreach($files as $file) {
		if(is_file($pluginDir.$file)) {

			$activation = activate_plugin($pluginDir.$file);

			if(!is_wp_error($activation)) {
				$activation_success = true;
			}

		}
	}

@hansschuijff
Copy link

Thanks for this. I was looking for this kind of functionality to automatically add some plugins on my staging and dev installs. Until now, the functionality I had only activated and deactivated based on the environment, and this was new territory for me.

I reworked the code a bit and had some small issues with it, but it was a good learning experience.

My forked version is namespaced and the get_plugins() to determine if a plugin is already installed (although a file_exists() would also work) and it uses the plugins basename as a starting point instead of the slug.

My thinking there is that when the slug is known the basename is equally know to be used in a config, and it gives easy access to the is_plugin_active() function to check if the plugin is allready active. Also as @simplenotezy notes, the filename isn't always the same as the slug (for instance: the basename of "contact-form-7" is "contact-form-7/wp-contact-form-7.php" ) and the code above would issue an error in that cases.

My core functionality plugin already offers helper functionality to translate the plugin name to a plugin basename, so I can easily make my version now work with both the basename or the the human readable plugin names as a starting point.

I installed this as a must use plugin, instead of in the root, but that shouldn't change anything, although perhaps some of the necessary files maybe loaded at that point.

The styles of line 32 I found too generic, since it basically removed all the links from f.i. the plugins list and it still doesn't guarentee that a user isn't confronted with not allowed responses when trying to deactivate the plugin (by using the bulk functionality that is still present). So I probably will look for another way to handle deactivation requests and have for now just removed that styles. Since I'm the only admin in this case it doesn't matter much.

The parameters of the feedback() method have been changed in core, so that will issue an easily fixable warning.

All in all a useful starting point on this learning journey. Thanks for sharing.

You can find a copy of my forked version here:
https://gist.github.com/hansschuijff/a6c4edb4e5162c1c16006d21fa8b9c8f

Regards,

Hans

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment