Orchard CMS: Access arbitrary content inside template - razor

Scenario: HTML snippets created in admin. These are accessed (by name) in a template dynamically, based on state of the template's model's fields.
I have a custom content type and content created. How can I access this content by name from cshtml when it is not part of the model?
Here is psuedo-code of what I want to do.
#{
string title = Model.Title;
string html = "";
if(title.Contains("widget-a")) {
html = GET_CONENT [widget-a].Body;
}
else if(title.Contains("widget-b")) {
html = GET_CONENT [widget-b].Body;
}
body = Model.Html + html;
}
#body
I don't want to attach new fields to the content item whose HTML I'm altering.

Related

Wordpress json - How to use the content rendered from json

Using basic Wordpress basic Json in the format //domain.com/wp-json/wp/v2/pages/ I can access to a specific page content.
What I need to do is to use the rendered content as html of a blank page.
How to store this content into a variable so that I can use it? I suppose I shloud store into an array. Any sample?
Thank you.
How to store this content into a variable so that I can use it?
var x = data.content.rendered;
Where data is the JSON object you provided.
After this line is executed, x will contain HTML that you can use it in your project.
What I need to do is to use the rendered content as html of a blank page.
Any sample?
//change this values
var wpApiBaseURL = "http://localhost/wp-json/wp/v2/";
var pageId = 2; // id of the page to fetch
//
var container = document.getElementById("container");
// fetch specific page
fetch(wpApiBaseURL + "pages/" + pageId)
.then(function(rawResponse) {
return rawResponse.json();
})
.then(function(jsonResponse) {
// load successful and replaces html contents of the container div
container.innerHTML = jsonResponse.content.rendered;
})
.catch(function(error) {
container.innerText = "Error loading page";
});;
<!DOCTYPE html>
<body>
<div id="container">
Loading
</div>
</body>

How can I use Render sub-template in a C# template in a Content module that uses lists within lists?

2SXC 10.25.2 / DNN 9.3.2
I have a 2sxc module that uses a C# template with "list" enabled. I have a content type called "pathway" and inside that I have 2 entity picker fields for "first step sessions" and then "next step sessions". These entity pickers use a "session" content type. Inside each of those "session" content types I also have an entity picker for "speaker(s)". All in all, it's a setup that I have lists within lists within lists.
When I create the loops for each of the sublists, I can easily do that within the 1 C# template but it becomes repetitive, long, and unruly because there's so much c# code where I'm looping the same session template for different entity picker sections. So, I tried using the "Render sub-template" code to simplify the template - I created new sub templates and inserted them in - it seemed to work at first, however, the template started outputting all "session" items into each item in the list.
I suspect that the subtemplate somehow loses the context of the item that it's in so it's outputting everything. Is there something special I need to know about using subtemplates with for each loops? Do I have to include params and, if so, how do I do that?
EDIT to include code sample:
Here is a small, simplified version of the code I'm working with:
#foreach(var Content in AsList(Data)) {
<h2>#Content.Title</h2>
<h3>Lead Sessions</h3>
<div class="lead-sessions text-green">
#foreach(var item in AsList(Content.LeadSessions as object)){
<h4>#item.LeadSessionTitle</h4>
<p>#item.LeadSessionText</p>
}
</div>
<h3>Next Sessions</h3>
<div class="next-sessions text-green">
#foreach(var nextitem in AsList(Content.NextSessions as object)){
<h4>#nextitem.LeadSessionTitle</h4>
<p>#nextitem.LeadSessionText</p>
}
</div>
}
I want to make a subtemplate so I don't have to repeat the same code for the sessions loop. How could I simplify this template to use a subtemplate for looping the sessions within the lead-sessions and next-sessions?
So based on the modified question, it's a bit like this
#foreach(var Content in AsList(Data)) {
<h2>#Content.Title</h2>
<h3>Lead Sessions</h3>
#RenderPage("_inner.cshtml", new { Items = Content.LeadSessions })
<h3>Next Sessions</h3>
#RenderPage("_inner.cshtml", new { Items = Content.NextSessions })
}
Second file _inner.cshtml
#{
var items = AsList(PageData["Items"]);
}
<div class="next-sessions text-green">
#foreach(var nextitem in items){
<h4>#nextitem.LeadSessionTitle</h4>
<p>#nextitem.LeadSessionText</p>
}
</div>
Yep, you can just use RenderPage without params, or pass in params like in the blog app:
#RenderPage("shared/_Category Filter.cshtml", new { MobileView = true, FilteredCategory = filteredCategory })
See https://github.com/2sic/app-blog/blob/master/_List.cshtml#L25
Then the template can retrieve the values like
#{
var filteredCategory = PageData["FilteredCategory"];
}
See https://github.com/2sic/app-blog/blob/master/shared/_Category%20Filter.cshtml#L6
You can pass around any amount of values/objects like this.
You can also create helpers - and then call those helpers. Like this
https://github.com/2sic/app-news/blob/master/shared/_Helpers.cshtml#L24-L33

Orchard Taxonomy Terms get direct children in view

