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

I’m looking at this again because the website has to be migrated to a new server.

Having established the staging version there are errors logged that I didn’t notice previously.

The error looks critical however the expected images are still generated as normal.

[2023-06-17 13:04:23] (ERROR @ /home/websvc/apps/domain/httpdocs/core/components/phpthumbof/model/phpthumbof.class.php : 156) [pThumb] Resource: 427 || Image: (none)
File not found: /home/websvc/apps/domain/httpdocs/[[+image]]  *** Skipping ***

If the [[+image]] placeholder is written out to screen it is the correct relative path eg. assets/media/image.jpg.

As I understand phpthumbof then prefixes input with $_SERVER['DOCUMENT_ROOT']. This value matches that seen in the error above /home/websvc/apps/domain/httpdocs/. So this must be why the images are output as expected but doesn’t explain the error being logged.

Can anyone suggest why the error is logged when it appears the code is working as it should?

Thanks

The problem is, that in this line of your code ($modx->getChunk($tpl)), the chunk “resource-grid-md.tpl” already gets parsed, but no properties are provided.

This means, that the snippet “generatePicture” gets executed twice. Once with [[+image]] as the source and once with the correct value.


Use a different method to check if a chunk with this name exists. Maybe something like this works:

if (!$modx->getObject('modChunk', ['name' => $tpl])) { ... }

Well spotted, this resolves the issue, thank you.

Updated snippet now reads as below.

// check if chunk exists for $tpl (ie. tpl is missing if $modx->getChunk returns empty)
// ISSUE - can't use this, it appears to work but executes getChunk in the process which
//       - wastes resources because it means getChunk is called twice (here and later in the snippet) and
//       - if the chunk contains a snippet that expects a placeholder errors will be logged because getChunk
//         should be called with an array of properties so it can parse any placeholders, without this the snippet in the chunk receives the raw placeholder [[+image_src]]
//       - ref. https://docs.modx.com/3.x/en/extending-modx/modx-class/reference/modx.getchunk

/*
if (empty($modx->getChunk($tpl)))  {
    die('[resource-grid] error: specified tpl chunk not found: ' . $tpl);
}
*/

// use getObject instead
if (!$modx->getObject('modChunk', ['name' => $tpl])) { 
    die('[resource-grid] error: specified tpl chunk not found: ' . $tpl);
}
// refs. https://docs.modx.com/3.x/en/extending-modx/xpdo/class-reference/xpdo/xpdo.getobject
//       https://community.modx.com/t/placeholder-not-processed-in-chunk-raw-placeholder-tag-appears-on-website-resolved/4351/4
1 Like