sitecore identify template type in treelist view - sitecore

I have a treelist which allows an editor to define a list of links which is then output in a sublayout.
Depending upon which templates the selected pages use in that treelist field will determine the field values I need to write out.
I have a generic content page template where its own sitecore URL should be referenced but I then have a pseudo template which contains a field for a string URL and additional field params relating to to an external site.
In that scenario I don't want the sitecore URL I instead need its field values so as to concat a link to an external site along with the token details and present that to the user in the list of links.
Currently I have the code below but I need to include a condition that says if the template of the current GUID item is type 'SSO-Link' then don't retrieve its sitecore URL from linkmanager instead refer to a field called URL as well as a number of additional fields.
Thanks - current code below
Item[] selectedItems = treelistField.GetItems();
foreach (Item item in selectedItems)
{
string itemName = item.Name;
string displayName = item.DisplayName;
string url = LinkManager.GetItemUrl(item);
string linkName = "Undefined";
if (displayName != null)
{
linkName = displayName;
}
else if (itemName != null)
{
linkName = itemName;
}
if (linkName != "Undefined" && url != null)
{
htmlOutput.Text += "<a href=\"" + url + "\">";
htmlOutput.Text += linkName;
htmlOutput.Text += "</a>";
}
}

From what I understand, you need to add this simple condition at the beginning of your loop:
foreach (Item item in selectedItems)
{
string url = null;
if (item.TemplateName == "SSO-Link")
{
url = item["URL"];
// other fields
}
else
{
url = LinkManager.GetItemUrl(item);
}
// your code

I use an extension for my templates and template items. Then I call a constants class for the ID of the template I am comparing to.
public static class TemplateExtensions
{
public static bool IsDerived([NotNull] this Template template, [NotNull] ID templateId)
{
return template.ID == templateId || template.GetBaseTemplates().Any(baseTemplate => IsDerived(baseTemplate, templateId));
}
public static bool IsDerived([NotNull] this TemplateItem template, [NotNull] ID templateId)
{
return template.ID == templateId || template.BaseTemplates.Any(baseTemplate => IsDerived(baseTemplate, templateId));
}
}
Constants
public static class Products
{
public static TemplateID ProductSection = new TemplateID(new ID("{73400360-5935-40B6-88BC-350DC5B9BC90}"));
public static TemplateID ProductDetail = new TemplateID(new ID("{9CD3D5ED-E579-4611-88E0-6B44C9D56F16}"));
}
Use
if (item.IsDerived(Products.ProductDetail))
{ if code here }
Hope this helps.

Related

Display items in bucket with Sitecore Data Provider

Hej Guys
I have a rather large problem, I've been tasked with creating a Custom Data Provider for extracting Stock Keeping Units(SKUs) from a SOLR database into sitecore, without actually populating the database with items.
I've created a data provider, which succesfully pulls data from the SOLR database a "creates" the items in sitecore, by using the following code:
public class SkuDataProvider : DataProvider, ISkuDataProvider
{
private readonly string _targetDatabaseName = "master";
private readonly string _idTablePrefix = "Skus";
private readonly ID _skuTemplateId = new ID("{F806B403-BDAF-4C60-959D-E706A82FC1DC}");
private readonly ID _skuRootTemplateId = new ID("{9767BC47-0A95-40E9-A2DE-3766FF241411}");
private readonly IEnumerable<SkuItemInfo> _skus;
public SkuDataProvider(/*IProductPageService productPageService*/)
{
_skus = new MockDataForSkuDataProvider().GetSimpleSkuCollection();
}
public override ItemDefinition GetItemDefinition(ID itemId, CallContext context)
{
Assert.ArgumentNotNull(itemId, "itemID");
// Retrieve the sku id from Sitecore's IDTable
var skuId = GetSkuIdFromIdTable(itemId);
if (!string.IsNullOrEmpty(skuId))
{
// Retrieve the sku data from the skus collection
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
// Ensure the sku item name is valid for the Sitecore content tree
var itemName = ItemUtil.ProposeValidItemName($"{sku.SkuId}_{sku.Name}");
// Return a Sitecore item definition for the sku using the sku template
return new ItemDefinition(itemId, itemName, ID.Parse(_skuTemplateId), ID.Null);
}
}
return null;
}
private string GetSkuIdFromIdTable(ID itemId)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemId);
if (idTableEntries.Any())
return idTableEntries[0].Key.ToString();
return null;
}
public override IDList GetChildIDs(ItemDefinition parentItem, CallContext context)
{
if (CanProcessParent(parentItem.ID))
{
var itemIdList = new IDList();
foreach (var sku in _skus)
{
var skuId = sku.SkuId;
// Retrieve the Sitecore item ID mapped to his sku
IDTableEntry mappedId = IDTable.GetID(_idTablePrefix, skuId) ??
IDTable.GetNewID(_idTablePrefix, skuId, parentItem.ID);
itemIdList.Add(mappedId.ID);
}
context.DataManager.Database.Caches.DataCache.Clear();
return itemIdList;
}
return base.GetChildIDs(parentItem, context);
}
private bool CanProcessParent(ID id)
{
var item = Factory.GetDatabase(_targetDatabaseName).Items[id];
bool canProcess = item.Paths.IsContentItem && item.TemplateID == _skuRootTemplateId && item.ID == new ID("{F37753A0-BC79-4FF7-B975-A8F142AACD76}");
return canProcess;
}
public override ID GetParentID(ItemDefinition itemDefinition, CallContext context)
{
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
return idTableEntries.First().ParentID;
}
return base.GetParentID(itemDefinition, context);
}
public override FieldList GetItemFields(ItemDefinition itemDefinition, VersionUri version, CallContext context)
{
var fields = new FieldList();
var idTableEntries = IDTable.GetKeys(_idTablePrefix, itemDefinition.ID);
if (idTableEntries.Any())
{
if (context.DataManager.DataSource.ItemExists(itemDefinition.ID))
{
ReflectionUtil.CallMethod(typeof(ItemCache), CacheManager.GetItemCache(context.DataManager.Database), "RemoveItem", true, true, new object[] { itemDefinition.ID });
}
var template = TemplateManager.GetTemplate(_skuTemplateId, Factory.GetDatabase(_targetDatabaseName));
if (template != null)
{
var skuId = GetSkuIdFromIdTable(itemDefinition.ID);
if (!string.IsNullOrEmpty(skuId))
{
var sku = _skus.FirstOrDefault(o => o.SkuId == skuId);
if (sku != null)
{
foreach (var field in GetDataFields(template))
{
fields.Add(field.ID, GetFieldValue(field, sku));
}
}
}
}
}
return fields;
}
protected virtual IEnumerable<TemplateField> GetDataFields(Template template)
{
return template.GetFields().Where(ItemUtil.IsDataField);
}
private string GetFieldValue(TemplateField field, SkuItemInfo sku)
{
string fieldValue = string.Empty;
switch (field.Name)
{
case "Name":
fieldValue = sku.Name;
break;
case "SkuId":
fieldValue = sku.SkuId;
break;
default:
break;
}
return fieldValue;
}
}
}
The problem emerges when accessing the Sitecore backend, where all items appears below the bucket item in a hierarchly-way.
I've checked that the Root item is set a bucket and that the template used is bucketable.
Furthermore when inserting manually in the backend, the item is correctly inserted in the bucket.
Do anyone got an idea for me, on how to fix this issue?
Best Regards
Nicolai
You need to set the Is Bucketable flag on the standard values of the template item rather than the template item itself.
Also, the way that items get "bucketed" is via events when the item is being created or saved. Sitecore then creates the bucket folders to store the items in. In your case as you have virtual items, you will need to handle their path via the data provider.
If you just want them hidden in the same way that they are in a standard bucket, then I would suggest creating a bucket folder under your SKU Root folder and using that item as the parent for all SKU virtual items. That way the bucket folder will be hidden by sitecore and you will get the same view as a standard bucket.
This is the template to use:

