Placeholder not processed in chunk, raw placeholder tag appears on website [resolved]

I have a snippet that creates a html grid of images. The snippet accepts a property &ids that contains a comma separated list of resource ids. It loops through the resouce ids creating an array of properties. Properties include image path and image alt text both of which are stored as TVs for each Resource. The snippet generates a block of html by processing the array through a template chunk with $chunk->process($arr_output_props, $template);. The chunk contains placeholders where each of the properties retrieved from the TVs should be output.

It works as intended for the text tvs however the template chunk contains a snippet which processes the image path to create a responsive element with multiple sources. This is stored in a TV of type image. These source files doe the element are generated with phpthumbof.

The issue is phpthumbof throws an error

File not found: K:/virtualhosts/domain.co.uk/httpsdocs/[[+image]]  *** Skipping ***

This is because the placeholder tag [[+image]] is sent to phpthumbof instead of the actual image file path assets/media/photo.jpg.

If I place the [[+image]] tag in the chunk outside of the snippet that calls phpthumbof the correct file path is shown. If I replace the [[+image]] placeholder with a hard coded image file path assets/media/photo.jpg the responsive images are generated by phpthumbof.

Something is preventing the [[+image]] tag being parsed and I can’t figure why.

Does anyone know what it wrong with the following code?

It may be relevant that the site is using pdoTools so is not using the default MODX parser. This is an update to an existing site that has used the generatePicture snipped for years without issue.

Snippet call

[[resource-grid? &ids=`292,56,293,294,295,296` &size=`md`]]

resource-grid snippet

<?php
/**
 * resource-grid
 * 
 * @version 0.1
 * @author Chris Dempsey, August 2021
 *
 * DESCRIPTION
 *
 * returns a grid of resources
 *
 * PROPERTIES
 *
 * &ids IDs of the resource content to fetch default: exits if none
 * &size size of output grid, options: sm, md, lg, default: md
 *
 * USAGE
 *
 * [[-resource-grid? &ids=`292,56,293,294,295,296` &size=`md`]]
 *
 */

// silent exit if we don't have modx
if(empty($modx) || !($modx instanceof modX)) return;

// silent exit if we don't have ids
if(empty($ids)) return 'no ids';

// define $output
$output = '';

// strip whitespace from supplied $ids
$ids = preg_replace('/\s+/', '', $ids);

// define array of allowed values for $size
$arr_allowed_sizes = array("sm", "md", "lg");

// ensure supplied $size is lowercase
strtolower($size);

// check if supplied $size is in allowed array
if (in_array($size, $arr_allowed_sizes)) {
    // allowed so set tpl
    $tpl = 'resource-grid-' . $size . '.tpl';
} else {
    // set tpl to md
    $tpl = 'resource-grid-md.tpl';
}

// check if chunk exists for $tpl (ie. missing if $modx->getChunk is empty)
if (empty($modx->getChunk($tpl)))  {
    die('[resource-grid] error: specified tpl chunk not found: ' . $tpl);
}

// loop through supplied resource ids and get content to generate output
$arrIds = explode(',', $ids);

// loop through ids to get required content
foreach ($arrIds as $id) {
    // check $id is integer otherwise continue to next id
    if(!is_int((int)$id)) continue;
    
    // get resource using getObject method
    $resource = $modx->getObject('modResource', $id);
    
    // if resource exists get data to populate template
    if(!$resource) {
        // current $id from $arrIds is not a resource, continue to next id in array
        continue;
    } else {
        // we have resource to work with
        
        // define array to hold output
        $arr_output_props = array();
        
        // generate url for current resource id
        $url = $modx->makeUrl($id);

        // get 3 elements required from resource to include in $output: image (img-resource-default), heading (pagetitle), tagline (description)
        $image = $resource->getTVValue('img-resource-default');
        $alt = $resource->getTVValue('img-resource-default-alt');
        $alt = htmlentities($alt);
        
        $heading = $resource->get('pagetitle');
        $heading = htmlentities($heading);
        
        // show longer tagline (introtext) on $size=lg otherwise use short (description)
        if($size=='lg') {
            $tagline = $resource->get('introtext');
        } else {
            $tagline = $resource->get('description');
        }
        $tagline = htmlentities($tagline);
        
        // add elements to $arr_output_props
        $arr_output_props['url']     = $url;
        $arr_output_props['image']   = $image;
        $arr_output_props['alt']     = $alt;
        $arr_output_props['heading'] = $heading;
        $arr_output_props['tagline'] = $tagline;
        
        // get template chunk from chunk name in $tpl variable
        $template = $modx->getChunk($tpl);

        // Create the temporary chunk (Source: Parsing a String at: https://docs.modx.com/revolution/2.x/developing-in-modx/other-development-resources/class-reference/modx/modx.getchunk)
        $uniqid = uniqid();
        $chunk = $modx->newObject('modChunk', array('name' => "{tmp}-{$uniqid}"));
        $chunk->setCacheable(false);
        
        // populate $template with values from properties array
            $output .= $chunk->process($arr_output_props, $template);
    }
}

// $output = htmlentities($output); // can't do this if allowing any field to be specified eg. *content could mean htmlentities being processed by TinyMCE and again here

// return output wrapped with a .row
return '<div class="row">' . $output . '</div>';





resource-grid-md.tpl called by resource-grid snippet

        <div class="col-lg-6 p-0x my-4">
            baseUrl
            [[getMediaSourceAttribute? &attribute=`baseUrl` &msId=`2` ]][[getMediaSourceAttribute? &attribute=`basePath` &msId=`2` ]][[+image]]
            <div class="feature-card">
                <a href="[[+url]]">
                    [[generatePicture?
                        &src=`[[+image]]`
                        &ratio=`16x9`
                        &breakpoints=`540,450,690,510,525`
                        &hd=`1`
                        &alt=`[[+alt]]`
                        &classPicture=``
                        &classImg=`img-fw object-fit-cover`
                    ]]
                    <div class="feature-card-body d-none d-md-block">
                        <h4 class="feature-card-title">[[+heading]]</h4>
                        <p class="feature-card-text">[[+tagline]]</p>
                    </div>
                </a>
            </div>
        </div>

Thanks,

Chris

Is there a reason why you use all these lines and create a temporary chunk

// get template chunk from chunk name in $tpl variable
$template = $modx->getChunk($tpl);

// Create the temporary chunk (Source: Parsing a String at: https://docs.modx.com/revolution/2.x/developing-in-modx/other-development-resources/class-reference/modx/modx.getchunk)
$uniqid = uniqid();
$chunk = $modx->newObject('modChunk', array('name' => "{tmp}-{$uniqid}"));
$chunk->setCacheable(false);

// populate $template with values from properties array
$output .= $chunk->process($arr_output_props, $template);

instead of just using

$output .= $modx->getChunk($tpl, $arr_output_props);

to generate the ouput.
I believe this would also solve your problem.

@halftrainedharry You were correct, using $output .= $modx->getChunk($tpl, $arr_output_props); resolved the issue.

Looks like I’ve misunderstood the example in the MODX docs at
https://docs.modx.com/current/en/extending-modx/modx-class/reference/modx.getchunk#parsing-a-string

I used this at some point in the distant past and copied the code for a fast start on the current task which is almost identical to the original.

Thanks