Sitecore LinkManager.GetItemUrl() resolving to alias - sitecore

I've created aliases for the home page of one of the local sites (and it's child pages) in my national website - and I can't figure out how this is happening.
When someone lands on a local page, I have a control (cs file) that creates the local links (to the child pages) on the left hand side of the local web page. These links are derived from the Sitecore context (current item's content path).
After I created the aliases for all of the pages in a local site, that's when I noticed this problem. If the URL is a Sitecore alias, the navigational links are built for the child aliases - otherwise they are resolved by the Sitecore LinkManager, just as they were before the aliases were created. However, when I hit a page for the original local item (not the alias), the links are being rendered for the alias:
childLink.NavigateUrl = LinkManager.GetItemUrl(child);
And I've verified that the child item is valid. Does anyone have any suggestions as to why the LinkManager would be rendering the links for the aliases - and how this can be avoided?

Sitecore.Links.LinkManager.GetItemUrl(item) returns the path to the original item, not the alias path. If you have special logic to identify aliases, for example by using the Sitecore.Context.RawUrl property, you may be running into an issue with output caching, which could be causing the alias version of the control to be displayed when you navigate to the original item.
Update: I'm pretty sure you are running into an output caching issue. I was able to reproduce this behavior by creating a test control, which displays a timestamp and the RawUrl, and by turning on output caching for the control in Presentation Details.
The first time the control is displayed, whether it is for the item or the alias, the output is cached, and this cached output is displayed each time the control is viewed, either for the original item or the alias. Even if you switch on "Vary By Data", the effect is the same, because "Vary By Data" is driven by the Data Source item, not the URL.
To fix this behavior, you need to add the cached state to the output of the GetCachingId property:
protected override string GetCachingID()
{
return this.GetType().Name + (IsAlias() ? "Alias": "Item");
}
private bool IsAlias()
{
return Sitecore.Context.Database.Aliases.Exists(Sitecore.Context.RawUrl);
}
Props to this answer for the IsAlias logic.

In this case, wheter or not the Alias will be given relies on a setting in the web.config.
If the LinkManager has the option "ApplyAliases" (Whether or not to check for and apply aliases when possible) set to true, the LinkManager will return aliases when possible.
You can read more about configuring your LinkManager, and overriding certain settings in codebehind on this blog page written by John West.
Good luck!

Related

How to generate custom unique ID

We are using Sitecore 7.2 with multi-site implementation. The actual data is shared between multisite, hence it's been stored in common Global Item folder.
We are facing a problem generating aunique ID on URL. I had a good search but could not find any solution except to use Sitecore Item ID.
This is what we want:
domain/players/player_id
e.g. domain/players/1234
where 1234 is uniquely generated ID.
Could someone please suggest if this is possible?
Every page that is managed in Sitecore is a Sitecore Item. As such, you should be able to just navigate to the name of the player item. If you were trying to say in your post that player items are stored in globals and not as pages, then you are left with the following options:
Query String: domain/players/player?playerId={ID}
If this is the route that you choose to take then I would suggest using the player item's Sitecore ID for the value of the query string parameter.
If you have other IDs then put the specified ID there, however it would be easiest with Sitecore IDs
What you would then do is get the item with the ID specified in the query string parameter (or get the item with the player ID specified in the query string parameter, depending on which route you take) and display the data for that player on the page
Sitecore.Context.Database.GetItem(Request.QueryString["playerId"])
playerItems.FirstOrDefault(playerItem => playerItem["Player ID"] == Request.QueryString["playerId"])
Note that this assumes that the Player ID is a field, not the Sitecore ID
If it is the Sitecore ID then change the lambda to use playerItem.ID == new ID(Request.QueryString["playerId"]
Regardless of which one you use, I suggest adding null checks to the QueryString getter
Sublayout Parameters
If you use this method, the query string will not change and people will not be able to get to the page from the direct URL
The process is the same as for query strings, except that you are using Sublayout parameters instead
Note that you must set these in a parent sublayout or in Sitecore (which means that you have a separate page for each player - i.e. this would be a bad solution)
Virtual Items
This is really what I think you are looking for
This can be a lot of work if you do it from scratch, or you can use the Wildcard Module
If you do it from scratch, you will need a custom pipeline and/or processor for handling the requests
Good suggestions from Zachary. I will add a couple more:
1) IIS Rewrite Module. If what you are really after is having external URLs look like /domain/players/1234, you could easily accomplish this by forwarding these requests to something like Zachary's option #1. The client sees /domain/players/1234, but it's really handled by a single Sitecore item at /domain/player/player.aspx?playerid=1234. Client doesn't have to know that.
2) Custom ItemResolver pipeline handler. Custom Pipelines may be a bit intimidating at first, but they are actually pretty easy to implement and highly useful. Would be pretty straightforward to add a new one which checked for "players/1234" and set the ContextItem to your player handling page and drop the ID into a session variable or some context variable.

