Help with writing a QR Code plugin - cached alias/url OnDocFormSave

I am in the middle of building a QR code generation plugin that on saving a resource, creates a QR code based on the resource url and saves it to disk, and then if a file exists for that resource, it adds a tab to the resource that includes the QR code image.

My problem is that it seems to require TWO saves to get the correct url into the image generation snippet. When I change the alias and save, the script executes and generates the image, however it contains the previous url with the old alias. If I just save a second time, the image gets replaced with the updated url with the new alias.

Is this due to some caching of the modx resource? Anyone have any tips to resolve? Some of my code is below for reference:

$webroot = $_SERVER['DOCUMENT_ROOT'];
$eventName = $modx->event->name;

$relativePath = '/content/qrcodes/';
$filePath = $webroot . $relativePath;
$filePrefix = 'qrcode.';
$fileExt = '.png';
$fullQRFile = $filePath . $filePrefix . $id. $fileExt;

$timestamp = time();

if (!is_dir($filePath)) {
    if (!mkdir($filePath, 0755, true)) {
        $modx->log(modX::LOG_LEVEL_ERROR, "Failed to create directory: $filePath");
    }
}

if (file_exists($fullQRFile)) {
    $modx->regClientStartupHTMLBlock('
    <script type="text/javascript">
        MODx.on("ready", function() {
            MODx.addTab("modx-resource-tabs", {
                title: "QR Code",
                id: "qrcode-resource-tab",
                width: "98%",
                items: [{
                    html: "<div id=\'qrcode-content\'></div>"
                }],
                listeners: {
                    activate: function(tab) {
                        loadQRCodeContent();
                    }
                }
            });

            function loadQRCodeContent() {
                var contentDiv = Ext.get("qrcode-content");
                var relativePath = "' . $relativePath . '";
                var filePrefix = "' . $filePrefix . '";
                var id = "' . $id. '";
                var fileExt = "' . $fileExt . '";
                var timestamp = new Date().getTime();

                contentDiv.update("<a href=\"" + relativePath + filePrefix + id + fileExt + "?timestamp=" + timestamp + "\" target=\"_blank\"><img width=\"512\" height=\"512\" src=\"" + relativePath + filePrefix + id + fileExt + "?timestamp=" + timestamp + "\"></a>" +
                    "<br><a href=\"" + relativePath + filePrefix + id + fileExt + "\" target=\"_blank\">Click here to download the PNG of this QR Code</a>");
            }

            loadQRCodeContent(); // Initial load of content
        });
    </script>');
}

switch ($eventName) {
    case 'OnBeforeDocFormSave':
        
    break;
    
    case 'OnDocFormSave':     
        if ($mode == modSystemEvent::MODE_UPD && $id > 0 && $id !== '') {
            $qrcodeParams = array(
                'id' => $id 
            );
            $qrcodeImage = $modx->runSnippet('qrCode', $qrcodeParams);
        }
    break;
}

Is the problem that the QR Code image is generated with the old URL during saving, or that the displayed image in the tab ā€œQR Codeā€ is just not updated after saving (until you reload the page)?


  • On what events to you run this plugin? I assume additional to OnDocFormSave, you also use OnDocFormRender to add the custom tab?
  • From the code you posted, itā€™s not clear how you get the resource url in the snippet ā€œqrCodeā€. This could be important if itā€™s indeed a caching problem.

@robcarey maybe switch to MODX3 and use this? QRNFCGenerator 3.0.1-pl | MODX

Just a quick sidenote :wink:

Definitely created with the old url on the first save - I have a script in there that refreshes the image whenever the tab is clicked - I append a timestamp on the tab being activated that ensures the image is reloaded and not cached each time. Also - I am visually looking at the actual file on the drive to be completely sure.

On first save when changing the alias, you get the old url. Second save = new url.

The snippet that is called that actually builds the QR code I donā€™t think is the issue. It is using the makeUrl command using the id:

$qrcodeurl = $modx->makeUrl($id, '', '', 'https', array('xhtml_urls' => false));

Using $modx->makeUrl() is actually the problem here.

The function uses the cache for the resource URI (ā€˜aliasMapā€™ in core/cache/context_settings/...) and the cache is only cleared after the event ā€œOnDocFormSaveā€ ran.

So what I need here is an ā€œOnDocFormAfterSaveā€ eventā€¦ which I donā€™t have.

I guess I could try to build my own makeurl function that looks at aliasā€¦and resource typeā€¦ and parent and build my own. That soundsā€¦ fun :slight_smile:

I believe the ā€œuriā€ field of the resource should already contain all that information. So I donā€™t think it would be that hard to implement.

You could also clear the ā€œcontext_settingsā€ partition of the cache yourself before calling $modx->makeUrl().

Or you can disable all alias caching with the system setting cache_alias_map (which is probably too radical a solution).

All good tips - Thanks @halftrainedharry I will give these a shot and report back for posterity.

1 Like