Question

We have a requirement where the url of a page needs to be localizable/translated. Our existing mechanism relies on the actual published url to retrieve the page via oData. To clarify with a simplified example: we have some logic in the front end that takes the request url (which doesn't have a file extension, appends a .html extension, e.g.:

/my-awesome-path/my-awesome-page

now becomes

/my-awesome-path/my-awesome-page.html

the logic then pulls the page from oData using the query

/odata.svc/Pages?$filter=url eq '/my-awesome-path/my-awesome-page.html'

There is much more logic that we have around this to parse this SEO-friendly url and get MVC controller function parameters and other whatnots, but that's not relevant here.

Our requirement is that we cannot localize the page to give it a translated url since this would mean the entire page can't be managed in the parent web publication.

To get the localized path leading up to the page filename we simply localize the SGs. The difficulty is with the page filename. On the page's metadata we have a linked "localizable metadata" component with a field for providing a localized page filename.

What we'd like to do is update the page's URL property during the publishing/deployment process to update the page's published url with the localized page filename from this linked metadata component (assume that we have access to the localized filename field's value at any stage between start of publishing to commitment of deployment).

I've tried doing this via a custom resolver, however, at this level it appears that the page.PublishedUrl property is already established by the CM and cannot be overridden. So updating the page.FileName property doesn't do anything useful.

I've also tried directly updating the URL column in the PAGE table in Broker DB to a different name and it appears that everything continues to work, including dynamic linking and unpublishing of the page. Obviously writing a storage extension or a deployer extension to directly update the DB via jdbc is unacceptable.

Here are the options I'm thinking of: 1) try a deployer extension and use the Tridion API to update the url property 2) try writing a custom renderer that executes the url replace logic without actually updating the url in the broker. I don't favour this since request-time processing is required each time.

My question is: what is the most appropriate way to update the page url property? Will writing a custom deployer using Tridion APIs to update the URL property lead me to a dead end just like the Resolver did?

Was it helpful?

Solution

Following the points in Nuno's comment above I decided against using a custom deployer and have solved the problem using 2 event subscriptions of the Event System. On page publish I first localize the page, grab the localized filename from the localized linked metadata component and save the page. Then in a subsequent event I simply unlocalize the page. Here is my working code:

[TcmExtension("Publish or Unpublish Events")]
public class PublishOrUnpublishEvents : TcmExtension
{
    public PublishOrUnpublishEvents()
    {
        EventSystem.Subscribe<Page, PublishEventArgs>(SetLocalizedPageFileName, EventPhases.Initiated);
        EventSystem.Subscribe<Page, SetPublishStateEventArgs>(UnlocalizePageOncePublished, EventPhases.Initiated);
    }


    public void SetLocalizedPageFileName(Page page, PublishEventArgs args, EventPhases phase)
    {
        string localFilename = GetLocalilizedFileNameFromPageMetadata(page);
        if (!string.IsNullOrEmpty(localFilename))
        {
            page.Localize();
            if (page.TryCheckOut())
            {
                page.FileName = localFilename;
                page.Save(true);
            }
        }
    }

    public void UnlocalizePageOncePublished(Page page, SetPublishStateEventArgs args, EventPhases phase)
    {
        string localFilename = GetLocalilizedFileNameFromPageMetadata(page);
        if (!string.IsNullOrEmpty(localFilename))
            page.UnLocalize();
    }

    private string GetLocalilizedFileNameFromPageMetadata(Page page)
    {
        string localFilename = string.Empty;
        if (page.Metadata != null)
        {
            ItemFields fields = new ItemFields(page.Metadata, page.MetadataSchema);
            if (fields.Contains("LocalizableMeta"))
            {
                ComponentLinkField localMetaField = fields["LocalizableMeta"] as ComponentLinkField;
                Component component = localMetaField.Value;
                ItemFields compFields = new ItemFields(component.Content, component.Schema);
                if (compFields.Contains("LocalizedPageFilename"))
                {
                    SingleLineTextField fileNameTextField = compFields["LocalizedPageFilename"] as SingleLineTextField;
                    localFilename = fileNameTextField.Value;
                }
            }
        }
        return localFilename;
    }
}

OTHER TIPS

Perhaps another option:

Store the localised URL has an additional metadata field for the page, keeping the same physical URL for the published pages.

I see your requirement is to avoid localisation of child pages, I like the way it's possible in wordpress to enter globally how URLs work, for example:

/mysite/%postname%/

It would be cool to build something similar to this within SDL Tridion, where the content title could be extracted and used at the content URL.

Either way, if you'd have to write a system that takes the 'Friendly URL' and does a look up for the actual URL, which I think would be pretty simple.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top