Find that Placeholder Part I

Finding out where a placeholder is set.

By Bob Ray  |  October 7, 2025  |  2 min read
Find that Placeholder Part I

In this article, we'll look at a utility snippet that helps you find the code that's setting a particular placeholder.

The Problem

Imagine that you have inherited a site created by another developer. You want to change the content or format of a value that's displayed with a placeholder. You've found the placeholder in the code of a template, resource, or chunk. The value of the placeholder is almost certainly set in a snippet or plugin, but which one? If the site has a lot of snippets and plugins, it can be a real pain to examine them all looking for the code that sets the placeholder.

Another use case is one that happens to me with some regularity. I know what the placeholder name is, but I can't remember the name of the custom snippet or plugin I used to set it. I have a lot of custom snippets and plugins, and they may have been written years ago, so it would be nice if there were a tool to find the code that sets the plugin.

Find that Placeholder

The solution is a fairly straightforward snippet called FindPlaceholder that searches all snippets and plugins on the site and reports the names of any that contain the placeholder name in question. This snippet will report any instance of the placeholder name, even if it's in a comment, or it's not a placeholder, so we may get some extra results, but this still beats having to do an exhaustive search through all the snippets and plugins, loading each one in the Manager, and looking for the code that sets the placeholder.

We'll put the placeholder name we're looking for in a property of the snippet tag on a new resource (let's call the snippet FindPlaceholder). The resource should be unpublished and/or hidden from menus. Here's an example snippet tag:

[[!FindPlaceholder? &placeholder=`somePlaceholder`]]

Here's the code of the FindPlaceholder snippet:

<?php
/* FindPlaceholder snippet */

/* Make this work in both MODX 2 and MODX 3 */
$prefix = $modx->getVersionData()['version'] >= 3
    ? 'MODX\Revolution\\'
    : '';

/* Get placeholder from snippet property */
$ph = $modx->getOption('placeholder', $scriptProperties, '', true);
if (empty($ph)) {
    return ('\n### Placeholder is empty');
}
$output = '';

function checkContent($content, $ph) {
    return (strpos($content, $ph) !== false);
}

$objectsToCheck = array(
   'Snippets' => 'modSnippet',
   'Plugins' => 'modPlugin',
);

foreach ($objectsToCheck as $objectName => $objectToCheck) {
    $count = 0;
    $output .= "\n### Checking " . $objectName . '';
    $objects = $modx->getCollection($prefix . $objectToCheck);
    foreach($objects as $object) {
        $content = $object->getContent();
        if (checkContent($content, $ph)) {
            $count++;
            $name = $object->get('name');
            $output .= "\n<br>&nbsp;&nbsp;&nbsp;Found placeholder in " .
                $objectName . ': ' . $name;
        }
    }
    if ($count === 0) {
        $output .= "\n<br>&nbsp;&nbsp;&nbsp;Placeholder not found in " . $objectName . 's';
    }
}
return $output;

At the top of the code above, we have the checkContent() function that checks the $content for our placeholder. It returns true if it finds one and false if not. In the function, we use str_pos() to check for the placeholder because it's the fastest method. It gives the position of the placeholder (which we don't need) if it's found. If it's not found, str_pos() returns false.

In the main code, we get the placeholder name from the snippet properties stored in the scriptProperties array. We return an error message if the placeholder is empty.

Then, we loop through the objects to search, one at a time.

foreach object to search get all the objects of that type with getCollection, and pull their code with $content = $object->getContent()

If we find the placeholder (str_pos() returned true), we add a message giving object type and the name of the object to the $output variable to be returned at the end of the snippet.

Improvements

If you are writing this for a client, you might want to beautify the output some by adding class names and some CSS, and/or making the output of each section into an ordered or unordered list. You could use a Tpl chunk for the outer structure and another Tpl chunk for the format of each line. This would be better than the ugly   code we used above to provide indentation.

It would be possible (though a little tricky) to calculate the line number where the placeholder appears in the snippet or plugin code. That would involve using the position to pull all the code up to the placeholder with substr() and counting the number of newlines by using explode() and count(). I'm not sure it would be reliable, though, and it's easy enough to edit the snippet or plugin and find the placeholder with your browser's search function.

We'll look at another improvement in the next article.

Coming Up

Some snippets or plugins might set the placeholder in a file (usually a class file) that's pulled into their code with include, include_once, require, or require_once. In those cases, our snippet won't see the placeholder because it's not in the body of the snippet or plugin code. We'll add an enhancement to handle that situation in the next article.


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.