Sitecore saveUI processor redirecting to item page after moving it

I have implemented a Sitecore saveUI processor for moving news items to a specific location inside a year/month hierarchical structure. It does the job well, except for the fact that when used inside the Page Editor (navigating to an item's page and then trying to save, and implicitly move, the item) I am redirected to our 404 page, since Sitecore expects the original item's url to still be valid after the operation.
Is there any way to tell Sitecore that the item has been moved? I'm thinking at some property in SaveArgs, but any solution would do, as long as it's somewhat maintainable (for example, I'd prefer a server-side solution, not a client-side JavaScript-based one, if possible).
Off the top of my head, make sure your processor the last one in the pipeline and add the following code to the end of the process method:
if(Sitecore.Context.PageMode.IsPageEditor)
{
var item = args.SavedItems.First() // or perhaps Context.Item;
var url = LinkManager.GetItemUrl(item);
HttpContext.Current.Response.Redirect(url);
}
Have you tried using the Sitecore Newsmover Module?
This works seamlessly and could be the way to go instead of creating custom movers. We have used this plenty of times and it does seem to work well in all conditions.
Sample config for this:
<template id="User Defined/News Article" sort="Descending">
<DateField>Posted Date</DateField>
<YearTemplate formatString="yyyy">User Defined/Folders/Article Year Folder</YearTemplate>
<MonthTemplate formatString="MMMM">User Defined/Folders/Article Month Folder</MonthTemplate>
</template>

How do you do preloading of components

I would like to know how do you do pre-loading of components in sitecore 7.1?
What I tried so far:
Create a standard value for the page.
Then modify the presentation details of the standard value.
Then add components that I want preloaded in the page.
Then create a Branch for the page.
Use the Branch to create the page.
This works fine except when I add new components in the page's standard value, all existing page is affected with my changes.
What I need to know - is there away that the old page is not affected by my changes in the standard value?
Is there a way only the new page that I create is affected when I modify the pre-loading of components in my page?
Your input is appreciated.
There are few things one should consider:
If there current Sitecore installation is upgraded from 6.4 or prior version to your current version; the item's layout deltas might be an issue. You will have to check the raw values of the Layout details field and figure it out.
Any changes made on the Layout Details on Standard Values do get cascaded down to the items created from that specific Template.
If you don't want these changes to get inherited try multiple inheritance. And change the template of those items created.
Lastly, if the above doesn't work, try creating a new template with the changes you want and change the Template of those items created.
Hope the above helps. Share any further questions you might have or even if the above haven't answered your questions.
Happy Sitecoring!
The main purpose of __Standard Values is automatic update of existing items.
In this case, you should not configure the item's layout in the __Standard Values.
You need to use Branch and configure layout in the Page item instead of __Standard Values.

Sitecore GetItemUrl() resolving to alias

I've created an alias (basically a virtual (or alternative) path in Sitecore) for an item that was also re-named. My custom redirect handler is then determining the item ID for the old link correctly.
But when I call LinkManager.GetItemUrl(item, urlOptions) the resulting URL is for the alias, not the actual Sitecore item that exists in the content tree.
Is this Sitecore's default behavior for LinkManager.GetItemURL() to resolve to an item's alias, if one exists?
Here's a possibly related question with a solution.
Can you ensure you're not using a custom LinkProvider, e.g. the custom LinkProvider on the shared source? If you are using that, part of its behavior is to apply aliases for item links.
Another thing would be to look at your HTML output caching and ensure that's not the issue (as referenced in the above link for the other question).
Also, what version of Sitecore are you using?

Links and references between cloned items in Sitecore 6.4

I'm building a data repository site that I will then clone in its entirety to provide multiple clone sites, enabling localistaion of global content.
What I need to do is to ensure that all references between items in the repository site (links in rich text fields, item references to pull in "related items" spots etc) are overridden to refer to the relevant clones instead of the original items in the repository.
This will likely involve e.g. customising the LinkManager and maybe GetItem(itemID) with some additional logic to find the correct clone.
What I need to know is which bits of the API do I need to worry about? Is there a single modification I can make which will inherit to link rendering in a rich text field in .Net components, item references fed to a sublayout from drop list, renderings through XSLT etc? I need an item ID to work as an alias for its clone when in the context of the clone site. Context.Database.GetItem(ID) needs to return a clone when in the clone site context.
I'm basically looking for a mechanism that will translate "Data/Home/Products/Product A" to "clone/Home/Products/ProductA" whenever and however I use it in the context of a clone site.
Where do I need to implement this logic, how many places?
Cross posted to SDN http://sdn.sitecore.net/SDN5/Forum/ShowPost.aspx?PostID=35598
This is related to an earlier question Handling internal links in Sitecore 6.4 cloned sites , but contains more detail and is more specific.
EDIT: though the ideal solution would place this functionality deep within Sitecore it is important that this only applies to content as viewed on the actual website, i.e. it must not interfere with Sitecore pipelines for e.g. creating, cloning and deleting items.
I recommend you take a different approach. Rather than changing the links themselves, you can add code to the HttpRequestPipeline to resolve "Data/Home/Products/Product A" as "clone/Home/Products/ProductA". A similar approach is described in Reusing and Sharing Data:
A CMS user could use the Rich Text Editor, rendering properties, or other features to link to an item
based on an item selection data template. Account for these conditions in your code. You can
configure an httpRequestBegin pipeline processor to handle HTTP requests for items [...]
To apply this approach to your scenario, add the custom implementation of HttpRequestProcessor after <processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel"/> in the HttpRequestBegin pipeline in web.config.
Here's the logic to implement:
Use HttpContext.Current.Request.UrlReferrer to determine the referring site.
Verify that the referring site is in your list of cloned sites.
Check if Sitecore.Context.Item is in the source site.
Create a string with the new path, and verify that this item exists using Database.GetItem().
Modify Sitecore.Context.Item to the new item.
The advantage of this approach is that you do not need to intercept the many ways that a link can be created, and you keep your path rewriting logic in one place. In effect, you will be creating an alias from "Data/Products/ProductA" to "clone/Home/ProductA" that will only take effect if your site is in your list of clones.
Update: I did a test of this approach in Office Core. I created a second site, AlternalteSite, with a child node Our-Process. The AlternateSite home page has a link to /home/Our-Process. When the code below is added to the HttpRequestBegin pipeline, the link directs to the /AlternateSite/Our-Process item.
public class SiteChanger : HttpRequestProcessor
{
// Some definitions removed...
public override void Process(HttpRequestArgs args)
{
if (ReferringSiteIsTarget())
{
Item targetItem = GetTargetItem();
if (targetItem != null)
{
Sitecore.Context.Item = targetItem;
}
}
}
private Item GetTargetItem()
{
string currentItemPath = Sitecore.Context.Item.Paths.FullPath;
string newPath;
if (currentItemPath.Contains(SourcePath))
{
newPath = currentItemPath.Replace(SourcePath, TargetPath);
return Sitecore.Context.Database.GetItem(newPath);
}
return null;
}
}
Update2: As James Walford points out in the comments, this approach only works if the clones are not renamed. Sitecore does not, to my knowledge, provide a way of traversing from a source item to its clones in the web database. In master, you can use the Link Database to get from an item to its clones (see this forum post by John West), but after publication, clones become normal items, so presumably will not be included in the Link Database.
One approach would be to add a multilist of links to clones to the standard template, and add logic to populate this as part of the uiCloneItems pipeline, and to use this data in the HttpRequestProcessor code. This will preserve the Link Database relationship, but will put overhead on both the cloning process and the Http Request resolution process, as your code would need to iterate through all the clones to determine which one lived in the requesting website.