4

I have the ID of a Component (or localized version of Component) and would like to get the Page that Component is used on (to Publish)

First part is easy

UsingItemsFilterData filter = new UsingItemsFilterData()
{
   BaseColumns = ListBaseColumns.IdAndTitle,
   ItemTypes = new[] { ItemType.Page }
};

var items = client.GetList(id, filter);

I do not localize pages, and here is where the problem starts

If I pass the master (global) Component ID to the function, I want to get the master Page (which I do)

If I pass a localized instance of the component I want to get the "local" (not localized) Page that should be published

So as example, Component localized in US English content Publication should allow me to find the ID of the US English Page. However I always get my master Page, as I do not localize any pages

I can get the Page I need, but in an intensive way, involving excessive looping etc.

Is there an efficient way to get this via the API?

2
  • Can you use a filter to scope this to a given repository? Or load the page in the same context as the component?
    – Nuno Linhares
    Commented Aug 31, 2016 at 10:53
  • The page is shared across 100+ websites (almost entirely not localized). Without managing a mapping I have no way of knowing the repository. Unfortunately, the Page does not exist in the context that the Component is edited (yay BluePrinting :) Commented Aug 31, 2016 at 11:07

2 Answers 2

1

I think you can use the resolver for this, depending on how exactly you need it to work. We have a "Get pages that would be published" Core Service utility. It resolves the Component and then filters out pages from the publish data.

Our utilities are running on Java because we can't run C# applications (don't ask), but hopefully the following translation is working enough to help out?

private List<string> GetResolvedPageIds(string componentId)
{
    ResolveInstructionData resolveInstruction = new ResolveInstructionData
    {
        Purpose = ResolvePurpose.Publish,
        IncludeChildPublications = true,
        IncludeComponentLinks = false
    };
    List<string> pageIds = new List<string>();
    PublishContextData[] publishContextData = service.ResolveItems(
        new[] {
            componentId
        },
        resolveInstruction,
        new[] {
            "tcm:0-1-65537", "tcm:0-2-65537" //etc
        },
        new ReadOptions()
    );
    foreach (PublishContextData publishContextItem in publishContextData)
    {
        foreach (ResolvedItemData resolvedItem in publishContextItem.ResolvedItems)
        {
            if(resolvedItem.Item.IdRef.EndsWith("-64"))
            {
                pageIds.Add(resolvedItem.Item.IdRef);
            }
        }
    }
    return pageIds;         
}

We currently do this using all publication targets with "Production" in the name (as per our naming standards), however if different publications use different targets, you could isolate something in, say, [04 Translated Site] by resolving against that site's target.

4
  • Thanks @Dave. This is an interesting solution, and certainly improves code cleanliness and performance. Only issue is I don't think it will include pages that have not previously been published. I think by publishing the Component I will only get pages previously published in the resolved items. I could be wrong though Commented Aug 31, 2016 at 14:55
  • I think you can control that with ResolvePurpose.Publish vs ResolvePurpose.RePublish, though I confess I've not tested that ... just making the assumption :) Commented Aug 31, 2016 at 14:58
  • Yea. I just tried that. I think with a Component that makes no difference. More testing required and I'll report back Commented Aug 31, 2016 at 15:00
  • This is my preferred solution, as much more efficient. There are a couple of gotchas to be aware of 1. Only already published pages appear when triggering the publish from a Component 2. You might want IncludeComponentLinks set to true, so that Component Links flag indirect page links Commented Sep 1, 2016 at 15:15
3

The API can't solve this for you, also if I'm getting your request right, you basically could have the following BluePrint:

[ 01 Master Content ]
          |______________
          |              |
          |   [ 02 Translated Content ]
          |              |
 [ 03 Master Site ]      |
          |______________|
                         |
               [ 04 Translated Site ]

Now the Component is created in 01, the Page in 03, the Component is localized in 03, and used on a shared Page in 04.

What the API can do for you is find the Page in 03, because that is where the page is created and where the Component is used. It can also find you the localized Component in 02, because that is not a shared, but a localized item.

But the API can never find the Page in 04, because it simply doesn't know about that, there could be a lot of Publications in that BluePrint where there is a shared Page where a shared Component is on, but the API doesn't know what the URI of the Publication is that you consider the translated website.

Actually to solve this task, you need to feed your algorithm with some knowledge about your BluePrint. When you add a mapping between Content and Site Publications, you can resolve the Page using URI manipulation.

Let's say that Master Content has tcm:0-1-1, Translated Content tcm:0-2-1, Master Site tcm:0-3-1 and Translated Site tcm:0-4-1.

When you query for the Page belonging to a Component in tcm:0-1-1, you automatically get a Page in tcm:0-3-1, so that is a simple task, you have the right data. But when you ask for the Page to a Component in tcm:0-2-1, you will get back the Page in tcm:0-3-1 (since the shared item in tcm:0-4-1 doesn't really exist in the database, it is just a "view"). Now if you have a mapping saying that when you look for the usage of Component from tcm:0-2-1, it should return items from tcm:0-4-1. Then you can simply manipulate the Publication ID in the URI of your Page (remember a Page in tcm:0-3-1 will have the URI tcm:3-xyz-64, with the Publication ID as the first part of the URI, change it into tcm:4-xyz-64 and you have the Page you are looking for).

Now this will become more complex depending on the complexity of your BluePrint. But that is the only solution I see for this, your code (the algorithm) needs knowledge of your BluePrint, which isn't clear in the CMS. The CMS only knows parent/child relationships, and not what you use the Publication for (even the Publication Type currently doesn't help you here yet).

2
  • Thanks Bart. Yes, this pretty much sums it up. I am desperately trying to avoid any mapping configuration as the number of permutations is huge (complex BluePrint). I have it working in code, my issue is the code is not that efficient, although it is probably as efficient as it is going to get. It is just a complex situation to solve without a brute force attack. Commented Aug 31, 2016 at 12:13
  • @ChrisMorgan I feel your pain, been there before and couldn't easily solve it either indeed. Commented Aug 31, 2016 at 12:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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