I am trying to access content from my level 2 document type from a sub level in Umbraco. level 2 has multiple pages of same document type. I am using the code below
var rootByTraversing = Umbraco.AssignedContentItem.AncestorOrSelf(2);
var openingTimesByDescendants = rootByTraversing.Descendants().Where(f => f.DocumentTypeAlias == "PageLevel2").FirstOrDefault();
Is it possible for me to get the immediate parent node of this document type and not FirstOrDefault node?
I don't want to access the content through node id.
Not sure I follow entirely, especially why you don't want to access via node ID... Your current content item has a Path property in which all ancestors IDs are listed in a comma separated list. Couldn't you just split that string and select whichever level (like ancestors[2] for level 2, I'd guess) to get the ID of that node. Then you could go something like
var level2AncestorId = Umbraco.AssignedContentItem.Path.Split(',')[2];
var openingTimesByDescendants = rootByTraversing.Descendants().Where(f => f.Id == (int)level2AncestorId && f.DocumentTypeAlias == "PageLevel2").FirstOrDefault();
Which should only give you one node and it should be the direct ancestor. Right?
Related
I have 'Association' content type with added Container Part. I also have "Company" and "Bearer" content types which have Containable Part. So Association contains some companies and bearers. I have query which returns me all associations. I'm trying to show items in grid (i have created custom layout provider and custom view for cell of grid). It's working, but when i'm trying to get items from Container part for each associatian - i don't get it. I mean i can get Container Part and even can get Items count , but can't get content items for companies and bearers. Also it will show me whole count of items in Container part. I need to get count of companies in Container part, exclude bearers count. How can i do it? Thanks!
The actual content items aren't stored on ContainerPart. Instead, each contained item's CommonPart has a Container value that links to the container. You need to use LINQ to locate all ContentItems that have CommonPart.Container equal to your container.
int containerId = containerItem.Id;
var containedList = _contentManager
.Query<CommonPart>()
.Join<CommonPartRecord>()
.Where(x => x.Container.Id == containerId)
.List();
I'm new to Umbraco, so this may not even be feasible. I've created my own Datatype using Archetype and want to be able to get an instance of that type on the page by type, not alias.
I know that I can do the following:
model.Content.GetPropertyValue("myAlias")
But I want to know if it's feasible to get the property by the type. Something along the lines of:
model.Content.GetPropertiesByType("TypeName")
which would return a list of controls on the page of that type?
Is this feasible?
It's possible, but not exactly straight forward.
Take a look at the available Umbraco Data Services - you'll need to retrieve the DataTypeDefinitions from the DataTypeService and retrieve the ContentType for the Model's IPublishedContent using the ContentTypeService.
Once you have these, you can match up the PropertyTypes on the ContentType with the retrieved DataTypeDefionitions based on the PropertyType's DataTypeDefinitionId.
The PropertyTypes have an Alias property which will match up with the Property Aliases on the Content itself.
You can use the content service if you get the id of the datatype you trying to find the multiples of from the url when you edit/create the datatype.
#foreach (var p in ApplicationContext.Current.Services.ContentService.GetById(Model.Content.Id).PropertyTypes.Where(p => p.DataTypeDefinitionId == -89))
{
<p>#p.DataTypeDefinitionId</p>
}
There are 3 concepts each type of user loggin in. The imagery is controlled by a lookup table based on the host header. By this, I mean that there are several domain names that point to the same IP/web instance, and that instance serves up the content based on reading the host header.
What we are doing now by having all the HTML (not the code) stored in a table that is referenced by the host header lookup.
CAn somebody guide me on this requirement please? Thanks
There are probably better ways to deal with multi-tenancy but let's assume you can't change any of that. What you want is probably this
string domain = HttpContext.Current.Request.ServerVariables["HTTP_HOST"];
You could map this domain onto a customer Id and store this in the user's cookie and look up based on this, mapping as necessary. Or simply use domain directly for your table lookup.
Request.Url.Host
This will give you the domain name such as: "www.example.com". I would recommend to store records including "view name" and "domain". Then, on your action, I would imagine something like this:
var record = db.HostRecords.Where(r => r.Domain == Request.Url.Host).FirstOrDefault();
var view = "Page.cshtml";
if (record != null){
view = record.ViewName;
}
return View(view);
I just want to customize List view.
is it possible? I think yes. How?
How to name alternative for List of Content types, let say, "Question"
Sure. As the question is a little vague about context, I'll make assumptions. I'll assume that you have a controller action building the list (similar to what the blog is doing). From the action, you are usually building a list shape with code looking something like this:
var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
var things = _someServiceClass.GetThings(something)
.Skip(pager.GetStartIndex()).Take(pager.PageSize))
.Select(p => Shape.Thing_Summary(
Thing: p,
SomethingElseThatIsRelevantToTheTemplate: foo));
Shape list = Shape.List(Pager: pager);
list.AddRange(things);
list.Metadata.Alternates.Add("list_things");
return new ShapeResult(this, list);
See that line near the end? It's adding the alternate, so that you can build a specific template for that particular list by creating a file named list.things.cshtml in the views folder of your theme.
I have a multi language site with the following structure:
siteroot
- en
-- home
-- login
-- etc.
- de
-- home
-- login
-- etc.
The content beneath the language nodes is not necessarily the same.
When switching languages I want to test if a parallel language node exists.
Currently I'm doing the following:
get current path
replace the language part of path
e.g. replace /en/login to /de/login
the closest I've found to test the existence of a page is:
XPathNodeIterator i = umbraco.library.GetXmlDocumentByUrl("http://localhost/de/login");
Debugging this shows, that umbraco actually hits the database. This can't be the best way to test the existence of a page.
Anybody have a better method at hand?
By the sounds your using the document class in cms.businesslogic.web namespace. This class is used for modifying/publishing nodes inside of umbraco.
Try using the node class that resides in umbraco.presentation.nodeFactory. This will interact with the in-memory XML cache only.
Node.GetCurrent() //static method - will give you the current loaded page.
Node.Parent //class property - will give parent method
The problem with the node class, that it can't take XPath queries (and will not give performance)
I've written a dynamic Linq provider that can be used to query the Umbraco XML structure using compiled xslt expressions. I going to be publishing in the next week or so. Let me know if your interested...
We have a multilingual site where we needed to do the same thing to set up our hreflang tags. There might be a better way, but I decided on building some Xpath to find out if a matching node exists in the other languages. We are using umbraco 7, and I would shy away from using NodeFactory if at all possible. It is depreciated. Using the umbraco helper won't hit the database, and is one of the best ways to query published content or media from umbraco for umbraco 7.
public static IPublishedContent GetLocalizedVersionOfPage(this IPublishedContent node, string regionName)
{
var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
var ancestorNames = node.AncestorsOrSelf()
.Where(n => n.Level > 1)
.OrderBy(n => n.Level)
.Select(n => n.Name).ToList();
var xpath = new StringBuilder();
xpath.AppendFormat("/root/HomePage[#nodeName='{0}']", regionName);
foreach (var ancestorName in ancestorNames)
{
xpath.AppendFormat("/*[#nodeName='{0}']", ancestorName);
}
var matchingNode = umbracoHelper.TypedContentAtXPath(xpath.ToString()).FirstOrDefault();
return matchingNode;
}
The above method is an extension method on the IPublishedContent. It allows you to pass in the region and it checks to see if a node with the same path determined by node name exists in the specified region. I thought about using the urlname instead of the node name. You could do that as well and maybe even make this faster by skipping the piece of code that does the .AncestorsOrSelf(). It just depends on how you want it to work. In my case, I wanted it to find a match based on the node name even if the url path was different, so I had to do the .AncestorsOrSelf(). Hope this helps.
Another thing to consider is how you call this method. if you use a loop like this:
#foreach (var region in Umbraco.TypedContentAtRoot().Where(n => n.IsDocumentType("HomePage")))
{
var localizedVersion = currentPage.GetLocalizedVersionOfPage(region.Name);
if (localizedVersion != null)
{
<link rel="alternate" href="#localizedVersion.UrlAbsolute()" hreflang="#LocalizeUtils.GetCulture(region.Name)" />
}
}
You will end up getting the ancestors of the current node over and over once for each region because it calls .AncestorsOrSelf() every time you call GetLocalizedVersionOfPage(). It probably makes sense to refactor the GetLocalizedVersionOfPage method so you only have to call .AncestorsOrSelf once. If you do this sort of thing too many times, it starts to affect performance (especially if your site is very nested).