Over the years, I think the concept of a “drop-in” plugin has become overloaded. What once referred to a very specific type of functionality has evolved to mean a couple of things.

  1. One of the definitions retains the original definition which is you can place specific files into the plugins directory to replace core WordPress functionality. These are not standard WordPress plugins, though. For example, you’ll likely often see files like advanced-cache.php or object-cache.php in the plugins directory. These are the original type of ‘drop-ins’ when it comes to working with WordPress.
  2. Another definition are plugins that aren’t specifically mu-plugins and they aren’t standalone plugins either. Instead, these are pieces of functionality that can be dropped into any other plugin and add functionality. Say you have two different plugins that are used by a lot of people and you want to give them the ability to add a feature without activating a new plugin. The way in which you can do this is have them drop a file into their existing plugin.

Here’s the challenge with the second definition: When you drop functionality of into the context of another plugin, that plugin may not be the only one already running the same code.

In other words, say you have a file called acme-functionality.php that can be added to any plugin. If you drop acme-functionality.php into multiple, activated plugins then you may end up with all kinds of results none of which are ideal. And why isn’t it ideal? Because you want the code to run only once.

What’s a way to check to see if a file is already running in the context of another plugin before running it’s code?

Run Custom Functionality Once in Multiple Plugins

Outlining Functionality

To be consistent, we’ll assume that the code we’re writing to drop-in to any other plugin will be referred to by acme-functionality.php.

Verifying this plugin necessitates the following functionality (or something close enough to it):

Make sure the plugin isn’t already active. This assumes we’ll have a function that returns a boolean value. And to determine this value, we need to do the following:

  1. Define a directory through which want to scan (in the case of WordPress, this would be the plugins directory and its subdirectories).
  2. Define the name of the file we only want to run once. This is the name of the file we’ve been referencing as acme-functionality.php.
  3. Count how many times the plugin is found throughout the plugins directory.
  4. Determine if it’s greater than or equal to one.

Then we can make a call to the function and if it returns false, we simply don’t run the code in the plugin.

Writing the Function

First, let’s take a look at the function that can help us run custom functionaltiy once in multiple plugins:

/**
 * Determines if this file is used in any of the other plugins running 
 * on the instance of WordPress.
 *
 * @return bool True if the file is used in any of the other plugins.
 */
function isPluginActive(): bool {
    // Define the directory to scan
    $dir = trailingslashit(
        dirname(__DIR__)
    );

    /* Define the name of the file we wish to check.
     * NOTE: This should always be the name of this file.
     */
    $fileToCheck = 'acme-functionality.php';

    // Initialize a counter to track of the number of files found
    $count = 0;

    // Recursively scan the directory and subdirectories for PHP files
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir)
    );
    foreach ($iterator as $file) {
        // If we find this file elsewhere, then increase the counter.
        if (
             $file->isFile() && 
             strtolower(pathinfo($file, PATHINFO_EXTENSION)) === 'php'
        ) {
            if ($file->getFilename() === $fileToCheck) {
                $count++;
            }
        }
    }

    return $count >= 1;
}

Note that I’m using several standard library functions such as RecursiveIteratorIterator and RecursiveDirectoryIterator.

Per the PHP manual, these are described as follows:

Can be used to iterate through recursive iterators.

RecursiveIteratorIterator

The RecursiveDirectoryIterator provides an interface for iterating recursively over filesystem directories.

RecursiveDirectoryIterator

The RecursiveIteratorIterator accepts a RecursiveDirectoryIterator which accepts a directory through which to iterate. In short, this makes it easy to iterator through all of the directories and subdirectories in the plugins directory.

Then, if the specified file name is found at least once, then we know the plugin is active.

Conclusion

When we know the code is used elsewhere in the file system, we can easily stop it from executing it again by simply calling the following conditional:

if (!isPluginActive()) {
    return;
}

// The rest of your code here.

It’s functions like this that help use write code that isn’t run any more than its needs to be run. If you wanted to take this a step a further, then it’s possible to even cache the result for a deterministic amount of time before running it again.

That’s beyond the scope of this article but it’s something to keep in mind should you be doing something similar in your own work.