Sitecore media item url

I am on Sitecore 7.2
I am experiencing issues trying to retrieve media URL.
I have a template (PageBanner) with just one field called BannerImage. Field type is Image.
Another template named Homepage inherits this template PageBanner.
A content item Home uses template Homepage. I can see the BannerImage field as a part of the Home content item. An image has been assigned to this field as well.
Now, the back-end bit where the issue is encountered.
homeItem.Field["BannerImage"] returns image item.
homeItem["BannerImage"] returns empty string.
If I try to cast it to ImageField -(ImageField)homeItem.Field["BannerImage"], the resultant ImageField item doesn't have MediaItem or any other field set.
I can do :
var imageFieldItem = Sitecore.Context.Database.GetItem(homeItem.Fields["BannerImage"].ID);
var mediaUrl = MediaManager.GetMediaUrl(imageFieldItem);
But that gives me a dynamic media url in the form of -~/media/a2c15f35836746f398e772c81d040607.ashx
I am looking to get the media URL by path.
Any idea what am I missing here?
You are making the correct call to get the URL using the MediaManager but you need to pass the inner MediaItem to the GetMediaUrl() method:
string imageURL = string.Empty;
Sitecore.Data.Fields.ImageField imageField = homeItem.Field["BannerImage"];
if (imageField != null && imageField.MediaItem != null)
{
Sitecore.Data.Items.MediaItem image = new Sitecore.Data.Items.MediaItem(imageField.MediaItem);
imageURL = Sitecore.StringUtil.EnsurePrefix('/', Sitecore.Resources.Media.MediaManager.GetMediaUrl(image));
}
As for the dynamic URL being generated, if it is in Edit mode then this is normal, Check in Normal mode that the media URL is fully rendered.
Try this code out in some utility class.
var imageUrl = GetImageUrl(homeItem, "BannerImage" false);
public static string GetImageUrl(Item item, string fieldname, bool includeServerUrl)
{
// do the checks
if (item == null) { return ""; }
if (fieldname.Length == 0) { return ""; }
// create media options
Sitecore.Resources.Media.MediaUrlOptions mediaUrlOptions = new Sitecore.Resources.Media.MediaUrlOptions { AlwaysIncludeServerUrl = true };
mediaUrlOptions.AbsolutePath = true;
// do we want to include the FQDN?
if (includeServerUrl)
mediaUrlOptions.AlwaysIncludeServerUrl = true;
// convert to image field
Sitecore.Data.Fields.ImageField imagefield = item.Fields[fieldname];
if (imagefield == null) { return ""; }
// get the item so we can process it
Item mediaitem = Sitecore.Context.Database.GetItem(imagefield.MediaID);
if (mediaitem == null) { return ""; }
// pass in the item with the options to get the URL
string mediaurl = Sitecore.Resources.Media.MediaManager.GetMediaUrl(mediaitem, mediaUrlOptions);
if (mediaurl == null) { return ""; }
return mediaurl;
}

