StripWords with Multiple Replacements

Using our custom output modifier, StripWords, to use a different replacement for each word stripped.

By Bob Ray  |  June 25, 2024  |  5 min read
StripWords with Multiple Replacements

In the previous article, we looked at a custom output modifier (and plugin) to remove or replace unwanted words or phrases from a web page. The output modifier could be used with any tag in MODX revolution.

In this article we'll see how to allow a different replacement string for each problem word or phrase. We'll also take a look at techniques for parsing strings.

Multiple Replacements

Suppose that you want to do multiple replacements to text on your site. The PHP str_replace() function will take an array for both its first and second argument (lets call the two arrays $find and $replace). The function replaces the first value in the $find array with the first value in the $replace array. Then it replaces the second value in the $find array with the second value in the $replace array — and so on through the arrays. It's important that the two arrays have the same number of elements.

In the previous example, we used a chunk to hold the strings. We'll do that here too.

We could put two separate lines in the chunk, one for the 'find' array and one for the 'replace' array. It's more convenient, though to create a single line with pairs of find/replace entries. It's also a little easier to parse them that way. Since we're not actually stripping the words, let's call the chunk WordsToReplace Here's the conventional format for the WordsToReplace chunk:

hell:heck,damn:darn,MODx:MODX

In the chunk, the pairs of words are delimited by a comma. The two words of each pair are separated by a colon.

In our snippet, we need to process that string to create our two arrays. The first step is to initialize our two arrays, get the chunk's content, and split it at the commas to get each pair (find/replace):

$find = array();
$replace = array();

$line = $modx->getChunk('WordsToReplace');
$pairs = array_map('trim', explode(',', $line));

Using array_map and trim makes sure that there are no leading or trailing spaces, tabs, or linefeeds, in case the user has mis-entered the values. At this point, the $pairs array looks like this:

array(
    [0] => 'hell:heck'
    [1] => 'damn:darn'
    [2] => 'MODx:MODX'
)

Next, we need to walk through that array, adding the appropriate values to our two arrays. We'll add an error check to make sure each member of the $pairs array has a colon:

foreach($pairs as $pair) {
    if (strpos($pair, ':') === false) {
        // $modx->log(modX::LOG_LEVEL_ERROR, '[stripWords] Parse error - missing colon');
        /* add a colon to prevent null entries */
        $pair = $pair . ':';
    }
    $couple = array_map('trim', explode(':', $pair));
    $find[] = $couple[0];
    $replace[] = $couple[1];
}

The modx log line is optional. It will report missing colons, but you may not want to treat that as an error. For entries with a missing colon, the word will be replaced with nothing, which you might want. For example, you might want to remove some entries and replace others by using a string like this in the chunk:

hell,damn,MODx:MODX

With that string, the first two would be removed and 'MODx' would be replaced with 'MODX'.

Finally, we need to use a slight modification to our output modifier to use the two arrays:

return str_replace($find, $replace , $input);

The Full Code

Putting it all together, here's the full code of our stripWords output modifier:

$find = array();
$replace = array();

$line = $modx->getChunk('WordsToReplace');
$pairs = array_map('trim', explode(',', $line));
foreach($pairs as $pair) {
    if (strpos($pair, ':') === false) {
        // $modx->log(modX::LOG_LEVEL_ERROR, '[stripWords] Parse error - missing colon');
        /* add a colon to prevent null entries */
        $pair = $pair . ':';
    }
    $couple = array_map('trim', explode(':', $pair));
    $find[] = $couple[0];
    $replace[] = $couple[1];
}
return str_replace($find, $replace , $input);

Speed Considerations

If page-load speed are critical for you, especially if the cache is often cleared, you can speed things up very slightly by doing the replacements in a plugin attached to the OnWebPagePrerender System Event. The only change to the code would be using $modx->resource->_output for the content instead of $input, so the last line of the code would be replaced by this:

$modx->resource->_output = str_replace($find, $replace , $modx->resource->_output);
return '';

The speed improvement would be very insignificant, however. It would only affect pages that are not cached and would only cut out the tiny amount of time necessary for MODX to identify the output modifier. Since it's not a conditional modifier and there are no arguments to parse, that would probably take just a few milliseconds.

Another possible way to speed things up would be to use strpos() on each word to be replaced and return without calling str_replace() if none of them are present in the content. The effects of this would also be minimal, and depending on the number of words involved, it might actually slow things down. You'd have to benchmark it to be sure.

Coming Up

Sometimes, creating two separate arrays for str_replace() is inconvenient and can lead to errors where the strings to be replaced don't line up with the replacements. It works very well for this use case, but in the next article, we'll look at a way to do replacements with a single associative array of keys and values.


Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.