I have a Taxonomy called Categories. In this taxonomy I have multiple levels of terms. Each term is a CategoriesTerm contenttype.
I have defined a custom razor template: Content-CategoriesTerm.cshtml, which is used when I click a CategoriesTerm on the frontend.
Now I want to display on that page all direct children (if any), but there is no property like Term.Children or something. How can I get the children of a term in the Razor view?
Check Taxonomy.cshtml and Orchard.Mvc.DisplayChildren. It goes like this:
var tag = Tag(Model, "ul");
IList<dynamic> items = Model.Items;
if (items.Any()) {
items[0].Classes.Add("first");
items[items.Count - 1].Classes.Add("last");
<div>
#tag.StartElement
#* see MenuItem shape template *#
#DisplayChildren(Model)
#tag.EndElement
</div>
#DisplayChildren could be done in Razor if you like:
public IHtmlString DisplayChildren(dynamic shape) {
var writer = new HtmlStringWriter();
foreach (var item in shape) {
writer.Write(Display(item));
}
return writer;
}

How to insert html in Microsoft Word Placeholder

I have this situation:
The user has an editor on his page and he enters text(with colors, formating, hyperlinks and he can also add pictures). When he clicks Submit the data from the editor(with the proper formating) must be sent to a specific placeholder in a Microsoft Office Word document.
I am using OpenXml SDK to write in the document and I tried HtmlToOpenXml so I can read the html.
I use HtmlToOpenXml and from the html string(from the user) I det a couple of paragraphs and now I have to insert them in the content control. Do you know how can I find the control and append them in it(if possible)
I managed to fix this and here is the code I used
//name of the file which will be saved
const string filename = "test.docx";
//html string to be inserted and rendered in the word document
string html = #"<b>Test</b>";
//the Html2OpenXML dll supports all the common html tags
//open the template document with the content controls in it(in my case I used Richtext Field Content Control)
byte[] byteArray = File.ReadAllBytes("..."); // template path
using (MemoryStream generatedDocument = new MemoryStream())
{
generatedDocument.Write(byteArray, 0, byteArray.Length);
using (WordprocessingDocument doc = WordprocessingDocument.Open(generatedDocument, true))
{
MainDocumentPart mainPart = doc.MainDocumentPart;
//just in case
if (mainPart == null)
{
mainPart = doc.AddMainDocumentPart();
new Document(new Body()).Save(mainPart);
}
HtmlConverter converter = new HtmlConverter(mainPart);
Body body = mainPart.Document.Body;
//sdtElement is the Content Control we need.
//Html is the name of the placeholder we are looking for
SdtElement sdtElement = doc.MainDocumentPart.Document.Descendants<SdtElement>()
.Where(
element =>
element.SdtProperties.GetFirstChild<SdtAlias>() != null &&
element.SdtProperties.GetFirstChild<SdtAlias>().Val == "Html").FirstOrDefault();
//the HtmlConverter returns a set of paragraphs.
//in them we have the data which we want to insert in the document with it's formating
//After that we just need to append all paragraphs to the Content Control and save the document
var paragraphs = converter.Parse(html);
for (int i = 0; i < paragraphs.Count; i++)
{
sdtElement.Append(paragraphs[i]);
}
mainPart.Document.Save();
}
File.WriteAllBytes(filename, generatedDocument.ToArray());
}

Hide projection widget if query has no results

We are building a website with the Orchard CMS where we have campaign adds.
These adds are linked to pages through tags (not the orchard tag part).
Then we built a custom filter that take these tags into consideration when fetching the campaign adds and display them in a widget.
On some pages there are tags but no campaigns that match these tags. We would like to hide the widget at this point.
One solution is to edit the widget layer every time a new campaign is added. But I would like to have a more solid solution than this.
Summary:
We would like to hide the entire projection widget when the query returns an empty result.
// Madelene
Most of the markup in the widget is rendered by the Widget.Wrapper.cshtml template. What you can do is filter what this wrapper will render based on the content of the widget itself. This way if the widget doesn't render anything, you can decide to hide the title and the other zones. Here is the code doing it:
#using Orchard.ContentManagement;
#using Orchard.Widgets.Models;
#{
var widgetPart = ((IContent)Model.ContentItem).As<WidgetPart>();
var tag = Tag(Model, "article");
var childContent = Display(Model.Child);
}
#if (!String.IsNullOrEmpty(Convert.ToString(childContent))) {
#tag.StartElement
if ((widgetPart.RenderTitle && HasText(widgetPart.Title)) || Model.Header != null) {
<header>
#if ((widgetPart.RenderTitle && HasText(widgetPart.Title))) {
<h1>#widgetPart.Title</h1>
}
#Display(Model.Header)
</header>
}
#childContent
if (Model.Footer != null) {
<footer>
#Display(Model.Footer)
</footer>
}
#tag.EndElement
}
Just create a file named Widget.Wrapper.cshtml in your theme and paste this content. You can check what was the previous content if you want to understand how it's done.
you could override the Projection widget, you can then edit the code for that widget within the cshtml file. This is by far the easiest way.
or
You could create a custom filter that did a check for the dependency and returned no items if that dependency was not met (this is a harder way of doing it)