Programmatically add a new field in a template in sitecore

In Sitecore is it possible to programmatically add a new field in a template?
I have a template "DictionaryName", in this template I want to add a field "Newname" with its type "Single-Line Text".
I wrote and tested this code for you - it worked out perfect on my machine and created new single line field within template specified. Here is the method:
private void AddFieldToTemplate(string fieldName, string tempatePath)
{
const string templateOftemplateFieldId = "{455A3E98-A627-4B40-8035-E683A0331AC7}";
// this will do on your "master" database, consider Sitecore.Context.Database if you need "web"
var templateItem = Sitecore.Configuration.Factory.GetDatabase("master").GetItem(tempatePath);
if (templateItem != null)
{
var templateSection = templateItem.Children.FirstOrDefault(i => i.Template.Name == "Template section");
if (templateSection != null)
{
var newField = templateSection.Add(fieldName, new TemplateID(new ID(templateOftemplateFieldId)));
using (new EditContext(newField))
{
newField["Type"] = "Text"; // text stands for single-line lext field type
}
}
{
// there are no template sections here, you may need to create one. template has only inherited fields if any
}
}
}
And below is the usage - first string parameter is the name of your new field, the second is string value for template path within the database you are using:
AddFieldToTemplate("New Single Line Field", "/sitecore/templates/Sample/Sample Item");
Replace "Sample Item" template with your template path and set desired field name to add. Also do not forget usings for namespaces:
using Sitecore;
using Sitecore.Data;
using Sitecore.Data.Items;
Hope this helps!
You can access programmatically a template from the item and then add a an item to this template. The template is a usual item childrens.
Wrote this Example for you.
Want to find out more https://doc.sitecore.com/legacy-docs/SC71/data-definition-api-cookbook-sc70-a4.pdf
public JsonResult CreateTemplate()
{
try
{
using(new SecurityDisabler())
{
///Get Database
Database master = Sitecore.Configuration.Factory.GetDatabase("master");
/// Every node in content tree ia an Item. Ex- Templates,Field, Item, etc.
/// Template: /sitecore/templates/System/Templates/Template -{AB86861A-6030-46C5-B394-E8F99E8B87DB}
var templateId = master.GetTemplate(new ID("{AB86861A-6030-46C5-B394-E8F99E8B87DB}"));
/// parentItem is the item/ Template folder where you want to create your template.
/// ParentItem: /sitecore/templates/[new folder {Guid}]
Item parentItem = master.GetItem(new ID("{3C7516ED-7E3E-4442-8124-26691599596E}"));
Item newItem = parentItem.Add("HelloTemplate", templateId);
// adding Field in Templates.
TemplateItem exampleTemplate = master.Templates[new ID(newItem.ID.ToString())];
TemplateSectionItem data = exampleTemplate?.GetSection("data");
if( data == null || data.InnerItem.Parent.ID != exampleTemplate.ID)
{
data = exampleTemplate.AddSection("Data", false);
}
TemplateFieldItem title = data?.GetField("title");
if(title == null)
{
TemplateFieldItem field = data.AddField("Title");
}
}
return Json(new { Result = "item created" }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(new { Result = "item not created " + ex.Message+"\n"+ex.StackTrace } , JsonRequestBehavior.AllowGet);
}
}

determine roles that have access to an item in Sitecore - in code

Sitecore 6.5 system:
In code, is there a way to determine which roles have access to a specific item?
I have an extranet set up, some items are "protected" - meaning the anonymous account has had the inheritance broken, and certain roles have been granted read access. I already have a custom pipeline built, so I can determine when user attempts to view a protected item, but I need to determine what role(s) has access to view the item so I can direct them appropriately.
Thanks,
Thad
edit:
Here is the relevant code - there may be a better way of doing this (I inherited the system & code), but I am attempting to utilize what was already in place. The problem with the code below is that Sitecore.Context.Item is null when the user doesn't have permission.
public class NotFoundProcessor : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
if (args.PermissionDenied)
{
//determine what role would give the user access
foreach(Sitecore.Security.Accounts.Role role in Sitecore.Security.Accounts.RolesInRolesManager.GetAllRoles())
{
bool roleCanRead = Sitecore.Context.Item.Security.CanRead(role);
//... do stuff here
}
}
}
}
Just from the top of my head, you can check all the roles if they have read access to chosen item:
foreach (Role role in RolesInRolesManager.GetAllRoles())
{
bool roleCanRead = item.Security.CanRead(role);
}
EDIT after code sample provided:
You need to try to resolve the item in the same way as ItemResolver does but wrapped it with SecurityDisabler and without setting it to Sitecore Context afterwards. This will allow you to find the requested item despite the fact the user doesn't have access to it:
public class NotFoundProcessor : HttpRequestProcessor
{
public override void Process(HttpRequestArgs args)
{
if (args.PermissionDenied)
{
Item item = GetItemUsingSecurityDisabler(args);
//determine what role would give the user access
foreach(Role role in RolesInRolesManager.GetAllRoles())
{
bool roleCanRead = item.Security.CanRead(role);
//... do stuff here
}
}
}
}
private Item GetItemUsingSecurityDisabler(HttpRequestArgs args)
{
using (new SecurityDisabler())
{
string path = MainUtil.DecodeName(args.Url.ItemPath);
Item item = args.GetItem(path);
if (item == null)
{
path = args.Url.ItemPath;
item = args.GetItem(path);
}
if (item == null)
{
path = args.LocalPath;
item = args.GetItem(path);
}
if (item == null)
{
path = MainUtil.DecodeName(args.LocalPath);
item = args.GetItem(path);
}
SiteContext site = Sitecore.Context.Site;
string rootPath = site != null ? site.RootPath : string.Empty;
if (item == null)
{
path = FileUtil.MakePath(rootPath, args.LocalPath, '/');
item = args.GetItem(path);
}
if (item == null)
{
path = MainUtil.DecodeName(FileUtil.MakePath(rootPath, args.LocalPath, '/'));
item = args.GetItem(path);
}
// I've ommited resolving item using DisplayName but you can add if necessary here
return item;
}
}

