Updated as of 8/19/2012
Summary
Revolution has inconsistent behavior when a Parent Resource is not a Container, but has children. This is especially true if you use 'makeUrl()' in Snippets to make your links. If the Parent Resource is not a Container, when you request it, the URL contains the extension based on Content Type. If you request a Child, the path excludes the extension from the Parent. This led to some tricksy code for my other plugins, so I decided to fix it.
This tutorial will show you how to replace all extensions in a URL when MODx cannot find the resource. It will then redirect the user to the appropriate page. Understand that this will ignore any request for an extension, but it was all or individual custom fixes for every link.
The Process
This requires very little setup. First, we'll build the Plugin, with the complete code. Afterwards, we will perform a test by creating two resources under specific conditions. Then we will request them using by adjusting their address in the browser address bar. Next, I'll address compatibility, so if you are using any of my other plugins from the other Tutorials, be sure to read this. Finally, for those interested, an Explanation of the Code will be posted in a reply post.
Note: All of the Plugins are getting updated (on 8/19/2012), due to fixes and better configuration. They are all compatible with each other now.
Create the Plugin
Click the Elements tab where your Resource tree is. Create a new Plugin. For the sake of clarity with my other plugins, let's name it "onNoCustomAlias". Paste the following code:
<?php
//Get the System Settings (if we haven't already...)
$keyURL = !empty($keyURL) ? $keyURL : $modx->getOption('key_url_request', null, 'toURL');
$keyFound = !empty($keyFound) ? $keyFound : $modx->getOption('key_doc_found', null, 'hasResource');
// Get "passed" variables
$isFound = empty($_REQUEST[$keyFound])
? 'false'
: $_REQUEST[$keyFound];
// Only do this if we need to scan.
if ($isFound == 'false')
{//See if a previous plugin has set the URL.
$toURL = !empty($_REQUEST[$keyURL])
? $_REQUEST[$keyURL]
: $_SERVER['REQUEST_URI'];
$toURL = reset(explode('?', $toURL));
function findByURL($url, $alias)
{ global $modx;
// Strip the extension
$alias = reset(explode('.',trim($alias)));
$q = $modx->newQuery
( 'modResource',
array
( 'published'=>1,
'context_key'=>$modx->context->key,
'alias'=>$alias
)
);
$q->select(array('id','alias'));
$q->limit(25);
$q->prepare();
$matches=$modx->getCollection('modResource',$q);
foreach($matches as $res)
{ if (!empty($res))
{//Align URLs by getting rid of end slashes and extensions
$chk_url = $modx->makeUrl($res->get('id'));
$chk_url = preg_replace("/\.[\w\-\h]{2,}/", "", trim($chk_url, '/'));
// Now compare the URLs
if($chk_url == $url)
return $res->get('id');
}
}
return -1;
}
// Split the Path Segments
$toPath = explode('/', trim($toURL, '/'));
// Align URLs by getting rid of end slashes and extensions
$toURL = preg_replace("/\.[\w\-\h]{2,}/", "", trim($toURL, '/'));
// Get the Resource ID
$toID = findByURL($toURL, end($toPath));
// Forward the client
if ($toID == -1) $_REQUEST[$keyFound] = 'false';
else
{ $_REQUEST[$keyFound] = 'true';
$modx->sendForward($toID);
}
}
Now that the code is placed, click Save. We still have to attach it to an event, however. So, click the System Events tab. Scroll down to OnPageNotFound. Mark the checkbox next to it. Set the priority to 3 or higher. Click Save again.
Note: If you a) use Articles, b) any of my other plugins, c) or any plugin that utilizes OnPageNotFound, then see the section on Compatibility.
Testing the Plugin
Test One: Parent Resource
Pick any Resource that is not a Container. Right-click on it and choose "View Resource". In general, it will apply the extension ".html". Now, in the address bar change the extension to ".xml" and press Enter. It will load the same resource. You may also remove the extension entirely and it should load.
Test Two: Child Resource
Use the Resource that you chose in the first test. Add a new Resource under it. Don't forget to set an alias, and title. Once it is Saved, Right-Click on it and choose "View Resource". It will load with whatever URL it likes, but the last path segment should have an extension. Do the following in the Address Bar and you should get the same results:
- Change the extension to ".css" and press Enter.
- Remove the extension and press Enter.
- Add any extension to the parent path segment and press Enter.
- Add an extension to child path segment and press Enter.
On Compatibility
Supports
This supports long extensions with any letter, number, or hyphen. It does not currently support white space in extension. This does not tamper with POST or GET parameters in any way, so extensions and "." may be used as pleased in these.
System Settings
The System Settings used here (getOption()) are used by the other Plugins, as well. They aren't necessary to create unless you are using the other Plugins. If you would
like to create them, refer to the updated Tutorial on my AJAX Framework and either Cross-Context Resources or Template Actions (links in my signature).
FuzzicalLogic's AJAX Tutorials
Priority for this plugin must be after (higher than) all other AJAX Framework plugins that use OnPageNotFound. This includes the following: onGetRequestType, onParseURLParams. For ensured compatibility, make sure you "upgrade" using the updated Tutorial. (links in my signature)
FuzzicalLogic's Aliasing Tutorials
Priority for this plugin must be after (higher than) all other Custom Aliasing tutorials. This includes the following: Cross-Context Resources, Template Actions. While it is not required to upgrade these plugins, updating them provides much better compatibility, optimized processing, and configuration options (for ease and security), as well as better support for path enforcement. (links in my signature)
Articles Plugin
If you use Articles, you will need to change the priority of ArticlesPlugin to be after all of my plugins.
Conclusion
I have had endless issues with extensions and extra slashes until the plugin was created. While most were derived from makeUrl(), or the ~id, this resolved some issues with Javascript as well. It's never a happy day when you request a page that you know exists, but the makeUrl either included an extension that MODx doesn't want, or removed one that it needs. This gets particularly hairy if you use multiple content types with children. Hopefully, the techniques demonstrated here will be useful, even if you have no need for the plugin itself.
[ed. note: fuzzicallogic last edited this post 14 years, 1 month ago.]