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.
Related
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.
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.
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);
I am using ColdFusion 8.0.1.
I am writing a little code in the application file that will look at the URL. If any of a certain type of property is passed, I don't want to update a property in a SESSION structure.
Basically, if a visitor accesses any page that has to do with our registration process, we do not want to update the SESSION.UserInfo.ReturnToURL variable. For every other page they access, we want to update the variable.
All pages that have to do with the registration process will have "myiq.reg" in the URL. If this were the case, I would use the code below.
// DETERMINE WHETHER TO UPDATE RETURNTOURL
if (not structKeyExists(URL, "myiq.reg")) {
URLString = "http://" & CGI.SERVER_NAME & CGI.SCRIPT_NAME & CGI.QUERY_STRING;
SESSION.UserInfo.ReturnToURL = URLString;
}
But it's not that simple. My people want to be able to pass other properties that are similar, like this:
myiq.reg_confirm
myiq.reg_password
myiq.reg_save
I need to be able to soft code these to work with any registration page that they might create in the future. Basically, I need something like this :
if (not structKeyExists(URL, "myiq.reg*")) {
SESSION.UserInfo.ReturnToURL = URLString;
}
Notice the WILDCARD after "myiq.reg". I've tried this, but it doesn't work.
How do I code this so that any page that is access with a URL property that begins with "myiq.reg" is ignored?
You could get a structKeyList() of the URL scope, and just do a regex find in that. Something like:
reFindNoCase("(?:^|,)myiq\.reg", structKeyList(URL))
(only superficially tested)
You could improve the regex a bit if you wanted to more accurately match actual variable name patterns rather than just any occurrence of myiq.reg in the string.
Something like this perhaps...
res = '';
params = StructKeyList(url);
for(i=1; i lte ListLen(params); i++) {
param = listGetAt(params, i);
if (CompareNoCase(Left(param, 8), 'myiq.reg') eq 0) {
res = param;
break;
}
}
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.)