How to use sitecore query in datasource location? (dynamic datasource)

Is it possible to set the datasource location (not the datasource) to be a sitecore query?
What I'm trying to do is to have the sublayout set its datasource location to a folder under the item containing it (current item).
The sublayout datasource location should point to a folder under the current item. So I tried setting the datasource location to query:./Items/* but that did not work.
You don't need the query -- the sublayout datasource location can simply use a relative path. e.g.
./Items
Obviously though, that folder needs to exist already. I've been meaning to blog this code, and it may be overkill but I'll post here since it may help you. The following can be added to the getRenderingDatasource pipeline to create a relative path datasource location if it doesn't exist already. Add it before the GetDatasourceLocation processor.
On the sublayout, you'll want to add a parameter contentFolderTemplate=[GUID] to specify the template of the item that gets created.
public class CreateContentFolder
{
protected const string CONTENT_FOLDER_TEMPLATE_PARAM = "contentFolderTemplate";
public void Process(GetRenderingDatasourceArgs args)
{
Assert.IsNotNull(args, "args");
Sitecore.Data.Items.RenderingItem rendering = new Sitecore.Data.Items.RenderingItem(args.RenderingItem);
UrlString urlString = new UrlString(rendering.Parameters);
var contentFolder = urlString.Parameters[CONTENT_FOLDER_TEMPLATE_PARAM];
if (string.IsNullOrEmpty(contentFolder))
{
return;
}
if (!ID.IsID(contentFolder))
{
Log.Warn(string.Format("{0} for Rendering {1} contains improperly formatted ID: {2}", CONTENT_FOLDER_TEMPLATE_PARAM, args.RenderingItem.Name, contentFolder), this);
return;
}
string text = args.RenderingItem["Datasource Location"];
if (!string.IsNullOrEmpty(text))
{
if (text.StartsWith("./") && !string.IsNullOrEmpty(args.ContextItemPath))
{
var itemPath = args.ContextItemPath + text.Remove(0, 1);
var item = args.ContentDatabase.GetItem(itemPath);
var contextItem = args.ContentDatabase.GetItem(args.ContextItemPath);
if (item == null && contextItem != null)
{
string itemName = text.Remove(0, 2);
//if we create an item in the current site context, the WebEditRibbonForm will see an ItemSaved event and think it needs to reload the page
using (new SiteContextSwitcher(SiteContextFactory.GetSiteContext("system")))
{
contextItem.Add(itemName, new TemplateID(ID.Parse(contentFolder)));
}
}
}
}
}
}