TL;DR: Here’s how you can write domain-specific, testable helper functions in procedural programming in WordPress.


If you decide to use procedural code when writing plugins or extensions for WordPress, this doesn’t mean that everything has to be in a monolithic function. That is, it’s still possible – and a good idea – keep domain-specific work contained within its own function.

So even if you’re using a weird mix of namespaces and autoloading along with procedural programming, you can still take advantage of functions that do one thing and one thing well to help keep the code a bit cleaner. I will say, though, this is where docblocks come in handy.

In this article, I’ll share an example of how to simultaneously using procedural programming, anonymous functions, and utility functions (or helper functions) to make sure that you’re writing code that’s well-documented and easy to follow.

Helper Functions in Procedural Programming in WordPress

Let’s say the purpose of the plugin is to look for a specific substring within the content of the post and remove said substring if it’s found.

To do this, we’ll need:

  • a hook that allows us to look at the content,
  • determine if the substring is present,
  • remove the substring if so,
  • return the modified content.

When reading the above notes, it should almost read exactly how the procedure should perform – and it is – but if you’re curious as to where the anonymous may be, then a safe bet would be the entry point into the program.

Note, however, that it doesn’t have to be an anonymous function. It can be named and invoked just as any other function may but since this has been a point of discussion of the last few articles, why not put it into place now?

So we can take one of the existing WordPress hooks, such as the_content and use a helper function to determine if a substring is present.

The code may look something like this:

add_filter(
    'the_content',
    /**
     * Removes a specified substring from the content, if found. 
     * 
     * @param string $content The content to process.
     * 
     * @return string $content The processed content.
    function (string $content) {
        if (!is_singular() || !in_the_loop() || !is_main_query())
        {
            return $content;
        }

        substringIsFound($substring, $content) ?
           return processedContent($substring, $content) :
           return $content;
    }
);

Next, if the code is present, then we’d want to remove it. There are a few ways this can be done but if you want the primary function of your plugin to follow the procedure outlined above, here’s one way you can do it:

/**
 * Looks to see if a specified substring exists within the content. Note
 * this only looks for the first occurance of the substring.
 *
 * @param string $substring The string for which to look.
 * @param string $content   The content in which to look.
 *
 * @return bool Whether or not the substring was found.
 */
function substringIsFound(string $substring, string $content): bool
{
    return (false !== stripos($content, $substring));
}

Finally, return the result of the function and make sure its the updated content:

/**
 * Removes the first iteration of the substring found in specified content.
 *
 * @param string $substring The string for which to look.
 * @param string $content   The content in which to look.
 *
 * @return string The modified content.
 */
function processedContent(string $substring, string $content): string
{
    return str_ireplace($substring, $content);
}

This will pass the modified content back to WordPress to present to the browser.

📝 Note the purpose of the code above is not to necessarily be used as-is in a plugin. Instead, it’s meant to show how to break apart concepts for a specific function and use said functions to improve readability and testability.

A Simple Exercise

If you’re used to procedural programming in WordPress, or even in object-oriented programming, then this particular algorithm isn’t complicated. But that’s not the point.

Remember, the point of sharing code like this so to show that functions need not be monoliths especially in the context of procedural programming. You can still write domain-specific, testable functions outside the scope of the main function that allow you to document, test, and examine the inputs and outputs in isolation.