Sitecore: How to get Item's Alias Url - sitecore

Is it possible to get the Alias url of an Item from .NET? I am able to use Sitecore.Links.LinkProvider class to get the item's default url, but I haven't found a way to get the Alias url.

I don't think there's a method built into the Sitecore API anywhere that does that, but you could try something like this ...
string query = String.Format("/*/system/Aliases//*[##templateid='{0}' and contains(#Linked item, '{1}')]", Sitecore.TemplateIDs.Alias, Sitecore.Context.Item.ID);
Sitecore.Data.Items.Item alias = Sitecore.Context.Database.SelectSingleItem(query);
string aliasUrl = string.Empty;
if (alias != null) {
aliasUrl = String.Format("/{0}.aspx", alias.Name);
}
(I have not tested this, it's based on some code I'm already using + some other stuff off the top of my head.)

Related

Add cookie for Xdebug in Paw

I debug my API using Xdebug and PHPStorm's debugging features. For this to work, the client needs a cookie named XDEBUG_SESSION.
When using Postman, I used to use a Chrome extension to add this cookie, and Postman's cookie interception feature to get this to work in Postman (since it's a sandboxed app).
However, I cannot create cookies in Paw. So, as a workaround, I modified the API response cookie to have the key as XDEBUG_SESSION and value as PHPSTORM, and debugging worked fine. However, this is not ideal as I would also like to set the expiry date to something far in the future (which I can't in Paw).
So, my questions are:
Is there a way to add custom cookies in Paw?
If not, is there a way to to edit the expiry date for an existing cookie (considering that name, value, domain and path are editable)?
Are there any other alternatives to achieve my objective?
I just managed to achieve this exact thing to debug my APIs with Paw (2.1.1).
You just have to Add a Header with the name Cookie and a value of Cookies picked from the dropdown that will appear. You then have to insert a Cookie named XDEBUG_SESSION with a value of PHPSTORM inside the Cookies value of the header just created.
To be more clear, you can see it in the screenshot below:
I messed around with it to see if I could create an extension. I wasn't able to, and the below does not work but thought I'd share in case anyone knows the missing pieces.
First off, there is no extension category (generator, dynamic value, importer) that this functionality falls into. I tried to make use of the dynamic value category but was unsuccessful:
CookieInjector = function(key, value) {
this.key = "XDEBUG_SESSION";
this.value = "PHPSTORM";
this.evaluate = function () {
var f = function (x,y) {
document.cookie=this.key+"="+this.value;
return true;
}
return f(this.key, this.value);
}
// Title function: takes no params, should return the string to display as
// the Dynamic Value title
this.title = function() {
return "Cookie"
}
// Text function: takes no params, should return the string to display as
// the Dynamic Value text
this.text = function() {
return this.key+"="+this.value;
}
}
// Extension Identifier (as a reverse domain name)
CookieInjector.identifier = "com.luckymarmot.PawExtensions.CookieInjector";
// Extension Name
CookieInjector.title = "Inject Cookie Into Cookie Jar";
// Dynamic Value Inputs
CookieInjector.inputs = [
DynamicValueInput("key", "Key", "String"),
DynamicValueInput("value", "Value", "String")
]
// Register this new Extension
registerDynamicValueClass(CookieInjector);
The main thing stopping this from working is I'm not sure how the request is built in PAW and not sure how to attach the cookie. I've looked through the documentation here: https://luckymarmot.com/paw/doc/Extensions/Reference/Reference, and can't find what I need.

Sitecore Url works with any Extension

In my website , the url's are working even entering something after .aspx and giving staus code 200.
Eg: below is normal page with .aspx and status code 200.
But even i have any random extension i got 200 status code which suppossed to be a 404 Status code,
Any Help.
Sitecore is quite generous when it resolves URL's. If you want to enforce correct extensions, you could create a custom Item Resolver which ensures the context item remains null in the process method if the URL has the incorrect extension.
Here's a helpful article on creating an Item Resolver:
Thoughts on httpRequestBegin - Custom Item Lookups
In my example below, the base process method is called. After that we check if the Context Item meets the requirements, and set it to null if not. (You'll need to implement TemplateIsAPageType and ExtensionIsValid as you see fit.)
public class CustomItemResolver : HttpRequestProcessor
{
public override void Process( HttpRequestArgs args )
{
base.Process(args);
if( Context.Item != null && TemplateIsAPageType() && !ExtensionIsValid())
{
Context.Item = null;
}
}
}
Another approach might be something like this, where we compare the requested URL with the resolved item's 'ideal' URL:
public class CustomItemResolver : HttpRequestProcessor
{
public override void Process( HttpRequestArgs args )
{
base.Process(args);
if( Context.Item == null)
return;
var requestUrl = HttpContext.Current.Request.RawUrl;
var idealUrl = LinkManager.GetItemUrl(Context.Item);
if(requestUrl != idealUrl)
Context.Item = null;
}
}
Sitecore skips everything after the last dot ”.” in an url when attempting to resolve an item.
This is done by the class Sitecore.Web.RequestUrl which has a property called ItemPath. This property attempts to create a valid path to an item from the requested url. It is not possible to override this property.
If you for some reason would like Sitecore to return a 404 status code if an item is requested with a file extension, such as .aspx, you could do something like this in a 404 not found item resolver. See this post http://laubplusco.net/handling-404-sitecore-avoid-302-redirects/ the following method extends the one shown in the post.
protected virtual bool IsValidContextItemResolved(string filePath)
{
if (Context.Item == null || !Context.Item.HasContextLanguage())
return false;
if (filePath.Contains(".") && !RequestIsForPhysicalFile(filePath))
return false;
return !(Context.Item.Visualization.Layout == null
&& string.IsNullOrEmpty(WebUtil.GetQueryString("sc_layout")));
}
It is important to ensure that the requested url is not for a physical file first. This is done by checking that the args.Url.filepath does not map to a physical file.
The rule which I show here says that if an item has been resolved and the filepath contains a dot then the requested url should return a 404 and the context item should be the not found item. The code could be extended to check what comes after the dot to see if it is a valid extension.

Sitecore Multisite Manager and 'source' field in template builder

Is there any way to parametise the Datasource for the 'source' field in the Template Builder?
We have a multisite setup. As part of this it would save a lot of time and irritation if we could point our Droptrees and Treelists point at the appropriate locations rather than common parents.
For instance:
Content
--Site1
--Data
--Site2
--Data
Instead of having to point our site at the root Content folder I want to point it at the individual data folders, so I want to do something like:
DataSource=/sitecore/content/$sitename/Data
I can't find any articles on this. Is it something that's possible?
Not by default, but you can use this technique to code your datasources:
http://newguid.net/sitecore/2013/coded-field-datasources-in-sitecore/
You could possibly use relative paths if it fits with the rest of your site structure. It could be as simple as:
./Data
But if the fields are on random items all over the tree, that might not be helpul.
Otherwise try looking at:
How to use sitecore query in datasource location? (dynamic datasouce)
You might want to look at using a Querable Datasource Location and plugging into the getRenderingDatasource pipeline.
It's really going to depend on your use cases. The thing I like about this solution is there is no need to create a whole bunch of controls which effectively do he same thing as the default Sitecore ones, and you don't have to individually code up each datasource you require - just set the query you need to get the data. You can also just set the datasource query in the __standard values for the templates.
This is very similar to Holger's suggestion, I just think this code is neater :)
Since Sitecore 7 requires VS 2012 and our company isn't going to upgrade any time soon I was forced to find a Sitecore 6 solution to this.
Drawing on this article and this one I came up with this solution.
public class SCWTreeList : TreeList
{
protected override void OnLoad(EventArgs e)
{
if (!String.IsNullOrEmpty(Source))
this.Source = SourceQuery.Resolve(SContext.ContentDatabase.Items[ItemID], Source);
base.OnLoad(e);
}
}
This creates a custom TreeList control and passes it's Source field through to a class to handle it. All that class needs to do is resolve anything you have in the Source field into a sitecore query path which can then be reassigned to the source field. This will then go on to be handled by Sitecore's own query engine.
So for our multi-site solution it enabled paths such as this:
{A588F1CE-3BB7-46FA-AFF1-3918E8925E09}/$sitename
To resolve to paths such as this:
/sitecore/medialibrary/Product Images/Site2
Our controls will then only show items for the correct site.
This is the method that handles resolving the GUIDs and tokens:
public static string Resolve(Item item, string query)
{
// Resolve tokens
if (query.Contains("$"))
{
MatchCollection matches = Regex.Matches(query, "\\$[a-z]+");
foreach (Match match in matches)
query = query.Replace(match.Value, ResolveToken(item, match.Value));
}
// Resolve GUIDs.
MatchCollection guidMatches = Regex.Matches(query, "^{[a-zA-Z0-9-]+}");
foreach (Match match in guidMatches)
{
Guid guid = Guid.Parse(match.Value);
Item queryItem = SContext.ContentDatabase.GetItem(new ID(guid));
if (item != null)
query = query.Replace(match.Value, queryItem.Paths.FullPath);
}
return query;
}
Token handling below, as you can see it requires that any item using the $siteref token is inside an Site Folder item that we created. That allows us to use a field which contains the name that all of our multi-site content folders must follow - Site Reference. As long at that naming convention is obeyed it allows us to reference folders within the media library or any other shared content within Sitecore.
static string ResolveToken(Item root, string token)
{
switch (token)
{
case "$siteref":
string sRef = string.Empty;
Item siteFolder = root.Axes.GetAncestors().First(x => x.TemplateID.Guid == TemplateKeys.CMS.SiteFolder);
if (siteFolder != null)
sRef = siteFolder.Fields["Site Reference"].Value;
return sRef;
}
throw new Exception("Token '" + token + "' is not recognised. Please disable wishful thinking and try again.");
}
So far this works for TreeLists, DropTrees and DropLists. It would be nice to get it working with DropLinks but this method does not seem to work.
This feels like scratching the surface, I'm sure there's a lot more you could do with this approach.

How to generate media item link with id instead of path in Sitecore

Anyone knows how to generate links in sitecore with ID instead of item path?
If you use GetMediaUrl method from the API, I can get this URL:
/~/media/Images/Archive/content/News and Events/News_and_Events_Level2/20070419162739/iwhiz3.jpg
The problem with this approach is that if someone changes the media item name, removes it somewhere or deletes it, the above link will break.
I notice if I insert a media link from rich text editor, I get the link as below:
/~/media/14BDED00E4D64DFD8F74019AED4D74EB.ashx
The second link is better because it's using the item id, so if the actual media item is renamed, removed, or deleted, all related links will be updated too. On top of that, when Sitecore renders the page, it will actually convert the above link and display the item path so it's readable.
I'm using Sitecore 6.5 and currently doing content migration so I need to make sure all internal links are updated properly.
May I know if there is a method to generate the second link by using sitecore API?
Thanks!
The GetMediaItemUrl extension method seems to give you what you want.
public static class ItemExtensions
{
public static string GetMediaItemUrl(this Item item)
{
var mediaUrlOptions = new MediaUrlOptions() { UseItemPath = false, AbsolutePath = true };
return Sitecore.Resources.Media.MediaManager.GetMediaUrl(item, mediaUrlOptions);
}
}
[TestFixture]
public class when_using_items_extensions
{
[Test]
public void a_url_based_on_media_item_id_can_be_generated()
{
// Arrange
Database db = global::Sitecore.Configuration.Factory.GetDatabase("master");
Item item = db.GetItem("/sitecore/media library/Images/MyImage");
// Act
var mediaUrl = item.GetMediaItemUrl();
// Assert
Assert.That(mediaUrl, Is.EqualTo("/~/media/17A1341ABEEC46788F2159843DCEAB03.ashx"));
}
}
These are called dynamic links and you can normally generate them using the LinkManager e.g:
Sitecore.Links.LinkManager.GetDynamicUrl(item)
.. but I'm not sure of the method to do this with Media links (there probably is one but I cant seem to find it and its not on MediaManager) but the basic syntax is:
"/~/media/" + item.ID.ToShortID() + ".ashx"
If you always want to use ID's instead of paths, you can change this setting in webconfig to false (like this):
<setting name="Media.UseItemPaths" value="false"/>`
Here is what the webconfig describes about it:
MEDIA - USE ITEM PATHS FOR URLS
This setting controls if item paths are used for constructing media URLs.
If false, short ids will be used.
Default value: true
Then you can use the default implementation (without additional parameters):
Sitecore.Resources.Media.MediaManager.GetMediaUrl(item);
This is what I use:
var imgField = ((Sitecore.Data.Fields.ImageField)currentItem.Fields["Icon"]);
MediaUrlOptions opt = new MediaUrlOptions();
opt.AlwaysIncludeServerUrl = true;
// Absolute Path works as well. So either use AbsolutePath or AlwaysIncludeServerUrl
opt.AbsolutePath = true;
string mediaUrl = MediaManager.GetMediaUrl(imgField.MediaItem, opt);

sitecore query items by client url

I am looking for a quick and dirty way to query the layouts files of a particular page by its friendly url. This is probably easy, but I can't find the solution.
Basically I want to say something like the following. Pseudo-code:
var mainpage = Sitecore.EasyQueryUtility.GetItemByFriendlyUrl(requestedUrl);
or
var mainpage = Sitecore.EasyQueryUtility.GetOppositeOfFriendlyUrl(friendlyurl);
It sounds like you want to do two things here:
Determine an item based on its rendered URL in the address bar (i.e. friendly URL)
Determine the layout being used by the item once you determine the item.
If those are correct, hopefully this can help you out:
Note: untested code I did on-the-fly
// if you have the full URL with protocol and host
public static Item GetItemFromUrl(string url)
{
string path = new Uri(url).PathAndQuery;
return GetItemFromPath(path);
}
// if you have just the path after the hostname
public static Item GetItemFromPath(string path)
{
// remove query string
if(path.Contains("?"))
path = path.split('?')[0];
path = path.Replace(".aspx", "");
return Sitecore.Context.Database.GetItem(path);
}
Once you have the item you can get the layout's name like so:
item.Visualization.GetLayout(Sitecore.Context.Device).Name;
Or the layout's physical file path to the ASPX:
item.Visualization.GetLayout(Sitecore.Context.Device).FilePath;
If you want to get the path of the aspx file which is used for the layout of your page, you can use:
Sitecore.Context.Item.Visualization.Layout.FilePath
I may have misunderstood you but if you want to control the format of friendly URLs you can set several attributes via the Sitecore.Links.UrlOptions class and pass an instance of this in to the link manager. See here for more details. (Note - the LinkManager class is only available from SiteCore 6 I beleive).
The code you would end up with looks like this:
Sitecore.Links.UrlOptions urlOptions = (Sitecore.Links.UrlOptions)Sitecore.Links.UrlOptions.DefaultOptions.Clone();
urlOptions.SiteResolving = Sitecore.Configuration.Settings.Rendering.SiteResolving;
string url = Sitecore.Links.LinkManager.GetItemUrl(item, urlOptions);
You can then set fields like AddAspxExtension on the urlOptions you pass in.
As you can see, the process is reliant on you passing in an item - whether it be obtained via the current context or retrieved from the URL you start off with.
If you were asking about obtaining the layout definition item, take a look at this which shows you how.