<![CDATA[ [Tutorial] Custom Aliasing: Creating Cross-Context Resources (Revo 2.2+) - My Forums]]> https://forums.modx.com/thread/?thread=78223 <![CDATA[Re: [Tutorial] Custom Aliasing: Creating Cross-Context Resources (Revo 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-469367
When displaying cross-context content, it is displayed in de template that is set in the article container. ) I use the plugin in combination with the articles/plugin.

On other contexts, i would like the article to display in the deafault template of that site, like a symlink can.
I have created the context-setting "default_template" for each context.

Can you give me a hint where to start for that implementation? Can it be done inside the plugin or should it be done in the article plugin?

I've moddified the plugin a bit already, so it looks in one ID only for the aliases, in the article container. So it could be detatched from a specific template.

I've added this two lines, right before the final sendForward:

$TemplateID = $modx->getOption('default_template', null, 'default');
$toResource->set('template',$TemplateID);

But with no effect.
]]>
robbedoes Jun 18, 2013, 02:41 PM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-469367
<![CDATA[Re: [Tutorial] Custom Aliasing: Creating Cross-Context Resources (Revo 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435783 one little typo in this line: if (in_array($catVal, $categories')) (the ' has to be removed).
Thank you!!!]]>
michelle84 Sep 04, 2012, 05:28 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435783
<![CDATA[Re: [Tutorial] Custom Aliasing: Creating Cross-Context Resources (Revo 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435772 I'm going to try it right now.]]> michelle84 Sep 04, 2012, 04:33 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435772 <![CDATA[Re: [Tutorial] Custom Aliasing: Creating Cross-Context Resources (Revo 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435724
Try that. The original code has been modified. Just for the future, it is really hard to support code that you can't remember anything about, so if there's a next time: please, get back to me as soon as possible. Otherwise, I can't guarantee the efficacy of the fix. It just so happened that these were really simple.]]>
fuzzicallogic Sep 03, 2012, 02:11 PM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435724
<![CDATA[Re: [Tutorial] Create Cross-Context Resources (Revolution 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435693 I found a few problems with the code (the one that was especially for me).
First, on line 24 there seems to be a '(' to much.

And also this line gives me an error:
if ($catVal in $res->getTVValue('categories'))


I get Parse error: syntax error, unexpected T_STRING . If I remove the line it works again.
Should it be in_array or something?]]>
michelle84 Sep 03, 2012, 10:22 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-435693
<![CDATA[Re: [Tutorial] Custom Aliasing: Creating Cross-Context Resources (Revo 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-434665 fuzzicallogic Aug 25, 2012, 05:51 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-434665 <![CDATA[Re: [Tutorial] Create Cross-Context Resources (Revolution 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-433859 Explanation of Code

This post gives a detailed step-by-step explanation of the code used in this Plugin. The code here demonstrates both simple and advance MODx concepts, including:

  • Querying xPDO
  • Accessing System Settings
  • Forward data to other Plugins
  • Receiving data from other Plugins
  • Accessing/Setting data through configurable Array Keys
  • URL construction for comparison



Aside from SQL Injection, one of the most common attacks comes in the form of hijacking $_GET, $_POST, and $_REQUEST variables. In these plugins, we allow the user to easily change keys via System Settings. This serves 3 purposes: a) immediate end to hijacks without adjustment of code; b) compatibility between similar plugins; and c) obscurity of data based on resource reference. Below is how we retrieve the Settings.

Note: For more customizable or complex situations, getOption() retrieves settings from the User (if set), then the Context (if set), then the System. You could logistically have a different setting for each depending on your needs, and the code would function across all related plugins. This would lead to more security, but also more maintenance.

//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');


Next, we need to know if a previous plugin (within the same event) has found the appropriate resource. This uses a key from the System Settings. After all, we want to make sure we don't conflict with similar Plugins, but also want to limit processing if we don't actually need it. If we do need to, we can set it for the later Plugins.


// Get "passed" variables
    $isFound = empty($_REQUEST[$keyFound])
        ? 'false'
        : $_REQUEST[$keyFound];
// Only do this if we need to scan.
    if ($isFound == 'false')
    {


Similar to before, we need the URL we are looking for. Since a previous Plugin may modify the URL according to its needs, we need the real URL to act upon. This uses the other key we got from above. This line gets the URL from the $_REQUEST (if already set by another Plugin), or from the $_SERVER (if not modified by a previous Plugin). Afterwards, we make sure that we aren't tampering with $_GET or $_POST by removing them from our stored URL.

    //Get the Request URL
        $toURL = !empty($_REQUEST[$keyURL]) 
            ? $_REQUEST[$keyURL]
            : $_SERVER['REQUEST_URI'];
    // Remove GET Parameters
        $toURL = reset(explode('?', $toURL));
        $path = explode('/', trim($toURL, '/'));


This function uses an xPDO Query to find a published Resource based on its alias. To speed and simplify the query, we check up front whether its Template matches a site-wide Alias. Notice, we get another System Setting here with getOption. This allows developers to add or change functionality without modifying the current Template. When they are done, they may change the System Setting and Template on the active Resources. If successful, it returns the actual Resource. If not, it returns null.

    /*
     * Checks if the alias is a Cross Context Alias
     */
        function isSiteAlias($alias)
        {//Get MODx instance
            global $modx;
        // Get System Setting
            $idAliasTemplate = $modx->getOption('id_site_alias', null, 1);
            $q = $modx->newQuery(
                'modResource', 
                array(
                    'published'=>1, 
                    'alias'=>$alias, 
                    'template'=>$idAliasTemplate,
                )
            );
            $q->select(array('id','alias'));
            $q->prepare();
        // Iterate through potential matches
            $matches = $modx->getCollection('modResource',$q);
            if (!empty($matches))
                foreach($matches as $res)
                // Respect parents
                    return $res;
        // Return empty variable
            return null;
        }
 


This function is how we make sure that an Aliased Resource respects the path. Prior to this addition, it did not and every Site Alias could be accessed regardless of path. This allowed for greater stability, but did not allow for adequate debugging. Now, developers will have an easier time debugging, but will have to check their links. It was a tradeoff, but fixing a link is easier than debugging an alias that doesn't truly exist.

    /*
     * Checks if the alias is a child of the previous path.
     */
        function isChildOf($alias, $child)
        {// Strip the extension
            $alias = reset(explode('.',trim($alias)));
            $parent = $child->getOne('Parent');
        // Simple climb
            if (!empty($parent))
                if ($alias == $parent->get('alias'))
                    return $parent;
        // Return empty result
            return null;
        }



This function allows us to access Children of the Custom Alias. This isn't strictly necessary for all, but it is necessary if we are allowing for Template-Based Actions. If the Child path segment is not actually a Child of the Resource, it will return a 404.


    /*
     * Checks if the alias is a parent of the next path.
     */
        function isParentOf($alias, $parent)
        {// Strip the extension
            $alias = reset(explode('.',trim($alias)));
            $children = $parent->getMany('Children');
        // Simple climb
            foreach($children as $key => $res)
            {   if (!empty($res))
                    if ($alias == $res->get('alias'))
                        return $res;
            }
        // Return empty result
            return null;
        }


Here is where the code actually begins. Since we broke up the path above, we need to go through each segment and determine if it is an Alias. If it is, we take the previous segments (if there are any) and move them to the Parents array. We also take the supplemental segments and move them to the Children array.


    // Initialize Tracking Variables
        $toResource = null;
    // Find the Alias (one alias per Request)
        foreach($path as $key => $segment)
        {//Check if it could be an Alias
            $toResource = isSiteAlias($segment);
            if (!empty($toResource))
            {
            // Split into two arrays
                $parents = explode('/', reset(explode($segment.'/', $toURL)));
                $children = explode('/', end(explode('/'.$segment, $toURL)));
                break;
            }
        }
 


Now, we check to make sure we are respecting the path of the parents. If the path does not match, the Plugin will set the Resource to null, forcing a 404 error.


        if (!empty($toResource) && !empty($parents))
        {   $child = $toResource;
            foreach($parents as $key => $segment)
            {   if (!empty($segment))
                {   $tmp = isChildOf($segment, $child);
                    if (empty($tmp))
                    {   $toResource = null;
                        break;
                    }
                    else $child = $tmp;
                }
            } 
        }



If we have Child segments, we obviously have the wrong Resource, so now we check if the Child exists (using the function above). If it does not, we set the Resource to null, forcing a 404.


    // Keep track of Children (for Paths deeper than Alias)
        if (!empty($toResource) && !empty($children))
        {   foreach($children as $key => $segment)
            {   if (!empty($segment))
                {   $tmp = isParentOf($segment, $toResource);
                    if (empty($tmp))
                    {   $toResource = null;
                        break;
                    }
                    else $toResource = $tmp;
                }
            }
        }


Finally, if we still have a Resource, we send the user to it. sendForward() is awesome, because it does its job without changing the URL on the browser. We also use the System Setting to let subsequent Plugins know that we found the Resource. If we don't have a Resource still, we let the plugins know that too. Here is where $_REQUEST really shines... we just modified the $_REQUEST meaning it will reset as soon as any other request for a page is made, but we didn't modify $_GET or $_POST at all, meaning the user's queries are intact.


    // Send to the Nearest found Child.
        if (!empty($toResource))
        {   $_REQUEST[$keyFound] = 'true';
            $modx->sendForward($toResource->get('id'));
        }
        else $_REQUEST[$keyFound] = 'false';
    }
]]>
fuzzicallogic Aug 19, 2012, 07:08 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-433859
<![CDATA[Re: [Tutorial] Create Cross-Context Resources (Revolution 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-433858
Quick Link: Tutorial]]>
fuzzicallogic Aug 19, 2012, 07:07 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-433858
<![CDATA[Re: [Tutorial] Create Cross-Context Resources (Revolution 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-433133
This is basically a simplified version of the original plugin here, but it only searches one context (eg. web) instead of looking for a match in all:
<?php
// fire on 'OnPageNotFound'
$curCtx = $modx->context->get('key');
$defaultCtx = $modx->getOption('default_context',null,'web');

if ($curCtx !== 'mgr' && $curCtx !== $defaultCtx) {
    $alias = $modx->request->getResourceIdentifier('alias');
    $modx->switchContext($defaultCtx);
    $resourceID = $modx->aliasMap[$alias];
    if (!empty($resourceID)) {
        $modx->sendForward($resourceID);
    }
}
]]>
okyanet Aug 14, 2012, 02:57 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=4#dis-post-433133
<![CDATA[Re: [Tutorial] Create Cross-Context Resources (Revolution 2.2+)]]> https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=3#dis-post-432371 michelle84 Aug 06, 2012, 11:48 AM https://forums.modx.com/thread/78223/tutorial-create-site-wide-resources-revo?page=3#dis-post-432371