2

In our articles we have a publisher control where we select the publisher in the data source:

enter image description here

The problem is when I try moving the publisher to another location in Sitecore some of the links break and some don't. So the publisher might appear for some articles and some will be referencing to the publisher at the old location.

Is there a way I can move the publisher and still be able to point to the new location in all articles? I have tried moving them but it's flaky some publishers show some don't and moving them back solves the issue.

Update: Same publisher referenced in two different articles:

Article 1:

enter image description here

Article 2:

enter image description here

I did rebuild link databases but it hasn't updated the links.

  • Sitecore 8.1 uses item ID for datasource location. It won't break if you move target item. Unless you manually pasted item path as a datasource. – Marek Musielak Jun 1 '17 at 9:52
  • Not manually pasting the item path but I guess browsing to the publisher is doing the same thing as pasting? For any article if you look at publisher control you will see the path to the item. – jahan Jun 1 '17 at 10:50
  • 1
    Have you tried switchint to Raw Values view and checking what is stored in Sitecore background? – Marek Musielak Jun 1 '17 at 10:57
  • Tired and it shows the path to the item. Thing is it does update the path for some articles and not for some. Same publisher might be showing in few articles and not in others. Just thinking of finding a way I can move it with updated references. Unless I can write a script to check the existing path and update it to new path. – jahan Jun 1 '17 at 11:16
  • When you move and item, Sitecore will update all references to it in rendering, layout and field datasources. You should not need a script to make them update on move. Can you compare an item that does not update to one that does to see the difference? Maybe update the link database. – Chris Auer Jun 1 '17 at 13:14
3

I agree with Chris Auer (see comments on the OP) that Sitecore should be updating these references for you, even if the reference is a path. That issue should be investigated, and this solution does not seek to dissuade you from finding the cuase of that issue. However, I have experienced issues like this that did not actualize (or, at least, were not discovered) until after the solution made it to production. As such, in order to ensure that such issues do not plague production environments, I liketo have a fallback.

I use the Rules Engine for this, and have a rule for changing rendering Data Source values to an ID, which I run on item:saved. The idea is that when the item is saved, it converts the Data Source path for each rendering an ID, so even if you move the referenced item the actual reference (the ID) should still be correct.

Here is the code for the Action that does the conversion:

public class EnsureLayoutDataSourcePathIsConvertedToId<TRuleContext> :
    Sitecore.Rules.Actions.RuleAction<TRuleContext>
    where TRuleContext : RuleContext
{
    #region Methods

    /// <summary>
    /// The apply rule.
    /// </summary>
    /// <param name="ruleContext">
    /// The rule context.
    /// </param>
    public override void Apply([NotNull] TRuleContext ruleContext)
    {
        Assert.IsNotNull(ruleContext, "ruleContext");
        Assert.IsNotNull(ruleContext.Item, "ruleContext.Item");

        if (ruleContext.IsAborted)
        {
            return;
        }

        Item item = ruleContext.Item;

        var layoutField = new LayoutField(item.Fields[global::Sitecore.FieldIDs.LayoutField]);
        if (!layoutField.InnerField.HasValue)
        {
            return;
        }

        Item existingItem = item.Database.GetItem(item.ID, item.Language, item.Version);
        if (existingItem == null)
        {
            return;
        }

        var oldLayout = new LayoutField(existingItem.Fields[global::Sitecore.FieldIDs.LayoutField]);

        /*
         * NOTE:
         *      Check if control datasource with paths and if old and new values are equal exit
         */
        if (!oldLayout.Value.Contains(" ds=\"/")
            && (string.IsNullOrEmpty(layoutField.Value) || layoutField.Value == oldLayout.Value))
        {
            return;
        }

        LayoutDefinition layout = LayoutDefinition.Parse(layoutField.Value);
        foreach (DeviceDefinition device in layout.Devices)
        {
            if (device == null)
            {
                continue;
            }

            foreach (RenderingDefinition rendering in device.Renderings)
            {
                // ReSharper disable UseNullPropagation
                if (rendering == null)
                // ReSharper restore UseNullPropagation
                {
                    continue;
                }

                if (!string.IsNullOrEmpty(rendering.Datasource)
                    && !rendering.Datasource.StartsWith("{", StringComparison.InvariantCultureIgnoreCase))
                {
                    Item datasourceItem = item.Database.GetItem(rendering.Datasource);
                    if (datasourceItem == null)
                    {
                        Log.Warn(
                            $"Could not find datasource item at path {rendering.Datasource} while saving item {item.ID}",
                            this);
                        continue;
                    }

                    rendering.Datasource = datasourceItem.ID.ToString();
                }
            }
        }

        layoutField.Value = layout.ToXml();
    }

    #endregion
}

Credit: Jimbo Baltika and Matt Gramolini wrote this Action, and shared it with me while I was working with them on another project.

  • Thanks for the answer zachary, I assume this rule will for work for items saved after the rule is applied. Could something similar be done for existing data source values? For example in my case. – jahan Jun 1 '17 at 16:09
  • Yes, if you configure the rule you could run it for all items by running a script (SPE or C#) that recursively saves each item, or you could just write a quick C# script that executes the body of the action on each item. That should get you back to everything being an ID. If you can wait, however, before you do so I would work with Sitecore Support and/or continue your investigation to see if you can find the cause of the issue. Remember that this is meant to be the second line of defense. – Zachary Kniebel Jun 1 '17 at 16:12
  • Yeah can raise it with sitecore support. – jahan Jun 2 '17 at 14:58
  • Great! Be sure to update this post with the cause of the issue, if Sitecore Support is able to help you find it! :) – Zachary Kniebel Jun 2 '17 at 15:49

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.