Closed dodyg closed 5 years ago
It's important to inherit @inherits OrchardCore.DisplayManagement.Razor.RazorPage<TModel>
in all your cshtml shape templates.
Note: I am not sure whether the CMS will pick up the shape templates anywhere or it has to be under /Views
.
The concept of Shape and Shape Templates needs better discussion in the current documentation. All the shape discussion is based on Orchard Core 1.0 documentation.
Do not precompile your Razor otherwise your Shape templates won't work
This is how to prevent Razor precompilation
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<RazorCompileOnPublish>false</RazorCompileOnPublish>
</PropertyGroup>
The Views
folder contains the Shapes templates. If you precompile your Razor views, this 'Views' folder won't be copied over and your Shapes rendering customization won't work.
Example When Shape templates are available
When Shape templates are missing because the Views
folder isn't at the published folder
SQL Queries module is kinda useless in comparison to Lucene Queries module because the thing that you can sort and filter in SQL Queries is very limited. You can't for example filter/sort by your Content Types field in SQL Queries. That just makes it a deal breaker. Lucene Queries doesn't have this limitation.
All you need is love and
private readonly OrchardCore.IOrchardHelper _helper;
private readonly OrchardCore.Queries.IQueryManager _queryManager;
or @inject
them at your views.
These two are pretty much all you need to implement decoupled CMS AFAIK.
Get by Alias
await _helper.GetContentItemByAliasAsync("alias:blog");
Get by Slug
await _helper.GetContentItemByAliasAsync("slug:blog/my-awesome-content");
Taxonomy module sounds cool but I have no idea how to use it from the Admin or how it relates to content.
OK this article is really useful: https://www.davidhayden.me/blog/taxonomies-in-orchard-core-cms
I wish there's an option to modify the /admin
path for OrchardCore admin UI.
Admin Menu should be enabled by default in an empty installation. It's super useful and it's not obvious for people implementing OrchardCore for the first time.
Content Types and Content Parts need discussions at the documentation. Right now people have to rely on Orchard 1 documentation.
This whole Orchard Core basic concepts from v1 need to be migrated and updated.
I still can't find a way how to obtain the site name and display it in Razor page.
@inject OrchardCore.Settings.ISiteService SiteService
string siteName = (await SiteService.GetSiteSettingsAsync()).SiteName;
It would be super nice if there's a version of _helper.GetContentItemByAliasAsync;
that takes multiple aliases.
Who would have thought that the humble TextField
has awesome list of editors!
@agriffard how does one load Widget in decoupled CMS? Just this _helper.GetContentItemByIdAsync
?
Once some keys concepts are understood, developing decoupled CMS with OrchardCore is a very pleasant experience.
This JSON rendering of a Content Item is just so invaluable. In this case this is a taxonomy content item. @Model.Topics.Content
.
It's important to inherit @inherits OrchardCore.DisplayManagement.Razor.RazorPage
in all your cshtml shape templates.
No. It has lots of helpers but you don't need them if you are not using a theme usually. You just need to inject @inject OrchardCore.IOrchardHelper OrchardHelper
and you have access to most of the things you need in a decoupled CMS.
Do not precompile your Razor otherwise your Shape templates won't work
You don't need shapes either. You should precompile your views.
SQL Queries module is kinda useless in comparison to Lucene Queries
There is a PR that provides it already, I will blame @Skrypt if it's not ready yet
I still can't find a way how to obtain the site name and display it in Razor page.
We definitely need to add an helper to IOrchardHelper for this
how does one load Widget in decoupled CMS
My advice is to create a "Section" content type that is based on FlowPart and you give it an alias. then you can load it and render it. You can also just use it as a data structure and render it by yourself.
json
Yes, we need helpers to render a json tree that can be navigated in html directly
something like this: https://www.jqueryscript.net/other/Beautiful-JSON-Viewer-Editor.html But we should do it in the admin first, simpler and would solve most issues
Helper.QueryCategorizedContentItemsAsync
usage isn't yet documented.
await _helper.QueryCategorizedContentItemsAsync(query =>
{
return query.Where(x => x.TermContentItemId == contentItemId);
});
This sample from the documentation isn't clear.
@foreach(var termId in Model.TermContentItemIds)
{
@await OrchardCore.GetTaxonomyTermAsync(Model.TaxonomyContentItemId, termId);
}
It will be much user friendly if ContentItemId is visible in the UI.
It can be much smaller in contrast of the other UI element. Right now we have to fish it out of the url.
Hello, I'm working on similar website using decoupled CMS. I also came across with missing information on this part. There is a very nice video with Sebastien but it's just one :). Now I'm facing problems with contact form and sending e-mail. If i make it as widget, how will i insert it in my ready html. On the other side, when i start to write my logic in back-end, I should struggle with workflows and their usage. It will be nice if you share some experience :)
@LatinaAtanasova I have not started to touch the form and sending email although that's coming. I will let you know when I figure it out. As you say, it's not very obvious.
I tried precompilation but orchard core does not pick up the Shape templates that was located at Views
folder. Now I have to copy the folder manually over.
If you are using the .Web sdk then it's automatic. All our module work like this.
@dodyg so far i managed to use
@LatinaAtanasova yeah I don't know how to render the form yet on decoupled CMS.
@sebastienros I already use .Web
SDK.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Markdig" Version="0.16.0" />
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
<PackageReference Include="OrchardCore.Application.Cms.Targets" Version="1.0.0-beta3-71077" />
</ItemGroup>
<ItemGroup>
<Content Update="wwwroot\css\site.css">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
me too :)
Yes, at the app level that's ok for pure mvc views but shape views need to be outputed on publishing.
This is because the shape discovering relies on the existing file providers, a shape view needs to be discovered at runtime even the related precompiled view will be used.
It works for modules because we also embed view contents in their assemblies, so shape views are found through our embedded file provider.
Right now, you need to output app level shape views (razor and liquid) on publishing.
Hello again, I need help on my project :) I have a few pages:
and in order to use menu functionality i included "The Theme" with restyling the menu html.
I try to understand and implement one simple widget. I created an alert message as follows:
My idea is to visualize that alert in zone name="Messages" which is in Contacts Page. (Next step will be to have it as success or warning, etc.) I try it with
<zone name="Messages">
@await DisplayAsync(Model.Content);
</zone>
but DisplayAsync is not reachable. I know that it can be used if page inherits OrchardCore.DisplayManagement.Razor.RazorPage
I need to have contact page, user registrations, some items and mapping them to users. I'll appreciate every advice :)
Right now my approach is to build the contact page form in razor as normal then submit the value to a workflow end point. I haven't completed the process yet. I will update when I am done.
Note: I just found out zone tag helper exists. I will research this further today and see if I can find a solution to the problem you encounter.
Thanks :) It will be great if you can share your experience with workflow. I also made one, but couldn't submit the value to it. I'm missing something with the transition between admin and back-end.
Make sure you enable HTTP Workflows Activities
module
I screwed up a workflow and now my Content Item listing is broken. https://github.com/OrchardCMS/OrchardCore/issues/3593
@LatinaAtanasova,
This is a good guide for workflow except that it's a bit out of date in the liquid part.
This contains the latest up to date reference on what is available for Liquid.
My workflow is this.
You need to create:
JSON.parse(readBody())
In my ContactUs
form, I just serialize a json payload and post it to the URL set by the HTTP Request
event.
So now when I submit my contact us form, a new content will be added in OrchardCore.
Thank you. I'll try it. By the way the following solution is nice and useful. I don't know if you have come across it. https://github.com/psijkof/ModernBusiness.OC.RazorPages
Good find. Let me review that.
This is an important information regarding media resize https://github.com/OrchardCMS/OrchardCore/issues/3474#issuecomment-483791638.
You cannot resize image outside these values.
To override the default values, do this in your startup.cs
MediaFileProvider.DefaultSizes = new[] { 16, 32, 50, 100, 160, 240, 480, 576, 600, 1024, 2048 };
The default values are very limiting because it doesn't allow you to do the ratio of still photography https://en.wikipedia.org/wiki/Aspect_ratio_%28image%29#Still_photography
Lucene Queries seems to have problem with sorting https://github.com/OrchardCMS/OrchardCore/issues/3278. Bummer.
Or use SupportedSizes configuration to provide custom supported resizing for the media module https://github.com/OrchardCMS/OrchardCore/commit/8da9513d011d62c272adeb917488c56efed9f950
We have an issue already and a design to support "any" size also.
All you need is love and
private readonly OrchardCore.IOrchardHelper _helper; private readonly OrchardCore.Queries.IQueryManager _queryManager;
or
@inject
them at your views.These two are pretty much all you need to implement decoupled CMS AFAIK.
Could you give an example of how to use these objects to execute a query in the controller and send the result of the query to the view?
This will get you going (Razor Page)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using OrchardCore.ContentManagement;
namespace Silverkey.Website.Pages
{
public class GeneralPageModel : PageModel
{
private readonly OrchardCore.IOrchardHelper _helper;
private readonly OrchardCore.Queries.IQueryManager _queryManager;
public ContentItem PageContent { get; set; }
public GeneralPageModel(OrchardCore.IOrchardHelper helper, OrchardCore.Queries.IQueryManager QueryManager)
{
_helper = helper;
_queryManager = QueryManager;
}
public async Task<ActionResult> OnGetAsync(string alias)
{
if (string.IsNullOrEmpty(alias))
return NotFound();
var content = await _helper.GetContentItemByAliasAsync($"alias:{alias}");
if (content is null)
return NotFound();
PageContent = content;
return Page();
}
}
}
View
@page "/p/{*alias}"
@model Silverkey.Website.Pages.GeneralPageModel
@{
ViewData[Fmt.Title] = Model.PageContent.DisplayText;
bool sideSectionExists = Model.PageContent.ContentItem.Content.SideSections.ContentItems.Count > 0;
var mainSectionSize = sideSectionExists ? "is-two-thirds" : Model.PageContent.ContentItem.Content.SinglePage.ColumnCssClass.Text;
}
@foreach (var pitch in Model.PageContent.ContentItem.Content.Pitch.ContentItems)
{
<section class="hero is-fullheight-with-navbar">
<div class="hero-body has-background-grey-lighter">
<div class="container">
<div class="columns is-centered">
<div class="column is-half" style="text-align:center;">
<h1 class="title is-1">@pitch.TitlePart.Title</h1>
<div class="content">
@Fmt.Markdown((string)pitch.MarkdownBodyPart.Markdown)
</div>
</div>
</div>
</div>
</div>
</section>
}
<main class="section">
<div class="container">
<div class="columns">
<div class="column @mainSectionSize">
<main>
<h1 class="title is-1">@Model.PageContent.ContentItem.Content.TitlePart.Title</h1>
<div class="content">
@Fmt.Markdown((string)Model.PageContent.ContentItem.Content.MarkdownBodyPart.Markdown)
</div>
<div class="content">
@foreach (var part in Model.PageContent.ContentItem.Content.MainSections.ContentItems)
{
<h2>@part.DisplayText</h2>
if (part.ContentType == "Columns")
{
<div class="columns">
@foreach (var column in part.BagPart.ContentItems)
{
<div class="column">
<h3>@column.DisplayText</h3>
@Fmt.Markdown((string)column.MarkdownBodyPart.Markdown)
</div>
}
</div>
}
}
</div>
</main>
</div>
@if (sideSectionExists)
{
<div class="column">
@foreach (var part in Model.PageContent.ContentItem.Content.SideSections.ContentItems)
{
<div class="card">
<div class="card-header">
<p class="card-header-title is-centered">
@part.TitlePart.Title
</p>
</div>
<div class="card-content">
<div class="content">
@Fmt.Markdown((string)part.MarkdownBodyPart.Markdown)
</div>
</div>
</div>
}
</div>
}
</div>
</div>
</main>
@foreach (var part in Model.PageContent.ContentItem.Content.BottomSections.ContentItems)
{
<section class="section">
<div class="container">
<div class="columns">
<div class="column">
<div class="content">
@part.TitlePart.Title
@Fmt.Markdown((string)part.MarkdownBodyPart.Markdown)
</div>
</div>
<div class="column">
</div>
</div>
</div>
</section>
}
Note @Fmt.Markdown
is my own method.
If you want to see what properties are available for you to access, do @Model.PageContent.Content
and it will show you all the structure in Json that you can access dynamically.
Thanks for the detailed example. Do you know how to create a table managed from the admin panel?
Use a text field with HTML Editor
When you are implementing a module, at="Foot"
is your friend. It puts the scripts at the bottom of the page.
<script at="Foot" src="https://unpkg.com/gijgo@1.9.11/js/gijgo.min.js" type="text/javascript"></script>
<script at="Foot">
document.write('<!-- some script -->');
</script>
Don't forget to put the Admin attribute for controller that handles your module admin pages
Encountered a deployment problem https://github.com/OrchardCMS/OrchardCore/issues/3755. The cause because the environment was set to Development.
This is important https://github.com/OrchardCMS/OrchardCore/issues/3752
Check that each module using the razor sdk also references directly (not transitively) the Microsoft.AspNetCore.Mvc package, that modules using our custom script tag reference OrchardCore.ResourceManagement, and that their _ViewImports.cshtml import the related tag helpers @addTagHelper *, OrchardCore.ResourceManagement.
I am going to write a running commentary and notes for a decoupled CMS website implementation so it can be a reference for official documentation/guide.
I am using
The website I am building contains:
I am not using any themes in this decoupled CMS implementation because it's not really obvious how to use it or whether it is beneficial at all.
I prefer the decoupled CMS approach at this moment because as a developer, using the traditional approach requires higher learning curve than using decoupled approach.
There are things like
Zone
,Placement
or whatnot that are simply not obvious and I assume necessary when using traditional approach. Using decoupled CMS, I just need to worry about getting the content and I can put them exactly where I want.