Deactivate Specific Plugins on Staging & Non-Production Sites

Deactivate Specific Plugins On Staging Non Production Sites Snipsnip Pro .code Snippets

Ever wanted to have some plugins active on your Live or Production site but automatically deactivated on your Staging or Test server? Oh yes you have! This makes it easy to do that. For example, I use it to make sure my analytics or caching or auto-social posting plugins are only active on the live site and never active on the staging sites. This script assumes that every site is Production unless the site’s domain contains one of the `$stagingKeywords` (which you can customize) and automatically deactivates the plugins you put in the `PLUGINS_TO_DEACTIVATE_ON_STAGING` list. And if you need the reverse functionality, then check out Deactivate_Plugins_On_Production.

What it does…

This code snippet provides a way to deactivate specific plugins on staging and non-production sites. It checks if the current site URL contains any of the specified staging keywords, indicating a staging environment. If it is a staging site or if the deactivations are forced, it filters out the specified plugins from the list of active plugins. This prevents those plugins from being loaded and executed on the site.

Why it does it…

Deactivating specific plugins on staging and non-production sites is important because it helps prevent any unintended effects or conflicts that may arise from having certain plugins active during development or testing. By selectively deactivating these plugins, developers can ensure a clean and controlled environment for their work, without the risk of interfering with the site’s functionality or introducing bugs.

How it does it…

– The code defines a class called `Deactivate_Plugins_On_Staging` that contains the functionality for deactivating plugins on staging sites.
– The class has a private variable `$stagingKeywords` that holds an array of keywords used to detect staging environments. These keywords include ‘staging’, ‘dev’, ‘local’, ‘test’, ‘sandbox’, and ‘demo’.
– There is another private variable `$forceDeactivations` that can be set to true to force the deactivation of plugins regardless of the environment detection.
– The class has a constant `PLUGINS_TO_DEACTIVATE_ON_STAGING` that lists the slugs of the plugins to be deactivated on staging sites.
– The constructor of the class checks if the deactivations should be applied based on the `$forceDeactivations` setting or if the site is detected as a staging site. If so, it adds a filter to the `option_active_plugins` hook, which calls the `deactivatePluginsOnStaging` method.
– The `isStagingSite` method checks if the current site URL contains any of the staging keywords. It converts the site URL to lowercase and compares it with each keyword. If a match is found, indicating a staging environment, it returns true.
– The `deactivatePluginsOnStaging` method takes the list of currently active plugins’ file paths as a parameter. It iterates over the `PLUGINS_TO_DEACTIVATE_ON_STAGING` array and deactivates the specified plugins by filtering them out from the list of active plugins. It supports wildcard matching for plugin slugs, allowing for more flexibility in specifying plugins to deactivate.
– If a plugin slug in `PLUGINS_TO_DEACTIVATE_ON_STAGING` contains a wildcard character ‘*’, it is replaced with ‘.*’ to create a regular expression pattern. The `array_filter` function is used to filter out the plugins whose slugs match the pattern.
– If a plugin slug doesn’t contain a wildcard, a direct match is performed by comparing the plugin slug with the path of each active plugin. If a match is found, the plugin is unset from the list of active plugins.
– Finally, the modified list of active plugins is returned, ensuring that the array is correctly indexed.

See the code…

<?php

/**
 * Deactivate Specific Plugins on Staging & Non-Production Sites [SnipSnip.pro] - https://snipsnip.pro/s/827
 */
if (!class_exists('Deactivate_Plugins_On_Staging')) {
    /**
     * Selectively deactivates plugins on staging and similar environments.
     */
    class Deactivate_Plugins_On_Staging {
        private $stagingKeywords = ['staging', 'dev', 'local', 'test', 'sandbox', 'demo'];
        private $forceDeactivations = false; // Set to true to deactivate regardless of environment detection.
        // List the slugs of plugins you want to deactivate
        const PLUGINS_TO_DEACTIVATE_ON_STAGING = [
            'query-monitor',
            'create-block-theme',
            'ai-engine*'
        ];

        public function __construct() {
            // Apply deactivations if forced or if the site is detected as a staging site.
            if ($this->forceDeactivations || $this->isStagingSite()) {
                add_filter('option_active_plugins', [$this, 'deactivatePluginsOnStaging']);
            }
        }

        /**
         * Checks if the current site URL matches any of the specified staging environment keywords.
         *
         * @return bool True if a matching keyword is found, indicating a staging environment.
         */
        private function isStagingSite() {
            $currentUrl = strtolower(get_option('siteurl'));

            foreach ($this->stagingKeywords as $keyword) {
                if (strpos($currentUrl, $keyword) !== false) {
                    return true;
                }
            }

            return false;
        }

        /**
         * Deactivates the specified plugins by filtering them out from the list of active plugins.
         *
         * This method is applied in staging environments only.
         * 
         * @param array $activePlugins The list of currently active plugins' file paths.
         * @return array The modified list with specific plugins deactivated.
         */
        public function deactivatePluginsOnStaging($activePlugins) {
            foreach (self::PLUGINS_TO_DEACTIVATE_ON_STAGING as $pluginPattern) {
                $pattern = strtolower($pluginPattern);
                
                if (strpos($pattern, '*') !== false) {
                    $pattern = str_replace('*', '.*', $pattern);
                    $activePlugins = array_filter($activePlugins, function($plugin) use ($pattern) {
                        // Extract plugin slug from the path for comparison
                        $pluginSlug = strtolower(substr($plugin, 0, strpos($plugin, '/')));
                        // Match against pattern (with wildcard support)
                        return !preg_match('/^' . $pattern . '$/', $pluginSlug);
                    });
                } else {
                    // Handle direct plugin slug match (no wildcards)
                    $pluginPath = $pattern; // Direct matching of the plugin slug to path
                    $key = array_search("$pluginPath/$pluginPath.php", $activePlugins);
                    if ($key !== false) {
                        unset($activePlugins[$key]);
                    }
                }
            }

            return array_values($activePlugins); // Ensure the array is correctly indexed after modifications
        }
    }

    new Deactivate_Plugins_On_Staging();
}

See the code on github…