This works:

{{ craft.entries.section('products').relatedTo(object).first.uri }}/{slug}

However, in this case, I need to use the extended relatedTo property, which includes curly braces:

{{ craft.entries({relatedTo: {targetElement: object, field: 'productConfigs'}}).first.uri }}/{{ object.slug }}

Because of the way renderObjectTemplate replacement seems to happen, the braces get screwed up.

Any way to work around this?

I'd actually rather do this in PHP/plugin if possible, but I'm not sure if a relevant hook/event exists.


It's not documented so I guess not officially supported, but you can use template variables in the URL formats. For example if you had a UrlFormats plugin, you could use something like this:

namespace Craft;

class UrlFormatsVariable
    // Use in the URL Format box:
    //  {{ craft.urlFormats.yourSectionHandle(object) }}
    public function yourSectionHandle($entry)
        // Craft checks the URL format with an array "object" first, to see if there's a {slug},
        // and so whether it should be checked for uniqueness and incremented if necessary.
        if (!$entry || !($entry instanceof EntryModel))
            return '{slug}';

        $relation = craft()->elements->getCriteria(ElementType::Entry)
                'targetElement' => $entry,
                'field'         => 'productConfigs',

        if (!$relation)
            // throw an exception or default to something

        return $relation->uri.'/'.$entry->slug;

Then you can keep your URL Format and Nested URL Format inputs cleaner:

{{ craft.urlFormats.yourSectionHandle(object) }}
  • returning '{slug}' didn't work for me. I would end up with an error message like "URI "{slug}" has already been taken." Instead, this seems to do the trick: {{ craft.urlFormats.yourSectionHandle(object)|default(object.slug) }}
    – Tim Kelty
    Aug 9 '16 at 19:52

Using template variables in URL formats is brilliant, but if you don't want to write your own plugin, you could use the fantastic Preparse plugin as well.

First, create a Preparse field that contains the following Twig code, and add the field to your entry type's field layout:

{% spaceless %}
    {{ craft.entries({
        relatedTo: {
            targetElement: entry,
            field: 'productConfigs'
    }).first().uri|default('') }}
{% endspaceless %}

Then, add the following to your URL format setting (preparseFieldHandle should be the handle for your Preparse field, obviously):

{{object.preparseFieldHandle ? object.preparseFieldHandle ~ '/'}}{slug}    

Note that any existing entries in the relevant section would have to be re-saved in order to have the Preparse field actually parse.


I'm not sure this is the best answer, but since others can post answers too:

One solution to this may be to disable the Section setting Entries in this section have their own URLs and manage your URLs manually using a custom route and the appropriate template logic.

  • By disabling that setting you also disable live preview.
    – carlcs
    Aug 5 '16 at 6:54
  • 2
    Good point. It would be possible to have URLs enabled for Live Preview and route things differently on the front-end. Not saying this is ideal. It always feels wrong when you have URLs enabled just for Live Preview or in a situation where the CP and front-end URLs need to be different. Aug 5 '16 at 14:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.