On March 26, 2019 we launched new MODX Forums. Please join us at the new MODX Community Forums.
Subscribe: RSS
  • This extra allows you to define custom alias or URI patterns for your resources. It supports translit and Redirector packages.

    You can build your patterns from resource fields, TV, snippets and output filters and set some constraints like you'd do with custom forms.

    For example, with CustomURLs you can add the resource's ID or publish month in the aliases of all resources or just for ones whose parent = 1 or template = 1.


    Pattern examples


    Simple text :
    simple-text

    Default MODx alias :
    [[+alias]]

    Resource placeholders :
    [[+id]]-[[+alias]]

    TVs :
    [[+tv.mytv]]-[[+id]]

    Snippets :
    [[MySnippet? &id=`[[+id]]`]]

    Output filters :
    [[+publishedon:strtotime:date=`%Y-%m-%d`]]/[[+id]]-[[+alias]]

    Default MODx URI :
    [[+cu.parent_uri]]/[[+alias]]

    More complex URI
    [[+cu.parent_uri]]/some-text/[[getResourceField? &id=`[[+parent]]`]]/[[+id]]-[[+alias]]


    Download : http://modx.com/extras/package/customurls
    Github : https://github.com/omycode/customurls
    Documentation : http://rtfm.modx.com/display/ADDON/CustomUrls [ed. note: ben_omycode last edited this post 7 years, 5 months ago.]
    • Shawn Himelberger Reply #2, 7 years, 1 month ago
      Installed... ran a rule.. didn't get it quite right. Tried to start over, tried uninstalling, removing. the Custom URLS are stuck... I've manually changed them on the resource field, but they are stuck. Any ideas?
        Shawn Himmelberger
        Himmelberger Design
        https://himmdesign.com/services/website-development/modx"" target="_blank" rel="nofollow"> MODx Web Design | https://himmdesign.com/services/website-development/modx"" target="_blank" rel="nofollow"> MODx Web Development
      • Hi himmdesign,
        Sorry the bug. Which version of MODx do you use ? What was the rule you've run ?
        • Consider this resource tree

          homepage
          products
          - prod1
          - prod2
          services
          - serv1
          - serv2
          contact

          I created a single rule with the pattern [[+cu.parent_uri]]/[[+alias]].

          At some point it worked for domain.tld/products/prod1. (Thank you very much!)
          But then domain.tld/contact stopped working.

          I have onNoCustomAlias installed. As I understand it, it checks to see if a resource is being called with/without the extension. But it doesn't work with paths, and I think there is a conflict with CustomUrls, so I disabled it. I toyed with the code but I'm hoping there is a more standard solution.

          For the above, I'm hoping to get all of these to work but after just a little bit of experimentation, now nothing is working except alias.html requests:
          /products (this is html page and container)
          /products/prod1
          /products/prod1.htm
          /products/prod1.html (because people could try either
          /contact (page, not a container)

          I've tried patterns like this but they don't seem to work:
          [[+parent]]/[[+alias]] ( shouldn't that be [[*parent]]? )
          [[+cu.parent_uri]]/[[+alias]]
          [[+cu.parent_uri]]/[[+alias]].html
          After changing patterns I regenerate the custom URLs. I added logging in the code to see what's being generated. I don't understand it at all. It looks like a query is made against every resource, but I don't see where the results are stored, otherwise I'd look to see what I'm creating with the patterns.

          I also have Redirector loaded but no patterns set for that yet.

          Can anyone walk me through some of this?
          Thanks!!
            Loved ModX when I was using it a few years ago. Shifted to WordPress, sorry. Thanks, all.
          • OK I think I understand. In fact, CustomUrls is not appropriate for your problem. CustomUrls generate one alias/URI per resource when resource is saved.

            What you're looking for is a plugin triggered on OnPageNotFound which could find the correct resource (ex: /products/prod1.html) from the wrong URI (ex: /products/prod1) and redirects automatically the user to the correct resource with a 301 header.

            I don't know if there is a package for that but maybe this code will help you :
            <?php
            if (!empty($_REQUEST['q'])) {
                // Get the URI
                $uri = $_REQUEST['q'];
                
                // Remove the extension
                $uri = preg_replace('#(/|(\..*))$#', '', $uri);
                
                // Search a resource with similar URI
                $c = $modx->newQuery('modResource');
                $c->where(array('uri:LIKE' => $uri.'%'));
                $c->select(array('id'));
                $resource = $modx->getObject('modResource', $c);
            
                // If a such resource exists we redirect user to
                if ($resource) {
                    $modx->sendRedirect($modx->makeUrl($resource->get('id')),array('responseCode' => 'HTTP/1.1 301 Moved Permanently'));
                }
            }
            • Holy Cow. That's a fundamental concept that I did not get from the information available. Please add this into the README and wiki (or I will based on confirmations here) :
              CustomUrls generates one alias/URI per resource when a resource is saved. This does not use the OnPageNotFound event to redirect requests with a 301 header.
              If that is accurate, can you clarify what this actually does do? From the introductory text:
              This extra allows you to define custom alias or URI patterns for your resources. It supports translit and Redirector packages. You can build your patterns from resource fields, TV, snippets and output filters and set some constraints like you'd do with custom forms. For example, with CustomURLs you can add the resource's ID or publish month in the aliases of all resources or just for ones whose parent = 1 or template = 1.
              From that, should I understand that this is intended to modify the alias value for resources? That doesn't look like what the code is doing. Please help me to understand what to expect from this extra so that I can properly use it, and I will be happy to collaborate to ensure that's communicated in the notes. ( Unless I'm the only one who doesn't "get it". smiley )

              About the redirect code, sincere thanks for that, but that q=alias isn't elegant.

              Here is what I thought CustomUrls did. Maybe the code can be forked into another extra that matches this apparently incorrect understanding.

              1. Set patterns like:
                [[+cu.parent_uri]]/[[+alias]]
                [[+cu.parent_uri]]/[[+alias]].html
                [[MySnippet? &id=`[[+id]]`]]
              2. On Generate, each resource is queried. The alias, ID, and other values are integrated into each pattern in a loop, and a new alias is stored for each pattern. That's X resources times Y patterns = Z new aliases.
              3. With the above patterns we might get:
                products/prod1
                products/prod1.html
                services/serv1
                services/serv1.html
              4. Based on snippet code which uses the ID to read each resource and process TV's or metadata, the snippet might return:
                /smartphones/lg/p999 for the product, or
                /software/development/webservices for the service
              5. With the cross-reference table generated, on every resource update, the ID/alias is used to regenerate the cross-references for the resource, again with one new alias for each pattern.
              6. On page request and OnPageNotFound, the table is queried with whatever the user specified. A match returns the ID.
              7. As to what happens here:
                • Perhaps a 301 redirect is made to /alias or ?q=id or some preferred/canonical reference.
                • Or perhaps a transparent URL rewrite is performed and resource 'id' is returned without changing the address bar.
              8. To create a new pattern for the entire site, use the config page and click the Generate button to refresh the xref table.

              OK, so it does not work like that. (?) But it sure seems close. Where is that wrong? And can you please correct it so that we can all understand exactly how CustomUrl does work?

              Thank you very much!!
                Loved ModX when I was using it a few years ago. Shifted to WordPress, sorry. Thanks, all.
              • Holy Cow. That's a fundamental concept that I did not get from the information available. Please add this into the README and wiki (or I will based on confirmations here) :
                CustomUrls generates one alias/URI per resource when a resource is saved. This does not use the OnPageNotFound event to redirect requests with a 301 header.
                If that is accurate, can you clarify what this actually does do? From the introductory text:
                This extra allows you to define custom alias or URI patterns for your resources. It supports translit and Redirector packages. You can build your patterns from resource fields, TV, snippets and output filters and set some constraints like you'd do with custom forms. For example, with CustomURLs you can add the resource's ID or publish month in the aliases of all resources or just for ones whose parent = 1 or template = 1.
                From that, should I understand that this is intended to modify the alias value for resources? That doesn't look like what the code is doing. Please help me to understand what to expect from this extra so that I can properly use it, and I will be happy to collaborate to ensure that's communicated in the notes. ( Unless I'm the only one who doesn't "get it". smiley )

                Yes this package modifies the alias/URI value for resources.
                I created this package because I wanted to add automatically resources ID in their alias and so make them unique and make my clients life easier ! But maybe the description of this package is confused. I will clarify that in wiki, README and code.

                Thanks to this extra, for example, I also can create folders in my resource tree that not appear in childrens alias. It can be usefull for classifying resources.

                About the redirect code, sincere thanks for that, but that q=alias isn't elegant.
                You're right, it was just a quick proposition. Here I replaced alias detection with code from Redirector package. More elegant I think. wink
                <?php
                // Get the URI
                $search = $_SERVER['REQUEST_URI'];
                $baseUrl = $modx->getOption('base_url', null, MODX_BASE_URL);
                if (!empty($baseUrl) && $baseUrl != '/' && $baseUrl != ' ') {
                    $search = str_replace($baseUrl,'',$search);
                }
                
                // Remove the extension
                $uri = preg_replace('#(/|(\..*))$#', '', $search);
                
                // Search a resource with similar URI
                $c = $modx->newQuery('modResource');
                $c->where(array('uri:LIKE' => $uri.'%'));
                $c->select(array('id'));
                $resource = $modx->getObject('modResource', $c);
                
                // If a such resource exists we redirect user to
                if ($resource) {
                    $modx->sendRedirect($modx->makeUrl($resource->get('id')),array('responseCode' => 'HTTP/1.1 301 Moved Permanently'));
                }


                Here is what I thought CustomUrls did. Maybe the code can be forked into another extra that matches this apparently incorrect understanding.

                1. Set patterns like:
                  [[+cu.parent_uri]]/[[+alias]]
                  [[+cu.parent_uri]]/[[+alias]].html
                  [[MySnippet? &id=`[[+id]]`]]
                2. On Generate, each resource is queried. The alias, ID, and other values are integrated into each pattern in a loop, and a new alias is stored for each pattern. That's X resources times Y patterns = Z new aliases.
                3. With the above patterns we might get:
                  products/prod1
                  products/prod1.html
                  services/serv1
                  services/serv1.html
                4. Based on snippet code which uses the ID to read each resource and process TV's or metadata, the snippet might return:
                  /smartphones/lg/p999 for the product, or
                  /software/development/webservices for the service
                5. With the cross-reference table generated, on every resource update, the ID/alias is used to regenerate the cross-references for the resource, again with one new alias for each pattern.
                6. On page request and OnPageNotFound, the table is queried with whatever the user specified. A match returns the ID.
                7. As to what happens here:
                  • Perhaps a 301 redirect is made to /alias or ?q=id or some preferred/canonical reference.
                  • Or perhaps a transparent URL rewrite is performed and resource 'id' is returned without changing the address bar.
                8. To create a new pattern for the entire site, use the config page and click the Generate button to refresh the xref table.

                OK, so it does not work like that. (?) But it sure seems close. Where is that wrong? And can you please correct it so that we can all understand exactly how CustomUrl does work?

                Thank you very much!!

                For performances purpose, I prefer to generate alias/URI on resource save once and then letting MODx handle resources instead of letting MODx search a resource that doesn't exist, call a OnPageNotFound plugin, and once again get the right resource from DB. So I don't think I will update this package in that way but you're free to forked it and develop your own MODx extra. But in your case a 404 plugin should do the trick I think.
                • OK, so CustomUrls sets the resource alias value for all resources. Again, I didn't get that at all from the information provided. I'm thinking this could be a language issue too. Or sometimes developers are so familiar with the basic concept of their work that they often jump right to discussing changes and details, not remembering that other people have no idea about the basic functionality of the code. I see this a LOT these days.

                  If there are multiple patterns, which one gets assigned to the resource alias?

                  What if the pattern is wrong? All of the aliases get trashed?

                  If you're using a pattern like [[+cu.parent_uri]]/[[+alias]] to generate a new alias, and we create bad aliases, how can we possibly get back to correcting them? This pattern uses the alias...

                  With a mass update like this I think it's prudent to advise admins that they should do a backup before clicking the button to process the patterns.

                  I dunno if I would have called this CustomUrls but more like AliasRewriter...

                  Thanks again!
                    Loved ModX when I was using it a few years ago. Shifted to WordPress, sorry. Thanks, all.
                  • If there are multiple patterns, which one gets assigned to the resource alias?
                    The first one with a constraint which matches with the resource or if there is no such pattern, the first pattern without any constraint.

                    What if the pattern is wrong? All of the aliases get trashed?
                    If a pattern is wrong, aliases will not be as expected. To fix them, you've just have to fix your pattern and regenerate aliases.

                    If you're using a pattern like [[+cu.parent_uri]]/[[+alias]] to generate a new alias, and we create bad aliases, how can we possibly get back to correcting them? This pattern uses the alias...
                    Not sure I understood the question but maybe this screencast will help : http://www.youtube.com/watch?v=iwJeUxxtazE
                    • Is it possible to remove directory name from the url using this plugin?

                      e.g. I have the following structure:

                      catalog
                      -category
                      --sub_category
                      ---product

                      -category2
                      --sub_category2
                      ---product2

                      -category3
                      ---product3

                      and urls are: catalog/category/sub_category/product or catalog/category3/product3. I need to remove "catalog" from the url.

                      Can't get how to do this(( Can you help please?